AGMSRecordSound

AGMSRecordSound is a Modula-2 program by Alexander G. M. Smith which records sound samples to disk, using a standard parallel port audio digitizer. AGMSRecordSoundPS3 is a modified version that works with version 3.0+ PerfectSound hardware.

To get you started, try this command:

AGMSRecordSound ram:test verbose

Type a control-C to stop it. You can play the resulting file with AGMSPlaySound or some other sound player.

Propoganda

Since AGMSRecordSound doesn't need to fit the whole sample into one contiguous memory block, you can record samples longer than your memory size (up to 2 gigabytes). It also multi-tasks so you can see the screen and do other things while recording, unlike all other sound digitizer programs I know of.

Anti-propoganda

The downside of this is crummy audio quality. Other digitizers take over the computer while recording since that is the best way to get better quality. The trouble comes from code that temporarily disables interrupts, making AGMSRecordSound's interrupt routine miss a sound sample. This happens all time time - whenever memory is allocated or deallocated, interrupts are disabled to prevent other programs from interfering. Hopefully Commodore will put in some DMA circuits for digitizing so that we can get good quality and multitasking.

Requirements

AGMSRecordSound requires sound sampler hardware plugged into the parallel port. I've tested it with AMAS (records from the right channel) and it should work with most other parallel port digitizers (try left if right doesn't work). If you have SunRize Industries' PerfectSound 3 digitizer then you have to use a different version of this program: AGMSPlaySoundPS3. You also need to have the arp.library file (version 39 or 1.3) in your LIBS: directory. If you have ARexx installed, AGMSRecordSound will take advantage of it. Other than that, it should work on all Amigas.

How It Works

An interrupt routine is set up for audio channel 1 (right side) that samples the parallel port, copies the data to the audio register and copies it to a buffer in memory. Every time audio channel 1 needs a new sound sample, this interrupt routine is called. When a buffer becomes full, it moves to the next buffer and signals the main program. If there are no empty buffers to be filled, the interrupt routine will slow down the audio channel to a lower sampling rate (around 440 Hz) so that the processor will have more CPU time for running tasks (less used by the interrupt code). You can still hear the sounds but they won't be stored in the buffer (not recorded in other words) and they will sound strange (like a dog growling under water) due to the lower sampling rate. When an empty buffer becomes available, it will resume filling at normal speed.

The other half of AGMSRecordSound is a process that dumps filled buffers to a disk file. If it is faster at emptying buffers than the interrupt routine is at filling them, it will go to sleep and wait for a signal: control-C (a signal from the user to stop recording) and control-F (a signal from the interrupt routine that another buffer is full). In the PerfectSound version, it also responds to control-E (steps up the volume control). After dumping each buffer, it can optionally test for a couple of stop conditions: reaching the maximum number of bytes or the sound being quiet for a long enough time.

Sound Quality

The problems with disabled interrupts cause pops and similar noises - great if you are trying to simulate an old scratchy record (or to record one), but otherwise annoying. The trick for getting "good" sound quality is to set the sampling rate to minimize this problem.

A really low sampling rate means that the disabled interrupt won't last long enough to cause trouble. After interrupts are re-enabled, the pending audio interrupt will get through and the sample will only be delayed in time for a short while. Samples after the delayed one will be back on schedule. Unfortunately, most people don't like to record at 1kHz :-). However, if you have a faster computer (I only have an A2000) then the disabled times will be shorter and sound quality should go up.

A really high sampling rate will suck up so much CPU time that only the interrupt routine will be running; every time it finishes sampling, another interrupt comes in. This is actually quite useful (more later). You can tell that this is happening by the lack of mouse pointer movement when you move the mouse. However, as soon as all the buffers are full, the interrupt routine will go into idle mode. This frees up CPU cycles for running other tasks - like the mouse pointer movement and buffer saving. As soon as one buffer has been saved, the interrupt routine will pick up speed and things will be frozen.

At high sampling rates, no other task is running and disabling interrupts. This means high quality sound, almost as good as those dedicated non-multitasking sampler programs. The catch is that nothing is recorded while the buffer is being dumped to disk. So, if you can put up with brief pauses then you can use this mode.

Also, you can use AGMSRecordSound as an ordinary sound digitizer. Just set the buffer size to fill up your whole memory (many smaller buffers are preferable since the interrupt routine can fill all but the one buffer being emptied - try buffers 20 size 100000 if you want to fill up 2 meg of memory). Then set the sampling rate to one that uses all the CPU time for sampling (12kHz is good on my A2000, you will need larger rates on faster computers).

At ridiculously high sampling rates, the interrupt routine will be running flat out at a speed less than the one you requested. This will result in a sample that is higher pitched than reality when you play it back.

Embedded IFF Information

The output file is an IFF file. You have lots of command line options available for specifying optional information (like sample name, author etc). Unfortunately some other sound sample processing programs can't handle the extra info (but AGMSPlaySound can!). If you find that you want to type in more information than will fit on a command line, put the long command line into a script file and execute it.

Help

Most of the arguments to the program are obvious if you know audio terminology and computer terminology. Anyways, you really don't have to specify any arguments except the name of the file to be created. For on-line help, just type a ? as the argument to get the standard ARP / AmigaDOS command template. A second ? typed at the template prompt will print the program credits. The Verbose option also explains in more detail what the current settings are. They are intuitively obvious (well, to me :-), but just in case you aren't intuitive about audio stuff, I'll describe the parameters in detail near the end of this message.

Stolen Channels

This program won't let other programs steal its sound channel (channel 1 to be specific). It allocates it with maximum priority and thus hangs on to it. If you are using AGMSPlaySound at the same time as you are recording, AGMSPlaySound will be bumped off channel 1 and will reappear on whatever other channel is free. If someone else has channel 1 with the highest priority then AGMSRecordSound won't try recording.

Error Handling

The main source of errors is from the file system. In particular, you may encounter a disk full error once in a while :-). When an error occurs, AGMSRecordSound stops whatever it is doing and shuts down. It will return a return code of 10 when something goes wrong.

Now, more about those disk full errors. I've set things up so that the file you are recording to is closed as if you had normally ended recording. Since it is an IFF file, this means going back and filling in the size of the sample in previously written data near the beginning of the file. It seems to work when using the old file system (OFS) but doesn't work under the fast file system (FFS). Well, I tried.

Technical Notes

Well, I found out a bit while writing this program. Ok, two bits, make that three or four after I figured out the PS3 hardware :-). For one thing, I found out how to use a digitizer: set CIAA port B to be all inputs (the parallel port). Set CIAB port A pins POUT and SEL to be outputs. The sampler spews out bytes to the parallel port with no handshaking, at some rate that I assume is pretty fast. Some digitizers use a high level on SEL to connect the right audio input to the sampler and a high level on POUT to connect the left channel. AMAS just seems to use the POUT bit to select left or right and seems to use right instead of left. Whatever. Once you have the desired channel, you can get a sample byte by reading the parallel port byte. Subtract $80 from it to make it into a signed number and store it away. Allow a small amount of time between switching from left to right (or vice versa) to let the sampler update its value (the time for a few instructions should be enough).

The PerfectSound 3.0+ hardware is a different story. The sample byte is split between the parallel port (CIAA port B) and the miscellaneous bits port (CIAB port A). The low 6 bits of parallel data (PB5-PB0 in CIAA) are actually the high six bits of the sample (shift them left by two). The low two bits of the sample are in the printer POUT (paper out) and BUSY signals (PA1-PA0 in CIAB). As before, SEL (PA2 in CIAB) controls the left / right (zero is left). So, what do PB6 and PB7 in CIAA do? A lot! The PerfectSound digitizer has a latched output, PB6 triggers the latch. Set PB6 to zero to latch a value, read the sample, and set PB6 back to one to start digitizing the next sample (I assume that's what it's doing). PB7 is the gain control. Normally you run the hardware with PB7 set to one. If you toggle PB7 to zero and back, the volume control will be stepped up or down one notch of 16 levels. SEL controls the volume direction (as well as left/right), zero for decreasing the volume. The volume gain control wraps around from minimum to maximum and as far as I could tell, there isn't any way of telling what the current gain setting is or of setting it to minimum or maximum.

I experimented a bit with ways of generating interrupts before I clued in that no interrupts happen while interrupts are disabled. CIA timers running continously are good. Audio channels themselves are also good for making a periodic interrupt (and at exactly the same speed as playback too). I even tried using an audio channel to generate an interrupt slightly before the audio channel I was using for timing would signal the next time period. The early interrupt routine would then busy wait for the timing channel interrupt. The "slightly" grew to over 800 CPU clock cycles before I got slightly improved sound (hey - a way of determining how long those disabled times are), slightly improved at a very slow sampling rate that made it useless.

Feedback

If you have any feature requests or find any bugs, please send me a message. I'm on several of the Ottawa BBX's (a BBS written by SteveX) and my commercial info service names are listed in the program's second help message (agmsmith@BIX.com and 71330.3173@CompuServe.com).

Distribution

AGMSRecordSound is FreeWare. Copyright (c) 1993 by Alexander G. M. Smith. That means that you can use it freely, can't blame me for anything that goes wrong (there are probably a few bugs left), and you shouldn't expect more from it than you paid for it. Also, don't blame me if your hard drive fills up and then has problems with invalid directory structures - it happens to me too.

File/A

Names the file where the sample will be stored. Any existing file by this name will be erased. A required keyword. You can specify NIL: if you just want to monitor your digitizer without recording the sound to a file. Only works in versions of AmigaDOS that support NIL:.

Verbose/S

When this command switch is used, lots of interesting messages will be displayed. All the parameter settings will be shown. During recording you can see what buffers are being dumped.

Buffers/K

This parameter specifies the number of buffers (any old ram is used) to use for recording the sound. You need at least 2. While the system is recording one buffer, the others can be emptied to disk. Try the verbose command switch to watch the buffers being emptied and to see how changing the number of buffers affects performance. Gee, I sure like these reuseable documentation paragraphs - I just changed "play" to "record" :-)

BufferSize/K

This parameter sets the size of each sound buffer. The default is 100000 bytes, the maximum is about 2000000000 bytes :-). As mentioned elsewhere, AGMSRecordSound doesn't need to use any chip ram at all. Buffers use general purpose ram. For best performance, use large buffers. That is because DOS can write a large chunk of data faster than several small chunks (less overhead).

Hz/K

This parameter controls the record rate. It is in units of samples per second, or bytes per second since each sample is one byte long (compact disks have 2 byte samples and thus sound better). The default is 7781 hz, less for the PerfectSound version due to extra overhead in reading each sample. The highest rate on my A2000 that lets you record and simultaneously save to disk (no gaps) is about 8500 hz. A speed of 12000 hz is good for better quality sound with small gaps between buffers. See the discussion on sound quality about picking values for hz.

The Hz setting is internally translated into a code value for the hardware. Since the hardware doesn't have all that many code values, only a few frequencies are actually available. A frequency near the one you specified will be picked. Note that this is half the playback code value since playback plays words (pairs of bytes) while we only record a byte at a time.

StopSize/K

This parameter specifies the maximum size of the sound sample file. The default is two billion. When this many bytes of data have been written, the sampling process will be stopped. Because the interrupt routine may have filled up a few buffers before this much data has been written, you will get a bit more than the stop size in your file.

StopQuiet/S

This switch triggers a neat feature requested by Hans Kerkhof who wanted something to record people calling in to a TV show. If you specify StopQuiet then the sampling will also stop when the input is quiet for a long enough period of time. This could also be useful for those of you making telephone answering machines. The next few command line arguments control the definition of "quiet" and how much quiet is needed.

QuietTime/K

This parameter lets you specify the integer number of seconds of quiet that will make the program stop recording. The number is approximate and will be converted into a count of quiet sound sample buffers (see BufferSize) that would cover roughly the time you request. The minimum time possible is the time it takes to record one sound sample buffer. If you specify the Verbose option, you can see the quiet time shown as the number of quiet buffers and the amount of real time that corresponds to. The default value is zero (that becomes the time it takes to record one buffer). Note that QuietTime is spelt with two "t"s in the middle, I often misspell it and get the error "Bad positional argument."

QuietVolume/K

If you have StopQuiet turned on, then each buffer will be examined after it has been dumped to determine if it is "quiet". A number of samples (adding up to 32 per second) will be picked out from the buffer and averaged together (or rather, the absolute value of each picked out sample will be averaged). The resulting value, from 0 to 127, is a statistical estimate volume level of that buffer. If you turn on the verbose option, it will show the buffer volume estimates. If the volume is less than or equal to the QuietVolume you specify then that buffer counts as being "quiet". If you get a certain number (determined by QuietTime) of quiet buffers in a row, then the program will stop.

Name/K

This lets you specify the name of the song or whatever you have recorded. If it is more than one word, put it in double quotes.

Copyright/K

This is for the IFF copyright notice inside your sound sample. Specify something like "1991, Alexander G. M. Smith".

Author/K

The author of this sample. If it is music then that is relatively obvious. I don't know who is the author of the sound of a toilet flushing, maybe the toilet manufacturer? Don't specify it if you don't want an author.

Anno=Annotation/...

An endless list of annotation. You can use the short form of the keyword (Anno) or the long form (Annotation). The values are strings (as many as you want) of annotation text. It can be whatever you want, usually something that describes the sample: anno "This is my first hour long sound sample" "The sound of the dripping tap was created by using the kitchen sink." "Use at your own risk."

ARexx: StopRecording

If you have ARexx installed, AGMSRecordSound will open an ARexx port called "AGMSRecordSound" (note the case of the letters) and respond to commands. Currently, the only command is "StopRecording" which will stop the recording, much like a Control-C does. Have a look at the Test.rexx script included with the archive to see how to use AGMSRecordSound from ARexx. You can thank Al Villarica for requesting this feature.

Control-C Etc.

Control-C will abort the program as soon as possible. This can take a while if it is busy dumping a buffer.

Control-E will step up the volume on the PerfectSound hardware, if you are using AGMSRecordSoundPS3 (does nothing otherwise). Don't hit the key too fast, when AGMSRecordSoundPS3 is running the rest of the operating system is slowed down and can't process your signals fast enough. In fact, it's so slow that you can overflow something (probably the supervisor stack) by typing a lot of Control-CDEF's, even in another program's window. The result is a visit from the guru (crash #3 usually).

Control-F is used by the interrupt routine to tell the main program that there is another full buffer. You can use it to if you want to wake up a poor little sleepy program (doesn't do any harm, unless you type it too quickly :-).

- Alex