Module Name: src Committed By: martin Date: Tue Mar 12 12:41:39 UTC 2024
Modified Files: src/usr.bin/audio/common [netbsd-9]: auconv.h audio.c decode.c libaudio.h sun.c wav.c src/usr.bin/audio/ctl [netbsd-9]: audioctl.1 src/usr.bin/audio/play [netbsd-9]: audioplay.1 play.c src/usr.bin/audio/record [netbsd-9]: audiorecord.1 record.c Log Message: Pull up the following revisions, requested by mrg in ticket #1818: usr.bin/audio/common/auconv.h up to 1.6 usr.bin/audio/common/audio.c up to 1.27 usr.bin/audio/common/decode.c up to 1.2 usr.bin/audio/common/libaudio.h up to 1.22 usr.bin/audio/common/sun.c up to 1.11 usr.bin/audio/common/wav.c up to 1.22 usr.bin/audio/ctl/audioctl.1 up to 1.25 usr.bin/audio/play/audioplay.1 up to 1.34 usr.bin/audio/play/play.c up to 1.64 usr.bin/audio/record/audiorecord.1 up to 1.45 usr.bin/audio/record/record.c up to 1.58 - support for playing 32-bit and 64-bit IEEE FP .wav files - support for recording 24 bit .wav files - read-overflow fixes for .wav files, and other fixes for the wav parser - audioplay gains -n flag (no play, like make -n) - audioctl manual spruced up - audiorecord manual gained useful examples To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.5.64.1 src/usr.bin/audio/common/auconv.h cvs rdiff -u -r1.25 -r1.25.18.1 src/usr.bin/audio/common/audio.c cvs rdiff -u -r1.1 -r1.1.18.1 src/usr.bin/audio/common/decode.c cvs rdiff -u -r1.20 -r1.20.18.1 src/usr.bin/audio/common/libaudio.h cvs rdiff -u -r1.9 -r1.9.18.1 src/usr.bin/audio/common/sun.c cvs rdiff -u -r1.14 -r1.14.6.1 src/usr.bin/audio/common/wav.c cvs rdiff -u -r1.23 -r1.23.2.1 src/usr.bin/audio/ctl/audioctl.1 cvs rdiff -u -r1.26.28.1 -r1.26.28.2 src/usr.bin/audio/play/audioplay.1 cvs rdiff -u -r1.57 -r1.57.2.1 src/usr.bin/audio/play/play.c cvs rdiff -u -r1.42 -r1.42.28.1 src/usr.bin/audio/record/audiorecord.1 cvs rdiff -u -r1.54 -r1.54.18.1 src/usr.bin/audio/record/record.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/audio/common/auconv.h diff -u src/usr.bin/audio/common/auconv.h:1.5 src/usr.bin/audio/common/auconv.h:1.5.64.1 --- src/usr.bin/audio/common/auconv.h:1.5 Mon Apr 28 20:24:12 2008 +++ src/usr.bin/audio/common/auconv.h Tue Mar 12 12:41:38 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: auconv.h,v 1.5 2008/04/28 20:24:12 martin Exp $ */ +/* $NetBSD: auconv.h,v 1.5.64.1 2024/03/12 12:41:38 martin Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -78,6 +78,24 @@ change_sign16_be(u_char *p, int cc) } static inline void +change_sign24_le(u_char *p, int cc) +{ + while ((cc -= 3) >= 0) { + p[2] ^= 0x80; + p += 3; + } +} + +static inline void +change_sign24_be(u_char *p, int cc) +{ + while ((cc -= 3) >= 0) { + p[0] ^= 0x80; + p += 3; + } +} + +static inline void change_sign32_le(u_char *p, int cc) { while ((cc -= 4) >= 0) { @@ -163,6 +181,44 @@ change_sign16_swap_bytes_be(u_char *p, i } static inline void +swap_bytes_change_sign24_le(u_char *p, int cc) +{ + u_char t; + + while ((cc -= 3) >= 0) { + t = p[2]; + p[2] = p[0] ^ 0x80; + p[0] = t; + p += 3; + } +} + +static inline void +swap_bytes_change_sign24_be(u_char *p, int cc) +{ + u_char t; + + while ((cc -= 3) >= 0) { + t = p[0]; + p[0] = p[2] ^ 0x80; + p[2] = t; + p += 3; + } +} + +static inline void +change_sign24_swap_bytes_le(u_char *p, int cc) +{ + swap_bytes_change_sign24_be(p, cc); +} + +static inline void +change_sign24_swap_bytes_be(u_char *p, int cc) +{ + swap_bytes_change_sign24_le(p, cc); +} + +static inline void swap_bytes_change_sign32_le(u_char *p, int cc) { u_char t; Index: src/usr.bin/audio/common/audio.c diff -u src/usr.bin/audio/common/audio.c:1.25 src/usr.bin/audio/common/audio.c:1.25.18.1 --- src/usr.bin/audio/common/audio.c:1.25 Wed Aug 5 06:54:39 2015 +++ src/usr.bin/audio/common/audio.c Tue Mar 12 12:41:38 2024 @@ -1,7 +1,7 @@ -/* $NetBSD: audio.c,v 1.25 2015/08/05 06:54:39 mrg Exp $ */ +/* $NetBSD: audio.c,v 1.25.18.1 2024/03/12 12:41:38 martin Exp $ */ /* - * Copyright (c) 1999 Matthew R. Green + * Copyright (c) 1999, 2013, 2015, 2019 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: audio.c,v 1.25 2015/08/05 06:54:39 mrg Exp $"); +__RCSID("$NetBSD: audio.c,v 1.25.18.1 2024/03/12 12:41:38 martin Exp $"); #endif @@ -110,6 +110,8 @@ static const struct { { AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS }, { AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM }, { AudioEac3, AUDIO_ENCODING_AC3 }, + { "ieee_float32", AUDIO_ENCODING_LIBAUDIO_FLOAT32 }, + { "ieee_float64", AUDIO_ENCODING_LIBAUDIO_FLOAT64 }, { NULL, -1 } }; @@ -203,7 +205,7 @@ write_header(struct track_info *ti) veclen = 0; tlen = 0; - + if (hdrlen != 0) { iv[veclen].iov_base = hdr; iv[veclen].iov_len = hdrlen; Index: src/usr.bin/audio/common/decode.c diff -u src/usr.bin/audio/common/decode.c:1.1 src/usr.bin/audio/common/decode.c:1.1.18.1 --- src/usr.bin/audio/common/decode.c:1.1 Sun Jun 21 06:06:01 2015 +++ src/usr.bin/audio/common/decode.c Tue Mar 12 12:41:38 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: decode.c,v 1.1 2015/06/21 06:06:01 mrg Exp $ */ +/* $NetBSD: decode.c,v 1.1.18.1 2024/03/12 12:41:38 martin Exp $ */ /* * Copyright (c) 1999 Matthew R. Green @@ -29,7 +29,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: decode.c,v 1.1 2015/06/21 06:06:01 mrg Exp $"); +__RCSID("$NetBSD: decode.c,v 1.1.18.1 2024/03/12 12:41:38 martin Exp $"); #endif #include <sys/types.h> @@ -85,7 +85,7 @@ decode_time(const char *arg, struct time tvp->tv_sec = tvp->tv_usec = 0; s = copy; - + /* handle [hh:]mm:ss.dd */ if ((colon = strchr(s, ':')) != NULL) { *colon++ = '\0'; Index: src/usr.bin/audio/common/libaudio.h diff -u src/usr.bin/audio/common/libaudio.h:1.20 src/usr.bin/audio/common/libaudio.h:1.20.18.1 --- src/usr.bin/audio/common/libaudio.h:1.20 Wed Aug 5 06:54:39 2015 +++ src/usr.bin/audio/common/libaudio.h Tue Mar 12 12:41:38 2024 @@ -1,7 +1,7 @@ -/* $NetBSD: libaudio.h,v 1.20 2015/08/05 06:54:39 mrg Exp $ */ +/* $NetBSD: libaudio.h,v 1.20.18.1 2024/03/12 12:41:38 martin Exp $ */ /* - * Copyright (c) 1999, 2009 Matthew R. Green + * Copyright (c) 1999, 2009, 2013, 2015, 2019, 2024 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,17 @@ int audio_format_from_str (char *); /* + * Audio encoding formats; this is a additional to those set + * in sys/audioio.h, but with a large offset to avoid future + * conflicts (additional ones are libaudio-software only.) + * + * This is to support floating-point WAV files. These require + * software conversion to a supported format. + */ +#define AUDIO_ENCODING_LIBAUDIO_FLOAT32 1001 /* 32-bit IEEE FP. */ +#define AUDIO_ENCODING_LIBAUDIO_FLOAT64 1002 /* 64-bit IEEE FP. */ + +/* * We copy the Sun/NeXT on-disk audio header format and document what * we know of it here. * @@ -95,7 +106,10 @@ int audio_sun_to_encoding (int, u_int *, int audio_encoding_to_sun (int, int, int *); /* - * M$ WAV files, info gleamed from sox sources + * RIFF WAVE files. Sources: RFC 2361, and various Microsoft docs + * https://learn.microsoft.com/en-us/windows/win32/xaudio2/resource-interchange-file-format--riff- + * https://learn.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653308(v=vs.85) + * "Multimedia Programming Interface and Data Specifications 1.0" chapter 4 */ /* @@ -107,29 +121,112 @@ int audio_encoding_to_sun (int, int, int #define WAVAUDIO_FILE_MAGIC_FMT ((u_int32_t)0x666d7420) #define WAVAUDIO_FILE_MAGIC_DATA ((u_int32_t)0x64617461) -/* purloined from public Microsoft RIFF docs via sox or mplayer */ +/* From RFC 2361 */ #define WAVE_FORMAT_UNKNOWN (0x0000) #define WAVE_FORMAT_PCM (0x0001) #define WAVE_FORMAT_ADPCM (0x0002) +#define WAVE_FORMAT_IEEE_FLOAT (0x0003) +#define WAVE_FORMAT_VSELP (0x0004) +#define WAVE_FORMAT_IBM_CVSD (0x0005) #define WAVE_FORMAT_ALAW (0x0006) #define WAVE_FORMAT_MULAW (0x0007) #define WAVE_FORMAT_OKI_ADPCM (0x0010) #define WAVE_FORMAT_IMA_ADPCM (0x0011) +#define WAVE_FORMAT_MEDIASPACE_ADPCM (0x0012) +#define WAVE_FORMAT_SIERRA_ADPCM (0x0013) +#define WAVE_FORMAT_G723_ADPCM (0x0014) #define WAVE_FORMAT_DIGISTD (0x0015) #define WAVE_FORMAT_DIGIFIX (0x0016) +#define WAVE_FORMAT_DIALOGIC_OKI_ADPCM (0x0017) +#define WAVE_FORMAT_MEDIAVISION_ADPCM (0x0018) +#define WAVE_FORMAT_CU_CODEC (0x0019) +#define WAVE_FORMAT_YAMAHA_ADPCM (0x0020) +#define WAVE_FORMAT_SONARC (0x0021) +#define WAVE_FORMAT_DSPGROUP_TRUESPEECH (0x0022) +#define WAVE_FORMAT_ECHOSC1 (0x0023) +#define WAVE_FORMAT_AUDIOFILE_AF36 (0x0024) +#define WAVE_FORMAT_APTX (0x0025) +#define WAVE_FORMAT_AUDIOFILE_AF10 (0x0026) +#define WAVE_FORMAT_PROSODY_1612 (0x0027) +#define WAVE_FORMAT_LRC (0x0028) #define WAVE_FORMAT_DOLBY_AC2 (0x0030) #define WAVE_FORMAT_GSM610 (0x0031) +#define WAVE_FORMAT_MSNAUDIO (0x0032) +#define WAVE_FORMAT_ANTEX_ADPCME (0x0033) +#define WAVE_FORMAT_CONTROL_RES_VQLPC (0x0034) +#define WAVE_FORMAT_DIGIREAL (0x0035) +#define WAVE_FORMAT_DIGIADPCM (0x0036) +#define WAVE_FORMAT_CONTROL_RES_CR10 (0x0037) +#define WAVE_FORMAT_NMS_VBXADPCM (0x0038) +#define WAVE_FORMAT_ROLAND_RDAC (0x0039) +#define WAVE_FORMAT_ECHOSC3 (0x003a) #define WAVE_FORMAT_ROCKWELL_ADPCM (0x003b) #define WAVE_FORMAT_ROCKWELL_DIGITALK (0x003c) +#define WAVE_FORMAT_XEBEC (0x003d) #define WAVE_FORMAT_G721_ADPCM (0x0040) #define WAVE_FORMAT_G728_CELP (0x0041) +#define WAVE_FORMAT_MSG723 (0x0042) #define WAVE_FORMAT_MPEG (0x0050) +#define WAVE_FORMAT_RT24 (0x0052) +#define WAVE_FORMAT_PAC (0x0053) #define WAVE_FORMAT_MPEGLAYER3 (0x0055) +#define WAVE_FORMAT_LUCENT_G723 (0x0059) +#define WAVE_FORMAT_CIRRUS (0x0060) +#define WAVE_FORMAT_ESPCM (0x0061) +#define WAVE_FORMAT_VOXWARE (0x0062) +#define WAVE_FORMAT_CANOPUS_ATRAC (0x0063) #define WAVE_FORMAT_G726_ADPCM (0x0064) #define WAVE_FORMAT_G722_ADPCM (0x0065) -#define IBM_FORMAT_MULAW (0x0101) -#define IBM_FORMAT_ALAW (0x0102) -#define IBM_FORMAT_ADPCM (0x0103) +#define WAVE_FORMAT_DSAT (0x0066) +#define WAVE_FORMAT_DSAT_DISPLAY (0x0067) +#define WAVE_FORMAT_VOXWARE_BYTE_ALIGNED (0x0069) +#define WAVE_FORMAT_VOXWARE_AC8 (0x0070) +#define WAVE_FORMAT_VOXWARE_AC10 (0x0071) +#define WAVE_FORMAT_VOXWARE_AC16 (0x0072) +#define WAVE_FORMAT_VOXWARE_AC20 (0x0073) +#define WAVE_FORMAT_VOXWARE_RT24 (0x0074) +#define WAVE_FORMAT_VOXWARE_RT29 (0x0075) +#define WAVE_FORMAT_VOXWARE_RT29HW (0x0076) +#define WAVE_FORMAT_VOXWARE_VR12 (0x0077) +#define WAVE_FORMAT_VOXWARE_VR18 (0x0078) +#define WAVE_FORMAT_VOXWARE_TQ40 (0x0079) +#define WAVE_FORMAT_SOFTSOUND (0x0080) +#define WAVE_FORMAT_VOXWARE_TQ60 (0x0081) +#define WAVE_FORMAT_MSRT24 (0x0082) +#define WAVE_FORMAT_G729A (0x0083) +#define WAVE_FORMAT_MVI_MV12 (0x0084) +#define WAVE_FORMAT_DF_G726 (0x0085) +#define WAVE_FORMAT_DF_GSM610 (0x0086) +#define WAVE_FORMAT_ISIAUDIO (0x0088) +#define WAVE_FORMAT_ONLIVE (0x0089) +#define WAVE_FORMAT_SBC24 (0x0091) +#define WAVE_FORMAT_DOLBY_AC3_SPDIF (0x0092) +#define WAVE_FORMAT_ZYXEL_ADPCM (0x0097) +#define WAVE_FORMAT_PHILIPS_LPCBB (0x0098) +#define WAVE_FORMAT_PACKED (0x0099) +#define WAVE_FORMAT_RHETOREX_ADPCM (0x0100) +#define WAVE_FORMAT_IRAT (0x0101) +#define WAVE_FORMAT_VIVO_G723 (0x0111) +#define WAVE_FORMAT_VIVO_SIREN (0x0112) +#define WAVE_FORMAT_DIGITAL_G723 (0x0123) +#define WAVE_FORMAT_CREATIVE_ADPCM (0x0200) +#define WAVE_FORMAT_CREATIVE_FASTSPEECH8 (0x0202) +#define WAVE_FORMAT_CREATIVE_FASTSPEECH10 (0x0203) +#define WAVE_FORMAT_QUARTERDECK (0x0220) +#define WAVE_FORMAT_FM_TOWNS_SND (0x0300) +#define WAVE_FORMAT_BTV_DIGITAL (0x0400) +#define WAVE_FORMAT_VME_VMPCM (0x0680) +#define WAVE_FORMAT_OLIGSM (0x1000) +#define WAVE_FORMAT_OLIADPCM (0x1001) +#define WAVE_FORMAT_OLICELP (0x1002) +#define WAVE_FORMAT_OLISBC (0x1003) +#define WAVE_FORMAT_OLIOPR (0x1004) +#define WAVE_FORMAT_LH_CODEC (0x1100) +#define WAVE_FORMAT_NORRIS (0x1400) +#define WAVE_FORMAT_ISIAUDIO2 (0x1401) +#define WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS (0x1500) +#define WAVE_FORMAT_DVM (0x2000) + #define WAVE_FORMAT_EXTENSIBLE (0xfffe) const char *wav_enc_from_val (int); @@ -143,7 +240,7 @@ typedef struct { u_int16_t tag; u_int16_t channels; u_int32_t sample_rate; - u_int32_t avg_bps; + u_int32_t avg_bytes_per_sec; u_int16_t alignment; u_int16_t bits_per_sample; } __packed wav_audioheaderfmt; @@ -153,7 +250,7 @@ typedef struct { u_int16_t valid_bits; u_int32_t speaker_pos_mask; u_int16_t sub_tag; - u_int8_t dummy[14]; + u_int8_t guid[14]; } __packed wav_audiohdrextensible; /* returns size of header, or -ve for failure */ Index: src/usr.bin/audio/common/sun.c diff -u src/usr.bin/audio/common/sun.c:1.9 src/usr.bin/audio/common/sun.c:1.9.18.1 --- src/usr.bin/audio/common/sun.c:1.9 Wed Aug 5 06:54:39 2015 +++ src/usr.bin/audio/common/sun.c Tue Mar 12 12:41:38 2024 @@ -1,7 +1,7 @@ -/* $NetBSD: sun.c,v 1.9 2015/08/05 06:54:39 mrg Exp $ */ +/* $NetBSD: sun.c,v 1.9.18.1 2024/03/12 12:41:38 martin Exp $ */ /* - * Copyright (c) 2002 Matthew R. Green + * Copyright (c) 2002, 2013, 2015 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: sun.c,v 1.9 2015/08/05 06:54:39 mrg Exp $"); +__RCSID("$NetBSD: sun.c,v 1.9.18.1 2024/03/12 12:41:38 martin Exp $"); #endif @@ -149,7 +149,7 @@ sun_prepare_header(struct track_info *ti break; #endif } - + /* if we can't express this as a Sun header, don't write any */ if (audio_encoding_to_sun(ti->encoding, ti->precision, &sunenc) != 0) { if (!ti->qflag && !warned) { Index: src/usr.bin/audio/common/wav.c diff -u src/usr.bin/audio/common/wav.c:1.14 src/usr.bin/audio/common/wav.c:1.14.6.1 --- src/usr.bin/audio/common/wav.c:1.14 Sat Nov 25 17:18:15 2017 +++ src/usr.bin/audio/common/wav.c Tue Mar 12 12:41:38 2024 @@ -1,7 +1,7 @@ -/* $NetBSD: wav.c,v 1.14 2017/11/25 17:18:15 jdolecek Exp $ */ +/* $NetBSD: wav.c,v 1.14.6.1 2024/03/12 12:41:38 martin Exp $ */ /* - * Copyright (c) 2002, 2009 Matthew R. Green + * Copyright (c) 2002, 2009, 2013, 2015, 2019, 2024 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,7 +33,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: wav.c,v 1.14 2017/11/25 17:18:15 jdolecek Exp $"); +__RCSID("$NetBSD: wav.c,v 1.14.6.1 2024/03/12 12:41:38 martin Exp $"); #endif @@ -49,6 +49,7 @@ __RCSID("$NetBSD: wav.c,v 1.14 2017/11/2 #include <string.h> #include <stdint.h> #include <unistd.h> +#include <stdbool.h> #include "libaudio.h" #include "auconv.h" @@ -60,6 +61,7 @@ static const struct { { WAVE_FORMAT_UNKNOWN, "Microsoft Official Unknown" }, { WAVE_FORMAT_PCM, "Microsoft PCM" }, { WAVE_FORMAT_ADPCM, "Microsoft ADPCM" }, + { WAVE_FORMAT_IEEE_FLOAT,"Microsoft IEEE Floating-Point" }, { WAVE_FORMAT_ALAW, "Microsoft A-law" }, { WAVE_FORMAT_MULAW, "Microsoft mu-law" }, { WAVE_FORMAT_OKI_ADPCM,"OKI ADPCM" }, @@ -88,6 +90,49 @@ wav_enc_from_val(int encoding) /* * WAV format helpers */ + +static bool +find_riff_chunk(const char search[4], size_t *remainp, char **wherep, uint32_t *partlen) +{ + wav_audioheaderpart part; + + *partlen = 0; + +#define ADJUST(l) do { \ + if (l >= *(remainp)) \ + return false; \ + *(wherep) += (l); \ + *(remainp) -= (l); \ +} while (0) + + while (*remainp >= sizeof part) { + const char *emsg = ""; + uint32_t len; + + memcpy(&part, *wherep, sizeof part); + ADJUST(sizeof part); + len = getle32(part.len); + if (len % 2) { + emsg = " (odd length, adjusted)"; + len += 1; + } + if (strncmp(part.name, search, sizeof *search) == 0) { + *partlen = len; + if (verbose > 1) + fprintf(stderr, "Found part %.04s length %d%s\n", + part.name, len, emsg); + return true; + } + ADJUST(len); + if (verbose > 1) + fprintf(stderr, "Skipping part %.04s length %d%s\n", + part.name, len, emsg); + } +#undef ADJUST + + return false; +} + /* * find a .wav header, etc. returns header length on success */ @@ -95,61 +140,87 @@ ssize_t audio_wav_parse_hdr(void *hdr, size_t sz, u_int *enc, u_int *prec, u_int *sample, u_int *channels, off_t *datasize) { - char *where = hdr, *owhere; - wav_audioheaderpart part; + char *where = hdr; wav_audioheaderfmt fmt; wav_audiohdrextensible ext; - char *end = (((char *)hdr) + sz); + size_t remain = sz; u_int newenc, newprec; + uint32_t len = 0; u_int16_t fmttag; static const char strfmt[4] = "fmt ", strRIFF[4] = "RIFF", strWAVE[4] = "WAVE", strdata[4] = "data"; - + bool found; + if (sz < 32) return (AUDIO_ENOENT); - if (strncmp(where, strRIFF, sizeof strRIFF)) +#define ADJUST(l) do { \ + if (l >= remain) \ + return (AUDIO_ESHORTHDR); \ + where += (l); \ + remain -= (l); \ +} while (0) + + if (memcmp(where, strRIFF, sizeof strRIFF) != 0) return (AUDIO_ENOENT); - where += 8; - if (strncmp(where, strWAVE, sizeof strWAVE)) + ADJUST(sizeof strRIFF); + /* XXX we ignore the RIFF length here */ + ADJUST(4); + if (memcmp(where, strWAVE, sizeof strWAVE) != 0) return (AUDIO_ENOENT); - where += 4; + ADJUST(sizeof strWAVE); - do { - memcpy(&part, where, sizeof part); - owhere = where; - where += getle32(part.len) + 8; - } while (where < end && strncmp(part.name, strfmt, sizeof strfmt)); + found = find_riff_chunk(strfmt, &remain, &where, &len); /* too short ? */ - if (where + sizeof fmt > end) + if (!found || remain <= sizeof fmt) return (AUDIO_ESHORTHDR); - memcpy(&fmt, (owhere + 8), sizeof fmt); - + memcpy(&fmt, where, sizeof fmt); fmttag = getle16(fmt.tag); if (verbose) - printf("WAVE format tag: %x\n", fmttag); + printf("WAVE format tag/len: %04x/%u\n", fmttag, len); if (fmttag == WAVE_FORMAT_EXTENSIBLE) { - if ((uintptr_t)(where - owhere) < sizeof(fmt) + sizeof(ext)) + if (len < sizeof(fmt) + sizeof(ext)) { + if (verbose) + fprintf(stderr, "short WAVE ext fmt\n"); return (AUDIO_ESHORTHDR); - memcpy(&ext, owhere + sizeof fmt, sizeof ext); - if (getle16(ext.len) < sizeof(ext) - sizeof(ext.len)) + } + if (remain <= sizeof ext + sizeof fmt) { + if (verbose) + fprintf(stderr, "WAVE ext truncated\n"); return (AUDIO_ESHORTHDR); + } + memcpy(&ext, where + sizeof fmt, sizeof ext); fmttag = getle16(ext.sub_tag); + uint16_t sublen = getle16(ext.len); if (verbose) - printf("WAVE extensible sub tag: %x\n", fmttag); + printf("WAVE extensible tag/len: %04x/%u\n", fmttag, sublen); + + /* + * XXXMRG: it may be that part.len (aka sizeof fmt + sizeof ext) + * should equal sizeof fmt + sizeof ext.len + sublen? this block + * is only entered for part.len == 40, where ext.len is expected + * to be 22 (sizeof ext.len = 2, sizeof fmt = 16). + * + * warn about this, but don't consider it an error. + */ + if (getle16(ext.len) != 22 && verbose) { + fprintf(stderr, "warning: WAVE ext.len %u not 22\n", + getle16(ext.len)); + } + } else if (len < sizeof(fmt)) { + if (verbose) + fprintf(stderr, "WAVE fmt unsupported size %u\n", len); + return (AUDIO_EWAVUNSUPP); } + ADJUST(len); switch (fmttag) { - case WAVE_FORMAT_UNKNOWN: - case IBM_FORMAT_MULAW: - case IBM_FORMAT_ALAW: - case IBM_FORMAT_ADPCM: default: return (AUDIO_EWAVUNSUPP); @@ -188,15 +259,27 @@ audio_wav_parse_hdr(void *hdr, size_t sz newenc = AUDIO_ENCODING_ULAW; newprec = 8; break; + case WAVE_FORMAT_IEEE_FLOAT: + switch (getle16(fmt.bits_per_sample)) { + case 32: + newenc = AUDIO_ENCODING_LIBAUDIO_FLOAT32; + newprec = 32; + break; + case 64: + newenc = AUDIO_ENCODING_LIBAUDIO_FLOAT64; + newprec = 32; + break; + default: + return (AUDIO_EWAVBADPCM); + } + break; } - do { - memcpy(&part, where, sizeof part); - owhere = where; - where += (getle32(part.len) + 8); - } while (where < end && strncmp(part.name, strdata, sizeof strdata)); + found = find_riff_chunk(strdata, &remain, &where, &len); + if (!found) + return (AUDIO_EWAVNODATA); - if ((where - getle32(part.len)) <= end) { + if (len) { if (channels) *channels = (u_int)getle16(fmt.channels); if (sample) @@ -206,10 +289,12 @@ audio_wav_parse_hdr(void *hdr, size_t sz if (prec) *prec = newprec; if (datasize) - *datasize = (off_t)getle32(part.len); - return (owhere - (char *)hdr + 8); + *datasize = (off_t)len; + return (where - (char *)hdr); } return (AUDIO_EWAVNODATA); + +#undef ADJUST } @@ -225,7 +310,7 @@ wav_prepare_header(struct track_info *ti * * bytes purpose * 0-3 "RIFF" - * 4-7 file length (minus 8) + * 4-7 RIFF chunk length (file length minus 8) * 8-15 "WAVEfmt " * 16-19 format size * 20-21 format tag @@ -272,6 +357,8 @@ wav_prepare_header(struct track_info *ti break; case 16: break; + case 24: + break; case 32: break; default: @@ -357,7 +444,7 @@ wav_prepare_header(struct track_info *ti abps = (double)align*ti->sample_rate / (double)1 + 0.5; nsample = (datalen / ti->precision) / ti->sample_rate; - + /* * now we've calculated the info, write it out! */ Index: src/usr.bin/audio/ctl/audioctl.1 diff -u src/usr.bin/audio/ctl/audioctl.1:1.23 src/usr.bin/audio/ctl/audioctl.1:1.23.2.1 --- src/usr.bin/audio/ctl/audioctl.1:1.23 Thu May 9 09:37:11 2019 +++ src/usr.bin/audio/ctl/audioctl.1 Tue Mar 12 12:41:38 2024 @@ -1,4 +1,4 @@ -.\" $NetBSD: audioctl.1,v 1.23 2019/05/09 09:37:11 wiz Exp $ +.\" $NetBSD: audioctl.1,v 1.23.2.1 2024/03/12 12:41:38 martin Exp $ .\" .\" Copyright (c) 1997, 1999 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -26,12 +26,12 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd May 8, 2019 +.Dd March 21, 2021 .Dt AUDIOCTL 1 .Os .Sh NAME .Nm audioctl -.Nd control audio device +.Nd control software audio format .Sh SYNOPSIS .Nm .Op Fl n @@ -49,7 +49,26 @@ .Sh DESCRIPTION The .Nm -command displays or sets various audio system driver variables. +command displays or sets the parameters that determine the playback and +recording format for software using an audio device. +It is most useful when the full +.Xr audio 4 +API is not available, e.g. when playing or recording raw audio data from a +.Xr sh 1 +script, or from the command line. +It does not control the underlying hardware format, which can be +changed with +.Xr audiocfg 1 . +.Pp +The variables that can be inspected and changed with +.Nm +are normally per-application and are reset when a +.Pa /dev/audioX +device is opened. +This can be circumvented by using +.Pa /dev/soundX +instead, which retains global state. +.Pp If a list of variables is present on the command line, then .Nm prints the current value of those variables for the specified device. @@ -77,32 +96,23 @@ the audio control device to use. .El .Sh FILES .Bl -tag -width /dev/audioctl0 -compact -.It Pa /dev/audio0 -audio I/O device (resets on open) +.It Pa /dev/sound0 +audio I/O device .It Pa /dev/audioctl0 audio control device -.It Pa /dev/sound0 -audio I/O device (does not reset on open) .El .Sh EXAMPLES To set the playing sampling rate to 11025, you can use .Dl audioctl -w play.sample_rate=11025 To set all of the play parameters for CD-quality audio, you can use .Dl audioctl -w play=44100,2,16,slinear_le -Note that many of the variables that can be inspected and changed with -.Nm -are reset when -.Pa /dev/audio0 -is opened. -This can be circumvented by using -.Pa /dev/sound0 -instead. .Sh COMPATIBILITY The old .Fl f flag is still supported. This support will be removed eventually. .Sh SEE ALSO +.Xr audiocfg 1 , .Xr audioplay 1 , .Xr audiorecord 1 , .Xr mixerctl 1 , @@ -113,3 +123,21 @@ The .Nm command first appeared in .Nx 1.3 . +.Sh CAVEATS +Since the parameters controlled by +.Nm +are global, they can be changed unexpectedly if another application +uses the same audio device. +.Pp +It is always preferable to use +.Dv AUDIO_SETINFO +on a per-process +.Pa /dev/audioX +device, if the +.Xr audio 4 +ioctls are available in the programming environment. +Similarly, +.Xr audioplay 1 +and +.Xr audiorecord 1 +are more safe for use in scripting. Index: src/usr.bin/audio/play/audioplay.1 diff -u src/usr.bin/audio/play/audioplay.1:1.26.28.1 src/usr.bin/audio/play/audioplay.1:1.26.28.2 --- src/usr.bin/audio/play/audioplay.1:1.26.28.1 Tue Feb 14 16:03:17 2023 +++ src/usr.bin/audio/play/audioplay.1 Tue Mar 12 12:41:39 2024 @@ -1,6 +1,6 @@ -.\" $NetBSD: audioplay.1,v 1.26.28.1 2023/02/14 16:03:17 martin Exp $ +.\" $NetBSD: audioplay.1,v 1.26.28.2 2024/03/12 12:41:39 martin Exp $ .\" -.\" Copyright (c) 1998, 1999, 2002, 2010 Matthew R. Green +.\" Copyright (c) 1998, 1999, 2002, 2010, 2019, 2024 Matthew R. Green .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 30, 2010 +.Dd March 3, 2024 .Dt AUDIOPLAY 1 .Os .Sh NAME @@ -32,7 +32,7 @@ .Nd play audio files .Sh SYNOPSIS .Nm -.Op Fl hiqV +.Op Fl hinqV .Op Fl B Ar buffersize .Op Fl b Ar balance .Op Fl d Ar device @@ -118,6 +118,8 @@ sample rate. Print a help message. .It Fl i If the audio device cannot be opened, exit now rather than wait for it. +.It Fl n +Do not write audio data, only parse files for sanity. .It Fl P When combined with the .Fl f @@ -169,9 +171,17 @@ program can be used to show the availabl .Nm can be used to play Sun/NeXT audio files, and also RIFF WAVE audio files. .Nm -can be configured in the -.Dq Netscape -web browser as the program to use when playing audio files. +can be configured in a web browser as the program to use when playing audio +files. +.Pp +In addition to the audio driver encodings list in the EXAMPLES section, +.Nm +supports playing IEEE floating point data in RIFF WAVE audio files +(with one caveat that the floating point size must be native). +In this case +.Nm +converts the floating point data into signed linear samples before +they are passed to the chosen audio device. .Sh ERRORS If the audio device or the control device can not be opened, an error is returned. @@ -182,29 +192,7 @@ hardware driver. .Sh SEE ALSO .Xr audioctl 1 , .Xr audiorecord 1 , -.Xr aria 4 , -.Xr audio 4 , -.Xr audioamd 4 , -.Xr auich 4 , -.Xr autri 4 , -.Xr auvia 4 , -.Xr clcs 4 , -.Xr clct 4 , -.Xr cmpci 4 , -.Xr eap 4 , -.Xr emuxki 4 , -.Xr esm 4 , -.Xr eso 4 , -.Xr ess 4 , -.Xr fms 4 , -.Xr gus 4 , -.Xr guspnp 4 , -.Xr neo 4 , -.Xr sb 4 , -.Xr sv 4 , -.Xr wss 4 , -.Xr yds 4 , -.Xr ym 4 +.Xr audio 4 .Sh HISTORY The .Nm @@ -214,8 +202,12 @@ The .Nm was first made available in .Nx 1.4 . +Support for RIFF WAVE recording was introduced in +.Nx 1.6 . +Support for RIFF WAVE IEEE floating point data was introduced in +.Nx 10.0 . .Sh AUTHORS The .Nm program was written by -.An Matthew R. Green Aq Mt m...@eterna.com.au . +.An Matthew R. Green Aq Mt m...@eterna23.net . Index: src/usr.bin/audio/play/play.c diff -u src/usr.bin/audio/play/play.c:1.57 src/usr.bin/audio/play/play.c:1.57.2.1 --- src/usr.bin/audio/play/play.c:1.57 Sat May 4 08:27:30 2019 +++ src/usr.bin/audio/play/play.c Tue Mar 12 12:41:39 2024 @@ -1,7 +1,7 @@ -/* $NetBSD: play.c,v 1.57 2019/05/04 08:27:30 isaki Exp $ */ +/* $NetBSD: play.c,v 1.57.2.1 2024/03/12 12:41:39 martin Exp $ */ /* - * Copyright (c) 1999, 2000, 2001, 2002, 2010 Matthew R. Green + * Copyright (c) 1999, 2000, 2001, 2002, 2010, 2015, 2019, 2021 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,10 +28,9 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: play.c,v 1.57 2019/05/04 08:27:30 isaki Exp $"); +__RCSID("$NetBSD: play.c,v 1.57.2.1 2024/03/12 12:41:39 martin Exp $"); #endif - #include <sys/param.h> #include <sys/audioio.h> #include <sys/ioctl.h> @@ -51,10 +50,14 @@ __RCSID("$NetBSD: play.c,v 1.57 2019/05/ #include "libaudio.h" +typedef size_t (*convert)(void *inbuf, void *outbuf, size_t len); + static void usage(void) __dead; static void play(char *); static void play_fd(const char *, int); -static ssize_t audioctl_write_fromhdr(void *, size_t, int, off_t *, const char *); +static ssize_t audioctl_write_fromhdr(void *, size_t, int, + off_t *, const char *, + convert *); static void cleanup(int) __dead; static audio_info_t info; @@ -62,6 +65,7 @@ static int volume; static int balance; static int port; static int fflag; +static int nflag; static int qflag; int verbose; static int sample_rate; @@ -72,7 +76,7 @@ static int channels; static char const *play_errstring = NULL; static size_t bufsize; -static int audiofd; +static int audiofd = -1; static int exitstatus = EXIT_SUCCESS; int @@ -84,7 +88,7 @@ main(int argc, char *argv[]) const char *defdevice = _PATH_SOUND; const char *device = NULL; - while ((ch = getopt(argc, argv, "b:B:C:c:d:e:fhip:P:qs:Vv:")) != -1) { + while ((ch = getopt(argc, argv, "b:B:C:c:d:e:fhinp:P:qs:Vv:")) != -1) { switch (ch) { case 'b': decode_int(optarg, &balance); @@ -115,6 +119,9 @@ main(int argc, char *argv[]) case 'i': iflag++; break; + case 'n': + nflag++; + break; case 'q': qflag++; break; @@ -170,22 +177,22 @@ main(int argc, char *argv[]) (device = getenv("AUDIODEV")) == NULL) /* Sun compatibility */ device = defdevice; - audiofd = open(device, O_WRONLY); - if (audiofd < 0 && device == defdevice) { - device = _PATH_SOUND0; + if (!nflag) { audiofd = open(device, O_WRONLY); - } - - if (audiofd < 0) - err(1, "failed to open %s", device); + if (audiofd < 0 && device == defdevice) { + device = _PATH_SOUND0; + audiofd = open(device, O_WRONLY); + } + if (audiofd < 0) + err(1, "failed to open %s", device); - if (ioctl(audiofd, AUDIO_GETINFO, &info) < 0) - err(1, "failed to get audio info"); - if (bufsize == 0) { - bufsize = info.play.buffer_size; - if (bufsize < 32 * 1024) - bufsize = 32 * 1024; + if (ioctl(audiofd, AUDIO_GETINFO, &info) < 0) + err(1, "failed to get audio info"); + if (bufsize == 0) + bufsize = info.play.buffer_size; } + if (bufsize == 0) + bufsize = 32 * 1024; signal(SIGINT, cleanup); signal(SIGTERM, cleanup); @@ -205,18 +212,105 @@ static void cleanup(int signo) { - (void)ioctl(audiofd, AUDIO_FLUSH, NULL); - (void)ioctl(audiofd, AUDIO_SETINFO, &info); - close(audiofd); + if (audiofd != -1) { + (void)ioctl(audiofd, AUDIO_FLUSH, NULL); + (void)ioctl(audiofd, AUDIO_SETINFO, &info); + close(audiofd); + audiofd = -1; + } if (signo != 0) { (void)raise_default_signal(signo); } exit(exitstatus); } +#ifndef __vax__ +static size_t +float32_to_linear32(void *inbuf, void *outbuf, size_t len) +{ + uint8_t *inbuf8 = inbuf, *end = inbuf8 + len; + uint8_t *outbuf8 = outbuf; + float f; + int32_t i; + + while (inbuf8 + sizeof f <= end) { + memcpy(&f, inbuf8, sizeof f); + + /* saturate */ + if (f < -1.0) + f = -1.0; + if (f > 1.0) + f = 1.0; + + /* Convert -1.0 to +1.0 into a 32 bit signed value */ + i = f * (float)INT32_MAX; + + memcpy(outbuf8, &i, sizeof i); + + inbuf8 += sizeof f; + outbuf8 += sizeof i; + } + + return len; +} + +static size_t +float64_to_linear32(void *inbuf, void *outbuf, size_t len) +{ + uint8_t *inbuf8 = inbuf, *end = inbuf8 + len; + uint8_t *outbuf8 = outbuf; + double f; + int32_t i; + + while (inbuf8 + sizeof f <= end) { + memcpy(&f, inbuf8, sizeof f); + + /* saturate */ + if (f < -1.0) + f = -1.0; + if (f > 1.0) + f = 1.0; + + /* Convert -1.0 to +1.0 into a 32 bit signed value */ + i = f * ((1u << 31) - 1); + + memcpy(outbuf8, &i, sizeof i); + + inbuf8 += sizeof f; + outbuf8 += sizeof i; + } + + return len / 2; +} +#endif /* __vax__ */ + +static size_t +audio_write(int fd, void *buf, size_t len, convert conv) +{ + static void *convert_buffer; + static size_t convert_buffer_size; + + if (nflag) + return len; + + if (conv == NULL) + return write(fd, buf, len); + + if (convert_buffer == NULL || convert_buffer_size < len) { + free(convert_buffer); + convert_buffer = malloc(len); + if (convert_buffer == NULL) + err(1, "malloc of convert buffer failed"); + convert_buffer_size = len; + } + len = conv(buf, convert_buffer, len); + return write(fd, convert_buffer, len); +} + static void play(char *file) { + convert conv = NULL; struct stat sb; void *addr, *oaddr; off_t filesize; @@ -233,8 +327,7 @@ play(char *file) fd = open(file, O_RDONLY); if (fd < 0) { - if (!qflag) - warn("could not open %s", file); + warn("could not open %s", file); exitstatus = EXIT_FAILURE; return; } @@ -265,15 +358,18 @@ play(char *file) madvise(addr, sizet_filesize, MADV_SEQUENTIAL); /* - * get the header length and set up the audio device + * get the header length and set up the audio device, and + * determine any conversion needed. */ if ((hdrlen = audioctl_write_fromhdr(addr, - sizet_filesize, audiofd, &datasize, file)) < 0) { + sizet_filesize, audiofd, &datasize, file, &conv)) < 0) { if (play_errstring) errx(1, "%s: %s", play_errstring, file); else errx(1, "unknown audio file: %s", file); } + if (verbose) + printf("header length: %zd\n", hdrlen); filesize -= hdrlen; addr = (char *)addr + hdrlen; @@ -284,7 +380,7 @@ play(char *file) } while ((uint64_t)datasize > bufsize) { - nw = write(audiofd, addr, bufsize); + nw = audio_write(audiofd, addr, bufsize, conv); if (nw == -1) err(1, "write failed"); if ((size_t)nw != bufsize) @@ -292,13 +388,13 @@ play(char *file) addr = (char *)addr + bufsize; datasize -= bufsize; } - nw = write(audiofd, addr, datasize); + nw = audio_write(audiofd, addr, datasize, conv); if (nw == -1) err(1, "final write failed"); if ((off_t)nw != datasize) errx(1, "final write failed"); - if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) + if (!nflag && ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) warn("audio drain ioctl failed"); if (munmap(oaddr, sizet_filesize) < 0) err(1, "munmap failed"); @@ -312,6 +408,7 @@ play(char *file) static void play_fd(const char *file, int fd) { + convert conv = NULL; char *buffer = malloc(bufsize); ssize_t hdrlen; int nr, nw; @@ -331,7 +428,7 @@ play_fd(const char *file, int fd) } err(1, "unexpected EOF"); } - hdrlen = audioctl_write_fromhdr(buffer, nr, audiofd, &datasize, file); + hdrlen = audioctl_write_fromhdr(buffer, nr, audiofd, &datasize, file, &conv); if (hdrlen < 0) { if (play_errstring) errx(1, "%s: %s", play_errstring, file); @@ -347,7 +444,7 @@ play_fd(const char *file, int fd) while (datasize == 0 || dataout < datasize) { if (datasize != 0 && dataout + nr > datasize) nr = datasize - dataout; - nw = write(audiofd, buffer, nr); + nw = audio_write(audiofd, buffer, nr, conv); if (nw == -1) err(1, "audio device write failed"); if (nw != nr) @@ -360,7 +457,7 @@ play_fd(const char *file, int fd) break; } /* something to think about: no message given for dataout < datasize */ - if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) + if (!nflag && ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) warn("audio drain ioctl failed"); return; read_error: @@ -374,11 +471,13 @@ read_error: * uses the local "info" variable. blah... fix me! */ static ssize_t -audioctl_write_fromhdr(void *hdr, size_t fsz, int fd, off_t *datasize, const char *file) +audioctl_write_fromhdr(void *hdr, size_t fsz, int fd, off_t *datasize, const char *file, convert *conv) { sun_audioheader *sunhdr; ssize_t hdr_len = 0; + *conv = NULL; + AUDIO_INITINFO(&info); sunhdr = hdr; if (ntohl(sunhdr->magic) == AUDIO_FILE_MAGIC) { @@ -457,7 +556,33 @@ set_audio_mode: enc ? enc : ""); } - if (ioctl(fd, AUDIO_SETINFO, &info) < 0) +#ifndef __vax__ + if (info.play.encoding == AUDIO_ENCODING_LIBAUDIO_FLOAT32 || + info.play.encoding == AUDIO_ENCODING_LIBAUDIO_FLOAT64) { + const char *msg; + + if (info.play.encoding == AUDIO_ENCODING_LIBAUDIO_FLOAT32) { + if (sizeof(float) * CHAR_BIT != 32) + return -1; + *conv = float32_to_linear32; + msg = "32"; + } else { + if (sizeof(double) * CHAR_BIT != 64) + return -1; + *conv = float64_to_linear32; + msg = "64"; + } + info.play.encoding = AUDIO_ENCODING_SLINEAR_LE; + info.play.precision = 32; + if (verbose) + printf("%s: converting IEEE float%s to precision=%d " + "encoding=%s\n", file, msg, + info.play.precision, + audio_enc_from_val(info.play.encoding)); + } +#endif /* __vax__ */ + + if (!nflag && ioctl(fd, AUDIO_SETINFO, &info) < 0) err(1, "failed to set audio info"); return (hdr_len); @@ -467,7 +592,7 @@ static void usage(void) { - fprintf(stderr, "Usage: %s [-hiqV] [options] files\n", getprogname()); + fprintf(stderr, "Usage: %s [-hinqV] [options] files\n", getprogname()); fprintf(stderr, "Options:\n\t" "-B buffer size\n\t" "-b balance (0-63)\n\t" Index: src/usr.bin/audio/record/audiorecord.1 diff -u src/usr.bin/audio/record/audiorecord.1:1.42 src/usr.bin/audio/record/audiorecord.1:1.42.28.1 --- src/usr.bin/audio/record/audiorecord.1:1.42 Tue Mar 18 18:20:44 2014 +++ src/usr.bin/audio/record/audiorecord.1 Tue Mar 12 12:41:39 2024 @@ -1,4 +1,4 @@ -.\" $NetBSD: audiorecord.1,v 1.42 2014/03/18 18:20:44 riastradh Exp $ +.\" $NetBSD: audiorecord.1,v 1.42.28.1 2024/03/12 12:41:39 martin Exp $ .\" .\" Copyright (c) 1998, 1999, 2001, 2002, 2010 Matthew R. Green .\" All rights reserved. @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 30, 2010 +.Dd March 25, 2021 .Dt AUDIORECORD 1 .Os .Sh NAME @@ -181,12 +181,14 @@ the audio control device to be used. .It AUDIODEVICE the audio device to be used. .El +.Sh EXAMPLES +Record CD quality audio to a WAVE file: +.Dl audiorecord -c 2 -e slinear_le -P 16 -s 44100 recording.wav .Sh SEE ALSO .Xr audioctl 1 , .Xr audioplay 1 , .Xr aria 4 , .Xr audio 4 , -.Xr audioamd 4 , .Xr auich 4 , .Xr autri 4 , .Xr auvia 4 , @@ -203,6 +205,7 @@ the audio device to be used. .Xr guspnp 4 , .Xr neo 4 , .Xr sb 4 , +.Xr sparc/audioamd 4 , .Xr sv 4 , .Xr wss 4 , .Xr yds 4 , @@ -220,7 +223,7 @@ big/little-endian samples was first made The .Nm program was written by -.An Matthew R. Green Aq Mt m...@eterna.com.au . +.An Matthew R. Green Aq Mt m...@eterna23.net . .Sh BUGS WAV big-endian samples are converted to little-endian, rather than a RIFX header being written. Index: src/usr.bin/audio/record/record.c diff -u src/usr.bin/audio/record/record.c:1.54 src/usr.bin/audio/record/record.c:1.54.18.1 --- src/usr.bin/audio/record/record.c:1.54 Wed Aug 5 06:54:39 2015 +++ src/usr.bin/audio/record/record.c Tue Mar 12 12:41:39 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: record.c,v 1.54 2015/08/05 06:54:39 mrg Exp $ */ +/* $NetBSD: record.c,v 1.54.18.1 2024/03/12 12:41:39 martin Exp $ */ /* * Copyright (c) 1999, 2002, 2003, 2005, 2010 Matthew R. Green @@ -32,7 +32,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: record.c,v 1.54 2015/08/05 06:54:39 mrg Exp $"); +__RCSID("$NetBSD: record.c,v 1.54.18.1 2024/03/12 12:41:39 martin Exp $"); #endif @@ -68,6 +68,7 @@ static char *encoding_str; static struct track_info ti; static struct timeval record_time; static struct timeval start_time; +static int no_time_limit = 1; static void (*conv_func) (u_char *, int); @@ -75,13 +76,21 @@ static void usage (void) __dead; static int timeleft (struct timeval *, struct timeval *); static void cleanup (int) __dead; static void rewrite_header (void); +static void stop (int); + +static void stop (int sig) +{ + no_time_limit = 0; + timerclear(&record_time); +} int main(int argc, char *argv[]) { u_char *buffer; size_t len, bufsize = 0; - int ch, no_time_limit = 1; + ssize_t nread; + int ch; const char *defdevice = _PATH_SOUND; /* @@ -283,7 +292,7 @@ main(int argc, char *argv[]) if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0) err(1, "failed to set audio info"); - signal(SIGINT, cleanup); + signal(SIGINT, stop); ti.total_size = 0; @@ -303,19 +312,27 @@ main(int argc, char *argv[]) s = "change sign (big-endian, 16 bit)"; else if (conv_func == change_sign16_le) s = "change sign (little-endian, 16 bit)"; + else if (conv_func == change_sign24_be) + s = "change sign (big-endian, 24 bit)"; + else if (conv_func == change_sign24_le) + s = "change sign (little-endian, 24 bit)"; else if (conv_func == change_sign32_be) s = "change sign (big-endian, 32 bit)"; else if (conv_func == change_sign32_le) s = "change sign (little-endian, 32 bit)"; else if (conv_func == change_sign16_swap_bytes_be) s = "change sign & swap bytes (big-endian, 16 bit)"; - else if (conv_func == change_sign16_swap_bytes_le) + else if (conv_func == change_sign24_swap_bytes_le) s = "change sign & swap bytes (little-endian, 16 bit)"; + else if (conv_func == change_sign16_swap_bytes_be) + s = "change sign & swap bytes (big-endian, 24 bit)"; + else if (conv_func == change_sign24_swap_bytes_le) + s = "change sign & swap bytes (little-endian, 24 bit)"; else if (conv_func == change_sign32_swap_bytes_be) s = "change sign (big-endian, 32 bit)"; else if (conv_func == change_sign32_swap_bytes_le) s = "change sign & swap bytes (little-endian, 32 bit)"; - + if (s) fprintf(stderr, "%s: converting, using function: %s\n", getprogname(), s); @@ -337,13 +354,15 @@ main(int argc, char *argv[]) (void)gettimeofday(&start_time, NULL); while (no_time_limit || timeleft(&start_time, &record_time)) { - if ((size_t)read(audiofd, buffer, bufsize) != bufsize) + if ((nread = read(audiofd, buffer, bufsize)) == -1) err(1, "read failed"); + if (nread == 0) + break; if (conv_func) - (*conv_func)(buffer, bufsize); - if ((size_t)write(ti.outfd, buffer, bufsize) != bufsize) + (*conv_func)(buffer, nread); + if (write(ti.outfd, buffer, nread) != nread) err(1, "write failed"); - ti.total_size += bufsize; + ti.total_size += nread; } cleanup(0); } @@ -386,7 +405,6 @@ rewrite_header(void) /* can't do this here! */ if (ti.outfd == STDOUT_FILENO) return; - if (lseek(ti.outfd, (off_t)0, SEEK_SET) == (off_t)-1) err(1, "could not seek to start of file for header rewrite"); write_header(&ti);