sound in APL
27 posts
• Page 2 of 3 • 1, 2, 3
Re: sound in APL
Could you use audiowrite to convert your existing mathlab files to .wav format ?
-
PGilbert - Posts: 440
- Joined: Sun Dec 13, 2009 8:46 pm
- Location: Montréal, Québec, Canada
Re: sound in APL
I can see that I haven't explained what I want to do clearly. My bad. So let me try again.
Let's say I do this:
z←512⍴(4⍴1),4⍴0
z will contain a representation of 64 cycles of a square wave. If I play these (suitably scaled) through my sound card at a sample rate of 8192 Hz., I'll hear a toot of a 1024 Hz. tone for about 63 milliseconds. I'm going to be computing much more complex sounds, but the problem remains the same: how to play the samples. It appears that in Dyalog the best approach is to embed the samples in some standard file format and then play the file. From my point of view, .wav is the best choice (no compression). But it's not clear to me how to make a file that contains both characters and ints of different sizes (the sizes are really important because the .wav interpreter identifies the various parts of a file by byte counts in the three section headers in the file).
Let's say I do this:
z←512⍴(4⍴1),4⍴0
z will contain a representation of 64 cycles of a square wave. If I play these (suitably scaled) through my sound card at a sample rate of 8192 Hz., I'll hear a toot of a 1024 Hz. tone for about 63 milliseconds. I'm going to be computing much more complex sounds, but the problem remains the same: how to play the samples. It appears that in Dyalog the best approach is to embed the samples in some standard file format and then play the file. From my point of view, .wav is the best choice (no compression). But it's not clear to me how to make a file that contains both characters and ints of different sizes (the sizes are really important because the .wav interpreter identifies the various parts of a file by byte counts in the three section headers in the file).
- Stu
- Posts: 97
- Joined: Thu Dec 31, 2015 1:30 am
Re: sound in APL
Stu, I believe the set of "native file functions" should make it possible to write exactly what you want to a file:
Does that help? Also take a look at ⎕DR, which will allow you to perform type conversions explicitly without also writing or reading them.
- Code: Select all
tn←'c:\temp\sounds.wav' ⎕NCREATE 0 ⍝ OK, not really a WAV file
1234 ⎕NAPPEND tn 163 ⍝ write 1234 as a 16-bit integer(3)
'A' ⎕NAPPEND tn 80 ⍝ write A as an 8-bit unicode char (0)
⎕UCS ⎕NREAD tn 80 3 0 ⍝ read 3 unicode chars starting at position 0
210 4 65
256⊥⌽210 4 ⍝ litte-endian 1234
1234
Does that help? Also take a look at ⎕DR, which will allow you to perform type conversions explicitly without also writing or reading them.
-
Morten|Dyalog - Posts: 458
- Joined: Tue Sep 09, 2008 3:52 pm
Re: sound in APL
This looks very promising. Thanks! I think I'll have to make the entire file from individual bytes with the 83 conversion. Just a few of the bytes will have to be hand coded because ⎕AV doesn't exactly match up with ASCII.
- Stu
- Posts: 97
- Joined: Thu Dec 31, 2015 1:30 am
Re: sound in APL
I wrote some code to create WAV files for PocketAPL under Dyalog (Classic not Unicode) some years back.
The MakeWave function created a WAV file of a single frequency, just one cycle long.
The functions WriteChar WriteLong WriteShort WriteSmall ReWriteLong MakeFile
You should not need "PoW" which selected either PocketApl or Windows using APLVersion.
PlaySound used a ⎕NA call. This also used PoW to select the correct DLL library (Winmm for Windows, coredll for PocketAPL0).
Since I wrote this, I've changed to using sin waves (rather than square) and also created a few cords.
Be aware, when creating a cord WAV file with a single "cycle", the fundamental frequencies of the 3(or more) notes making up the cord, have to be "well tempered", so they all start and finish at exactly the same time. Using an "equal temperament" scale (see below) will sound dreadful.
Good luck
The MakeWave function created a WAV file of a single frequency, just one cycle long.
- Code: Select all
name MakeWave freq;file;tie;sizpos;datpos;cycle;val;size;freq;rate;bits;chans;chan;max;count;bin;data
⍝ Make 1 cycle of wave sound
+file←('\My Documents\wave'PoW'c:\wave'),name,'.wav'
tie←MakeFile file
chans←1 ⍝ Mono=1/Stero=2
rate←44100 ⍝ low=8000/high=44100 sample rate in Bytes per sec
bits←16 ⍝ size (in bits) of a sample
size←rate×(bits÷8)×chans ⍝ size (in bytes) of 1 sec of sound
⍝ max←{⍵=8:255 ⋄ 65536}bits ⍝ maximum (integer) value of a sample
max←{⍵=8:¯1+2*⍵ ⋄ ¯1+2*⍵-1}bits ⍝ maximum (integer) value of a sample
⍝ Write the ".WAV" header
sizpos←tie WriteChar'RIFF' ⍝ RIFF format tag
tie WriteLong 0 ⍝ Size to end of file from here, fill in later
tie WriteChar'WAVE' ⍝ .WAV tag
tie WriteChar'fmt ' ⍝ Format tag
tie WriteLong 16 ⍝ Size of Format
tie WriteShort 1 ⍝ Format tag WAVE_FMT_PCM
tie WriteShort chans ⍝ number of channels
tie WriteLong rate ⍝ Number of samples a second
tie WriteLong size ⍝ Number of Bytes per sec
tie WriteShort 1 ⍝ Block Align ?
tie WriteShort bits ⍝ Number of bits in each sample
datpos←tie WriteChar'data' ⍝ Data Block tag
tie WriteLong 0 ⍝ Size of data the following data, fill in later
count←0
⍝ Calculate the data, use square, rather than sin wave
data←chans/⌊0.5+(size÷chans){
{
⍵{
(max÷⍺)×⍵
}{
⍵,⌽⍵
}¯1+⍳⌊0.5+⍵
}(⍺÷2×⍵)
}freq
data←chans/⌊0.5+(size÷chans){{⍵/¯32768 32767}(⌊⍺÷2×⍵)}freq
⍝ Now write the data to file
:For cycle :In 1 ⍝ Number of complete cycles to write to file
:If bits=16
tie WriteShort data
count+←2×⍴data
:Else
tie WriteSmall data
count+←⍴data
:End
:End
⍝ update the header with the correct sizes
tie sizpos ReWriteLong count+28
tie datpos ReWriteLong count
⎕NUNTIE tie
{}PlaySound file ⍝ Play untill next sound or PlayNoSound
{}⎕DL 0.125
The functions WriteChar WriteLong WriteShort WriteSmall ReWriteLong MakeFile
- Code: Select all
{r}←tie WriteChar data
r←data ⎕NAPPEND tie 82
- Code: Select all
{r}←tie WriteLong data
r←data ⎕NAPPEND tie 323
- Code: Select all
{r}←tie WriteShort data;max
r←data ⎕NAPPEND tie 163
- Code: Select all
{r}←tie WriteSmall data
r←data ⎕NAPPEND tie 83
- Code: Select all
{r}←tiepos ReWriteLong data;tie;pos
tie pos←tiepos
r←data ⎕NREPLACE tie pos 323
- Code: Select all
tie←MakeFile file
:Trap 0
file ⎕NERASE file ⎕NTIE 0
:End
tie←file ⎕NCREATE 0
You should not need "PoW" which selected either PocketApl or Windows using APLVersion.
PlaySound used a ⎕NA call. This also used PoW to select the correct DLL library (Winmm for Windows, coredll for PocketAPL0).
- Code: Select all
PlaySound←{
ps←{}
bin←'ps'⎕NA{
⍵=1:'Winmm|PlaySound <0t i U'
⍵=2:'coredll|PlaySoundW <0t i U'
}2 PoW 1
ps ⍵ 0 9
⍝ 9=asynchronously+loop the sound until next sndPlaySound
⍝BOOL WINAPI PlaySound(
⍝LPCSTR pszSound, C:\Program Files\NetMeeting\blip.wav
⍝HMODULE hmod,
⍝DWORD fdwSound );
⍝ * flag values for fuSound and fdwSound arguments on [snd]PlaySound
⍝ */
⍝#define SND_SYNC 0x0000 /* play synchronously (default) */
⍝#define SND_ASYNC 0x0001 /* play asynchronously */
⍝#define SND_NODEFAULT 0x0002 /* silence (!default) if sound not found */
⍝#define SND_MEMORY 0x0004 /* pszSound points to a memory file */
⍝#define SND_LOOP 0x0008 /* loop the sound until next sndPlaySound */
⍝#define SND_NOSTOP 0x0010 /* don't stop any currently playing sound */
}
Since I wrote this, I've changed to using sin waves (rather than square) and also created a few cords.
Be aware, when creating a cord WAV file with a single "cycle", the fundamental frequencies of the 3(or more) notes making up the cord, have to be "well tempered", so they all start and finish at exactly the same time. Using an "equal temperament" scale (see below) will sound dreadful.
- Code: Select all
scale←{ ⍝ create 4 octaves of C scales
scal←{⍵,⍵××\11⍴*(-/⍟(⍵+⍵)⍵)÷12}
{(0.5×⍵),⍵,2×⍵,2×⍵,2×⊃⍵
}scal 261.626
⍝261.626 277.183 293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164 493.883
}
Good luck
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
-
ray - Posts: 237
- Joined: Wed Feb 24, 2010 12:24 am
- Location: Blackwater, Camberley. UK
Re: sound in APL
Thanks Ray! A lot of useful info there.
-Stu
-Stu
- Stu
- Posts: 97
- Joined: Thu Dec 31, 2015 1:30 am
Re: sound in APL
Building on Ray's contribution and looking at the Matlab sound function I've put together a couple of functions that should give you what you need.
https://github.com/theaplroom/apl-sound-wave
It might be worthwhile adding another cover function to combine the PlaySound and Wave functions, but it should be enough to get you started.
https://github.com/theaplroom/apl-sound-wave
It might be worthwhile adding another cover function to combine the PlaySound and Wave functions, but it should be enough to get you started.
- gil
- Posts: 72
- Joined: Mon Feb 15, 2010 12:42 am
Re: sound in APL
Thanks Gil! This looks very nice. I was able to get a "wavwrite" of my own running, but it's an ugly kludge compared to yours. Since mine doesn't use the Windows sound API, it doesn't have all the features yours does. My next step it to look into the Dyalog manual to learn how to use namespaces (APL didn't have them when I learned APL in the late 1970's and used it for a year or two).
- Stu
- Posts: 97
- Joined: Thu Dec 31, 2015 1:30 am
Re: sound in APL
Since this is the "no question is silly" group I'll risk a few questions about your Sound namespace. I have your namespace on my desktop along with my own audio workspace. How do I access your Wave function in my workspace? I've looked in "Mastering Dyalog APL" about namespaces, but I still can't figure out how to do it.
Something in Dyalog prevents me from copying your functions into my workspace. Whenever I try to copy one, the closing curly brace is red. Cut-and-paste from a namespace to some other place is apparently illegal. What's up with that?
Something in Dyalog prevents me from copying your functions into my workspace. Whenever I try to copy one, the closing curly brace is red. Cut-and-paste from a namespace to some other place is apparently illegal. What's up with that?
- Stu
- Posts: 97
- Joined: Thu Dec 31, 2015 1:30 am
Re: sound in APL
Hi Stu
Namespaces are containers for code similar to folders in the file system. The scripted version of namesapces (like my file in github) can be loaded into your workspace by executing the user command:
Red curly braces indicate a syntax error. You could get that if you missed copying the entire function (missing the opening brace).
PS. I made a second commit last night as I noticed one of the functions was missing 2 lines. Try downloading a fresh copy and run the above command.
Namespaces are containers for code similar to folders in the file system. The scripted version of namesapces (like my file in github) can be loaded into your workspace by executing the user command:
]load C:\path\to\file\Sound.dyalog
Red curly braces indicate a syntax error. You could get that if you missed copying the entire function (missing the opening brace).
PS. I made a second commit last night as I noticed one of the functions was missing 2 lines. Try downloading a fresh copy and run the above command.
- gil
- Posts: 72
- Joined: Mon Feb 15, 2010 12:42 am
27 posts
• Page 2 of 3 • 1, 2, 3
Who is online
Users browsing this forum: No registered users and 1 guest
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group