From 841b9f38aa91ad6ff1fd33d19792175bc821aa5c Mon Sep 17 00:00:00 2001 From: j50n Date: Sat, 12 Feb 2022 21:02:30 -0700 Subject: [PATCH] #16 added a sounds example --- README.md | 3 +- build | 4 + examples/pushiterable/README.md | 3 + examples/sounds/README.md | 19 +++ examples/sounds/sounds.ts | 49 ++++++++ examples/warandpeace/README.md | 4 +- oundsUrl(name: string): string{ | 212 ++++++++++++++++++++++++++++++++ release-notes.md | 4 + 8 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 examples/sounds/README.md create mode 100755 examples/sounds/sounds.ts create mode 100644 oundsUrl(name: string): string{ diff --git a/README.md b/README.md index 5f90d98..b16a78e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ deno doc --reload https://deno.land/x/proc/mod.ts 2> /dev/null ## Examples - [Simple Examples for Input and Output Handlers](./runners/handlers/README.md) -- [Count Unique Words in _War and Peace_](./examples/warandpeace/README.md) +- [Playing Sounds with `aplay`](./examples/sounds/README.md) +- [Count the Unique Words in _War and Peace_](./examples/warandpeace/README.md) - [Use `PushIterable` to Implement Workers](./examples/pushiterable/README.md) ## Related Projects diff --git a/build b/build index b645367..f7ef09a 100755 --- a/build +++ b/build @@ -21,4 +21,8 @@ cd "$HERE/examples/warandpeace" && ( cd "$HERE/examples/pushiterable" && ( PATH=".:$PATH" ./example-of-pushiterable.ts +) + +cd "$HERE/examples/sounds" && ( + ./sounds.ts ) \ No newline at end of file diff --git a/examples/pushiterable/README.md b/examples/pushiterable/README.md index d31ad67..87c4ca0 100644 --- a/examples/pushiterable/README.md +++ b/examples/pushiterable/README.md @@ -1,5 +1,8 @@ # Use `PushIterable` to Implement Workers +This example takes a fundamentally different approach to running child +processes, flipping the direction of the data on the input (`stdin`) side. + `proc` can be used to manage persistent child processes that accept messages from your parent process and respond back with messages of their own. In order to "push" messages to a process, you need to use a diff --git a/examples/sounds/README.md b/examples/sounds/README.md new file mode 100644 index 0000000..3aab476 --- /dev/null +++ b/examples/sounds/README.md @@ -0,0 +1,19 @@ +# Playing Sounds with `aplay` + +Did you ever wonder if there were an easy way to play sounds in Deno? + +Deno does not yet support the Web Audio API, so our ability to play sounds +natively is limited. Fortunately, `aplay` is available (at least on Ubuntu) +without requiring an install. + +Programs that are written in `C`, like `aplay`, start up very quickly and run +efficiently. You can play a sound - or even multiple sounds at the same time - +without missing a beat. The example demonstrates this. The one caveat is IO +speed - if you are loading sounds from something other than memory. The example +downloads the sounds it will need into memory first, before it attempts to play +them. The WAV files are streamed through `stdin` to `aplay` using buffered, +non-blocking IO. + +Have fun! + +[sounds.ts](./sounds.ts) diff --git a/examples/sounds/sounds.ts b/examples/sounds/sounds.ts new file mode 100755 index 0000000..ba658a7 --- /dev/null +++ b/examples/sounds/sounds.ts @@ -0,0 +1,49 @@ +#!/usr/bin/env -S deno run --allow-run=aplay --allow-net=github.com,raw.githubusercontent.com + +import * as proc from "../../mod.ts"; + +/** + * Grab the sound files from my github repository. + * @param name The name of the sound. + * @returns The WAV file. + */ +async function getSoundFile(name: string): Promise { + const url = + `https://github.com/j50n/deno-proc/blob/main/examples/sounds/${name}.wav?raw=true`; + return new Uint8Array(await (await fetch(url)).arrayBuffer()); +} + +/** + * Play a sound using `aplay`. + * @param sound A WAV file. + */ +async function play(sound: Uint8Array): Promise { + for await ( + const line of proc.runner( + proc.bytesInput(), + proc.stringIterableUnbufferedOutput(), + )().run({ cmd: ["aplay"] }, sound) + ) { + console.log(line); + } +} + +const [cowWav, cowbellWav] = await Promise.all([ + getSoundFile("cow"), + getSoundFile("cowbell"), +]); + +console.log(`MOO sound is ${cowWav.length} bytes.`); +console.log(`Bell sound is ${cowbellWav.length} bytes.`); + +/* Moo. */ +await play(cowWav); +await proc.sleep(100); + +/* Ring a bell. */ +await play(cowbellWav); +await proc.sleep(100); + +/* Moo and ring a bell. */ +await Promise.all([play(cowWav), play(cowbellWav)]); +await proc.sleep(100); diff --git a/examples/warandpeace/README.md b/examples/warandpeace/README.md index 523b5ae..c721401 100644 --- a/examples/warandpeace/README.md +++ b/examples/warandpeace/README.md @@ -1,4 +1,6 @@ -# Count Unique Words in _War and Peace_ +# Count the Unique Words in _War and Peace_ + +This is a fun little example of line-oriented data processing. Tolstoy's _War and Peace_ is sprawling and immense, and it uses a lot of words. But how many _unique_ words does it contain? diff --git a/oundsUrl(name: string): string{ b/oundsUrl(name: string): string{ new file mode 100644 index 0000000..3a62d3a --- /dev/null +++ b/oundsUrl(name: string): string{ @@ -0,0 +1,212 @@ +APLAY(1) General Commands Manual APLAY(1) + +NNAAMMEE + arecord, aplay - command-line sound recorder and player for ALSA soundcard driver + +SSYYNNOOPPSSIISS + aarreeccoorrdd [_f_l_a_g_s] [filename] + aappllaayy [_f_l_a_g_s] [filename [filename]] ... + +DDEESSCCRRIIPPTTIIOONN + aarreeccoorrdd is a command-line soundfile recorder for the ALSA soundcard driver. It supports several file formats and multiple + soundcards with multiple devices. If recording with interleaved mode samples the file is automatically split before the + 2GB filesize. + + aappllaayy is much the same, only it plays instead of recording. For supported soundfile formats, the sampling rate, bit depth, + and so forth can be automatically determined from the soundfile header. + + If filename is not specified, the standard output or input is used. The aappllaayy utility accepts multiple filenames. + +OOPPTTIIOONNSS + _-_h_, _-_-_h_e_l_p + Help: show syntax. + + _-_-_v_e_r_s_i_o_n + Print current version. + + _-_l_, _-_-_l_i_s_t_-_d_e_v_i_c_e_s + List all soundcards and digital audio devices + + _-_L_, _-_-_l_i_s_t_-_p_c_m_s + List all PCMs defined + + _-_D_, _-_-_d_e_v_i_c_e_=_N_A_M_E + Select PCM by name + + _-_q _-_-_q_u_i_e_t + Quiet mode. Suppress messages (not sound :)) + + _-_t_, _-_-_f_i_l_e_-_t_y_p_e _T_Y_P_E + File type (voc, wav, raw or au). If this parameter is omitted the WAVE format is used. + + _-_c_, _-_-_c_h_a_n_n_e_l_s_=_# + The number of channels. The default is one channel. Valid values are 1 through 32. + + _-_f _-_-_f_o_r_m_a_t_=_F_O_R_M_A_T + Sample format + Recognized sample formats are: S8 U8 S16_LE S16_BE U16_LE U16_BE S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE + U32_BE FLOAT_LE FLOAT_BE FLOAT64_LE FLOAT64_BE IEC958_SUBFRAME_LE IEC958_SUBFRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG + GSM SPECIAL S24_3LE S24_3BE U24_3LE U24_3BE S20_3LE S20_3BE U20_3LE U20_3BE S18_3LE S18_3BE U18_3LE + Some of these may not be available on selected hardware + The available format shortcuts are: + -f cd (16 bit little endian, 44100, stereo) [-f S16_LE -c2 -r44100] + -f cdr (16 bit big endian, 44100, stereo) [-f S16_BE -c2 -f44100] + -f dat (16 bit little endian, 48000, stereo) [-f S16_LE -c2 -r48000] + If no format is given U8 is used. + + _-_r_, _-_-_r_a_t_e_=_#_<_H_z_> + Sampling rate in Hertz. The default rate is 8000 Hertz. If the value specified is less than 300, it is taken as + the rate in kilohertz. Valid values are 2000 through 192000 Hertz. + + _-_d_, _-_-_d_u_r_a_t_i_o_n_=_# + Interrupt after # seconds. A value of zero means infinity. The default is zero, so if this option is omitted then + the record/playback process will run until it is killed. Either '-d' or '-s' option is available exclusively. + + _-_s_, _-_-_s_a_m_p_l_e_s_=_# + Interrupt after tranmission of # PCM frames. A value of zero means infinity. The default is zero, so if this op‐ + tions is omitted then the record/playback process will run until it is killed. Either '-d' or '-s' option is + available exclusively. + + _-_M_, _-_-_m_m_a_p + Use memory-mapped (mmap) I/O mode for the audio stream. If this option is not set, the read/write I/O mode will be + used. + + _-_N_, _-_-_n_o_n_b_l_o_c_k + Open the audio device in non-blocking mode. If the device is busy the program will exit immediately. If this op‐ + tion is not set the program will block until the audio device is available again. + + _-_F_, _-_-_p_e_r_i_o_d_-_t_i_m_e_=_# + Distance between interrupts is # microseconds. If no period time and no period size is given then a quarter of the + buffer time is set. + + _-_B_, _-_-_b_u_f_f_e_r_-_t_i_m_e_=_# + Buffer duration is # microseconds If no buffer time and no buffer size is given then the maximal allowed buffer + time but not more than 500ms is set. + + _-_-_p_e_r_i_o_d_-_s_i_z_e_=_# + Distance between interrupts is # frames If no period size and no period time is given then a quarter of the buffer + size is set. + + _-_-_b_u_f_f_e_r_-_s_i_z_e_=_# + Buffer duration is # frames If no buffer time and no buffer size is given then the maximal allowed buffer time but + not more than 500ms is set. + + _-_A_, _-_-_a_v_a_i_l_-_m_i_n_=_# + Min available space for wakeup is # microseconds + + _-_R_, _-_-_s_t_a_r_t_-_d_e_l_a_y_=_# + Delay for automatic PCM start is # microseconds (relative to buffer size if <= 0) + + _-_T_, _-_-_s_t_o_p_-_d_e_l_a_y_=_# + Delay for automatic PCM stop is # microseconds from xrun + + _-_v_, _-_-_v_e_r_b_o_s_e + Show PCM structure and setup. This option is accumulative. The VU meter is displayed when this is given twice or + three times. + + _-_V_, _-_-_v_u_m_e_t_e_r_=_T_Y_P_E + Specifies the VU-meter type, either _s_t_e_r_e_o or _m_o_n_o. The stereo VU-meter is available only for 2-channel stereo + samples with interleaved format. + + _-_I_, _-_-_s_e_p_a_r_a_t_e_-_c_h_a_n_n_e_l_s + One file for each channel. This option disables max-file-time and use-strftime, and ignores SIGUSR1. The stereo + VU meter is not available with separate channels. + + _-_P Playback. This is the default if the program is invoked by typing aplay. + + _-_C Record. This is the default if the program is invoked by typing arecord. + + _-_i_, _-_-_i_n_t_e_r_a_c_t_i_v_e + Allow interactive operation via stdin. Currently only pause/resume via space or enter key is implemented. + + _-_m_, _-_-_c_h_m_a_p_=_c_h_1_,_c_h_2_,_._._. + Give the channel map to override or follow. Pass channel position strings like _F_L, _F_R, etc. + + If a device supports the override of the channel map, aappllaayy tries to pass the given channel map. If it doesn't + support the channel map override but still it provides the channel map information, aappllaayy tries to rearrange the + channel order in the buffer to match with the returned channel map from the device. + + _-_-_d_i_s_a_b_l_e_-_r_e_s_a_m_p_l_e + Disable automatic rate resample. + + _-_-_d_i_s_a_b_l_e_-_c_h_a_n_n_e_l_s + Disable automatic channel conversions. + + _-_-_d_i_s_a_b_l_e_-_f_o_r_m_a_t + Disable automatic format conversions. + + _-_-_d_i_s_a_b_l_e_-_s_o_f_t_v_o_l + Disable software volume control (softvol). + + _-_-_t_e_s_t_-_p_o_s_i_t_i_o_n + Test ring buffer position. + + _-_-_t_e_s_t_-_c_o_e_f_=_<_c_o_e_f_> + Test coefficient for ring buffer position; default is 8. Expression for validation is: coef * (buffer_size / 2). + Minimum value is 1. + + _-_-_t_e_s_t_-_n_o_w_a_i_t + Do not wait for the ring buffer ‐ eats the whole CPU. + + _-_-_m_a_x_-_f_i_l_e_-_t_i_m_e + While recording, when the output file has been accumulating sound for this long, close it and open a new output + file. Default is the maximum size supported by the file format: 2 GiB for WAV files. This option has no effect if + --separate-channels is specified. + + _-_-_p_r_o_c_e_s_s_-_i_d_-_f_i_l_e _<_f_i_l_e _n_a_m_e_> + aplay writes its process ID here, so other programs can send signals to it. + + _-_-_u_s_e_-_s_t_r_f_t_i_m_e + When recording, interpret %-codes in the file name parameter using the strftime facility whenever the output file + is opened. The important strftime codes are: %Y is the year, %m month, %d day of the month, %H hour, %M minute and + %S second. In addition, %v is the file number, starting at 1. When this option is specified, intermediate direc‐ + tories for the output file are created automatically. This option has no effect if --separate-channels is speci‐ + fied. + + _-_-_d_u_m_p_-_h_w_-_p_a_r_a_m_s + Dump hw_params of the device preconfigured status to stderr. The dump lists capabilities of the selected device + such as supported formats, sampling rates, numbers of channels, period and buffer bytes/sizes/times. For raw de‐ + vice hw:X this option basically lists hardware capabilities of the soundcard. + + _-_-_f_a_t_a_l_-_e_r_r_o_r_s + Disables recovery attempts when errors (e.g. xrun) are encountered; the aplay process instead aborts immediately. + +SSIIGGNNAALLSS + When recording, SIGINT, SIGTERM and SIGABRT will close the output file and exit. SIGUSR1 will close the output file, open + a new one, and continue recording. However, SIGUSR1 does not work with --separate-channels. + +EEXXAAMMPPLLEESS + aappllaayy --cc 11 --tt rraaww --rr 2222005500 --ff mmuu__llaaww ffoooobbaarr + will play the raw file "foobar" as a 22050-Hz, mono, 8-bit, Mu-Law .au file. + + aarreeccoorrdd --dd 1100 --ff ccdd --tt wwaavv --DD ccooppyy ffoooobbaarr..wwaavv + will record foobar.wav as a 10-second, CD-quality wave file, using the PCM "copy" (which might be defined in the + user's .asoundrc file as: + pcm.copy { + type plug + slave { + pcm hw + } + route_policy copy + } + + aarreeccoorrdd --tt wwaavv ----mmaaxx--ffiillee--ttiimmee 3300 mmoonn..wwaavv + Record from the default audio source in monaural, 8,000 samples per second, 8 bits per sample. Start a new file + every 30 seconds. File names are mon-nn.wav, where nn increases from 01. The file after mon-99.wav is + mon-100.wav. + + aarreeccoorrdd --ff ccdd --tt wwaavv ----mmaaxx--ffiillee--ttiimmee 33660000 ----uussee--ssttrrffttiimmee %%YY//%%mm//%%dd//lliisstteenn--%%HH--%%MM--%%vv..wwaavv + Record in stereo from the default audio source. Create a new file every hour. The files are placed in directories + based on their start dates and have names which include their start times and file numbers. + +SSEEEE AALLSSOO + aallssaammiixxeerr((11)),, aammiixxeerr((11)) + +BBUUGGSS + Note that .aiff files are not currently supported. + +AAUUTTHHOORR + aarreeccoorrdd and aappllaayy are by Jaroslav Kysela This document is by Paul Winkler . Updated + for Alsa 0.9 by James Tappin + + 1 January 2010 APLAY(1) diff --git a/release-notes.md b/release-notes.md index e6851b7..247bbd6 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,5 +1,9 @@ # Release Notes +## 0.14.1 + +- `#16` **documentation** Demonstrate using `aplay` to play `.wav` files. + ## 0.14.0 - **feature** Support workers with `PushIterable`; includes example.