Hi all...
I intend to do an Audio Function Generator using Awk, (already started thanks to Don), but the biggest thing I have struggled with was variable frequency.
I was going to generate differing sized waveforms on the fly but that would that would mean the frequencies are dependent on any even number of bytes as odd numbered bytes could never create a symmetrical waveform like a sinewave or alternatively have a pre calculated look up table of lots of waveforms and sizes...
Then VOILA, a little lateral thinking created this idea; how about using a back door and forcing a .WAV file to use a different RATE inside its header.
Well it WORKS! WOOHOO...
This is a bash DEMO and has no error checking.
It suffers from aliasing at LF and minor frequency error on HF with and 8 byte sinewave set of values as because of the sampling frequency used.
#!/bin/bash
# VariFreq.sh
# NOTE:- This DEMO is only for 8 bit depth, unsigned integer, mono wave samnples.
# Other depths, stereo and signed 16 bit integers are equally posiible but this is all I need.
# Creative Commons Licence CC0. (Public Domain). First Upload to http://www.unix.com.
#
HEADER_START="\\x52\\x49\\x46\\x46\\x24\\x00\\x08\\x00\\x57\\x41\\x56\\x45\\x66\\x6d\\x74\\x20\\x10\\x00\\x00\\x00\\x01\\x00\\x01\\x00"
# bit 'RATE' and byte 'rate' default settings at 8000 SPS, 8 bit depth, mono, unsigned integer.
RATE="\\x40\\x1f\\x00\\x00\\x40\\x1f\\x00\\x00"
HEADER_END="\\x01\\x00\\x08\\x00\\x64\\x61\\x74\\x61\\x00\\x00\\x08\\x00"
DATA="\\x80\\x26\\x00\\x26\\x7F\\xD9\\xFF\\xD9"
FREQ=1000
SAMPLE=8000
BURST=10
#
clear
#
audio_signal()
{
# Generate the 512KB file.
printf "%b" "$HEADER_START" > /tmp/sinewave.wav
printf "%b" "$RATE" >> /tmp/sinewave.wav
printf "%b" "$HEADER_END" >> /tmp/sinewave.wav
for waveform in {0..15}
do
DATA=$DATA$DATA
done
printf "%b" "$DATA" >> /tmp/sinewave.wav
}
#
while true
do
printf "\nEnter frequency between 250 and 6000, Ctrl-C to stop:- "
read -r FREQ
echo ""
# Limited error checking here as it is a DEMO.
if [ "$FREQ" = "" ]
then
FREQ=1000
fi
SAMPLE=$(( 8 * FREQ ))
if [ "$FREQ" -gt 6000 ] || [ "$FREQ" -lt 250 ]
then
# Reset to 1KHz.
SAMPLE=8000
fi
SAMPLE=$( printf "%04x" "$SAMPLE" )
RATE="\\x${SAMPLE:2:2}\\x${SAMPLE:0:2}\\x00\\x00\\x${SAMPLE:2:2}\\x${SAMPLE:0:2}\\x00\\x00"
DATA="\\x80\\x26\\x00\\x26\\x7F\\xD9\\xFF\\xD9"
audio_signal
# OSX command line player.
afplay -t $BURST -d /tmp/sinewave.wav
# ALSA command line player.
# aplay -d $BURST -v /tmp/sinewave.wav
done
Results, MBP OSX 10.7.5, default bash terminal.
Enter frequency between 250 and 6000, Ctrl-C to stop:- 1357
Playing file: /tmp/sinewave.wav
Playing format: AudioStreamBasicDescription: 1 ch, 10856 Hz, 'lpcm' (0x00000008) 8-bit unsigned integer
Buffer Byte Size: 16384, Num Packets to Read: 16384
Enter frequency between 250 and 6000, Ctrl-C to stop:- 577
Playing file: /tmp/sinewave.wav
Playing format: AudioStreamBasicDescription: 1 ch, 4616 Hz, 'lpcm' (0x00000008) 8-bit unsigned integer
Buffer Byte Size: 16384, Num Packets to Read: 16384
Enter frequency between 250 and 6000, Ctrl-C to stop:- 5781
Playing file: /tmp/sinewave.wav
Playing format: AudioStreamBasicDescription: 1 ch, 46248 Hz, 'lpcm' (0x00000008) 8-bit unsigned integer
Buffer Byte Size: 23124, Num Packets to Read: 23124
Enter frequency between 250 and 6000, Ctrl-C to stop:- 234
Playing file: /tmp/sinewave.wav
Playing format: AudioStreamBasicDescription: 1 ch, 8000 Hz, 'lpcm' (0x00000008) 8-bit unsigned integer
Buffer Byte Size: 16384, Num Packets to Read: 16384
Enter frequency between 250 and 6000, Ctrl-C to stop:- 6001
Playing file: /tmp/sinewave.wav
Playing format: AudioStreamBasicDescription: 1 ch, 8000 Hz, 'lpcm' (0x00000008) 8-bit unsigned integer
Buffer Byte Size: 16384, Num Packets to Read: 16384
Enter frequency between 250 and 6000, Ctrl-C to stop:- ^C
AMIGA:barrywalker~/Desktop/Code/Shell> _
Enjoy finding simple solutuons to often bery difficult problems...
Bazza.