Jump to content
IGNORED

TROGBlog - wav2atari.pl


RSS Bot

Recommended Posts

I have a habit of checking out the 2600 programming forums every week or so, and two weeks ago I started commenting on the topic Advanced sound techniques: how do they work? My interest in this topic was mostly in sample playback. I've been messing with digital sound samples since 1990, and I was very impressed when I found out a couple years ago that the 2600 was capable of playing back decent quality sound samples. My only exposure to this was the Berzerk Voice-Enhanced, which is a thing of beauty (and a joy forever.)

 

While responding to that topic, I mentioned if I couldn't find a decent program to translate 8-bit PCM wav files into 4-bit Atari format, I'd try writing one myself. Well, tonight after I put the kids to bed, I had a couple beers and set to work. An hour later, I had wav2atari.pl:

 

use Getopt::Long;

$result = GetOptions ("wav=s", \$wavfile, "outfile=s", \$outfile, "help", \&usage);

sub usage {
print "\n$0 -wav <wav_file> -outfile <out_file> -help

This program reads in the specified wav file.  The sound data is translated
into a 4-bit Atari format that is dasm readible.  Two samples are encoded
into each byte of output.  A comment is placed every 256 bytes to denote
a new page in Atari ROM.

Note that the first of the two samples goes into the lower nibble.  This
works optimally in Atari code.  The first sample can be written directly to
AUDV0, since the register will strip off the higher 4 bits automatically.
Then the second sample can be written to AUDV0 after 4 LSRs.  This prevents
the need for temp variables and saves precious cycles during playback.

The asm data is written to the specified -outfile.  RIFF PCM header
information is written to STDOUT.

Currently only 8-bit PCM wav files are supported.\n";

exit;
}

#$wavfile = shift;

if ($wavfile eq "") {
die "ERROR: Must provide input wave file.\n";
}

open (WAV, $wavfile)
or die "Could not open wavfile '$wavfile'.\n";

# Read ChunkID
read (WAV, $data, 4);
if ($data ne "RIFF") {
die "ERROR: This doesn't appear to be a RIFF PCM WAV file.\n";
}
print "      ChunkID = $data\n";

# Read ChunkSize
read (WAV, $data, 4);
$data = unpack ("V1", $data);
print "    ChunkSize = $data\n";

# Read Format
read (WAV, $data, 4);
print "       Format = $data\n";
if ($data ne "WAVE") {
die "ERROR: This is a RIFF file, but it doesn't appear to be a WAVE file.\n";
}

# Read Subchunk1ID
read (WAV, $data, 4);
print "  Subchunk1ID = $data\n";

# Read Subchunk1Size
read (WAV, $data, 4);
$data = unpack ("V1", $data);
print "Subchunk1Size = $data\n";

# Read AudioFormat
read (WAV, $data, 2);
$data = unpack ("v1", $data);
print "  AudioFormat = $data\n";

# Read NumChannels
read (WAV, $data, 2);
$data = unpack ("v1", $data);
print "  NumChannels = $data\n";

# Read SampleRate
read (WAV, $data, 4);
$data = unpack ("V1", $data);
print "   SampleRate = $data\n";

# Read ByteRate
read (WAV, $data, 4);
$data = unpack ("V1", $data);
print "     ByteRate = $data\n";

# Read BlockAlign
read (WAV, $data, 2);
$data = unpack ("v1", $data);
print "   BlockAlign = $data\n";

# Read BitsPerSample
read (WAV, $data, 2);
$data = unpack ("v1", $data);
print "BitsPerSample = $data\n";

# Read Subchunk2ID
read (WAV, $data, 4);
print "  Subchunk2ID = $data\n";

# Read Subchunk2Size
read (WAV, $data, 4);
$data = unpack ("V1", $data);
print "Subchunk2Size = $data\n";

# Read in all the data.

$data_byte_count = 0;
$page_count = 0;
$output = "";
while (read (WAV, $data, 2)) {
@data = unpack ("C2", $data);

if ($data_byte_count % 512 == 0) {
	$output .= "; Page $page_count\n";
	$page_count++;
}

# If there is an odd number of bytes in the sample, drop the last byte.
if ($data[1] eq "") {
	print "Warning: last byte of sound data was ignored because this file\n";
	print "contains an odd number of sound bytes.\n";
	$data_byte_count++;
	last;
}

# Note, the first of the two bytes goes into the lower nibble.  This works
# optimally in Atari code.  The first sample can be written directly to
# AUDV0, since the register will strip off the higher 4 bits automatically.
# Then the second sample can be written to AUDV0 after 4 LSRs.  This prevents
# the need for temp variables and saves precious cycles during playback.

#strip off the lower 4 bits.
$lownibble = $data[0] >> 4;

#shift 4 bits to the right, effectively stripping off the lower 4 bits.
$highnibble = $data[1] & 240;

$condensedbyte = $highnibble + $lownibble;
$output .= sprintf ("	.byte #%%%08b\n", $condensedbyte);

$data_byte_count += 2;
}

print "$data_byte_count bytes of sound data processed.\n";

close WAV;

open (OUTPUT, ">$outfile");
print OUTPUT $output;
close OUTPUT;

I had expected this program wouldn't be too difficult to write. The guts of the program is only about 10 lines. The rest is just spitting out the RIFF header info.

 

For those who aren't familiar with a .pl file, it's a perl script. You'll have to have a perl interpreter installed on your system to use the script. But it should be easy to translate this program into your scripting language of choice if you don't happen to use perl.

 

 

My quest to get my own samples working on the Atari started on Google. I quickly found a nice spec for the PCM wave format here. Next I grabbed a small random wav from Google to use as my test subject:

 

music.gif

hello.wav ( 4.59K )

Number of downloads: 1

 

I'm pretty sure this particular hello is Graham Chapman from Monty Python and the Holy Grail. All the better.

 

After I fed this wav file through wav2atari.pl, I made some modifications to my unsound wave generation demo, and then some more tweaking, and suddenly, it worked! Hearing this sample play back correctly in a 2600 emulator is one of the most satisfying moments I've ever had programming for the 2600. :)

 

The atari binary still needs work. I just threw this together, so the sample playback rates are not perfectly balanced (the delay between the low nibble sample and the high nibble sample should be exactly the same, but they're not), yet it still sounds pretty good.

 

If I get the time and energy, I'll enhance wav2atari to work on 16-bit samples, and add a downsampling option so you can specify the output sample rate. I also need to clean up the playback asm so the delays are balanced.

 

The zip file I'm including below contains the wav2atari.pl script, the HELLO.BIN Atari binary, the hello.asm dasm assembly file, and the original hello.wav file for comparison. Enjoy!

 

zip.gif

HelloWorld.zip ( 11K )

Number of downloads: 0

 

 

http://www.atariage.com/forums/index.php?a...;showentry=5907

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...