Working with Sound Output using the AICA SPU
- PH3NOM
- DC Developer
- Posts: 576
- https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
- Joined: Fri Jun 18, 2010 9:29 pm
- Has thanked: 0
- Been thanked: 5 times
Working with Sound Output using the AICA SPU
Whats up guys?
Out of personal interest, I have been learning about multi-media applications, and how to use them on Dreamcast.
I have ported liba52 and libfaad to DC, and i would like to make a working decoder. Their sample decoder apps are working on DC, I just need to make a audio output driver that works for Dreamcast.
At first I was using SDL_Mixer to play wave streams but that is not the best way to go on DC, as I want things to be as optimized for the hardware as possible.
So I am turning to internal KOS sound functions, which have little documentation or examples to study from.
Surprisingly, the function snd_sfx_load(const char *fn) did not work for me at first; it would return a negative value ( or incredibly large ) for the file size and fail on malloc().
I had to obtain the file size manually to get things working.
But it seems there is a limitation in the snd_sfx_load() function I am not aware of; how many bytes can this function handle? It seems to only play the first ~1sec of the audio file then stop...
Am I the only one having this problem? Or is there another function besides snd_sfx_load() that I should be working with?
Any comments will be appreciated!
Thanks in advance.
Out of personal interest, I have been learning about multi-media applications, and how to use them on Dreamcast.
I have ported liba52 and libfaad to DC, and i would like to make a working decoder. Their sample decoder apps are working on DC, I just need to make a audio output driver that works for Dreamcast.
At first I was using SDL_Mixer to play wave streams but that is not the best way to go on DC, as I want things to be as optimized for the hardware as possible.
So I am turning to internal KOS sound functions, which have little documentation or examples to study from.
Surprisingly, the function snd_sfx_load(const char *fn) did not work for me at first; it would return a negative value ( or incredibly large ) for the file size and fail on malloc().
I had to obtain the file size manually to get things working.
But it seems there is a limitation in the snd_sfx_load() function I am not aware of; how many bytes can this function handle? It seems to only play the first ~1sec of the audio file then stop...
Am I the only one having this problem? Or is there another function besides snd_sfx_load() that I should be working with?
Any comments will be appreciated!
Thanks in advance.
- BlueCrab
- The Crabby Overlord
- Posts: 5663
- Joined: Mon May 27, 2002 11:31 am
- Location: Sailing the Skies of Arcadia
- Has thanked: 9 times
- Been thanked: 69 times
- Contact:
Re: Working with Sound Output using the AICA SPU
If you want to play WAV files, use snd_sfx_load. Otherwise, you'll want to look at the snd_stream stuff instead. You might want to take a look at the Ogg Vorbis playing libraries to see how it works.
-
- DCEmu Freak
- Posts: 81
- Joined: Fri Jul 27, 2007 2:23 am
- Has thanked: 2 times
- Been thanked: 4 times
Re: Working with Sound Output using the AICA SPU
I'm having the same exact problem with the audio only playing the first second or two and then stopping. It happens for MP3, OGG and WAV. I've tried changing the bitrate and even tried mono / stereo, but it does the same thing. I've also had the audio speed up / change pitch.
- BlueCrab
- The Crabby Overlord
- Posts: 5663
- Joined: Mon May 27, 2002 11:31 am
- Location: Sailing the Skies of Arcadia
- Has thanked: 9 times
- Been thanked: 69 times
- Contact:
Re: Working with Sound Output using the AICA SPU
That's certainly strange... Might be something wrong with your toolchain or something, maybe?
-
- DC Developer
- Posts: 9951
- Joined: Sun Dec 30, 2001 9:02 am
- Has thanked: 0
- Been thanked: 1 time
Re: Working with Sound Output using the AICA SPU
PH3NOM - As far as I remember, the snd_sfx stuff in KOS is pretty basic.
The .wav loader is primitive, and it's quite possible that it'd break on a perfectly valid .wav file. Specifically, it doesn't use a proper RIFF parser, so it only works if the chunks in the file happen to be in the right place. It also doesn't do much in the way of error checking, so it'll probably break unpredictably in that case.
That could have been your problem.
Also, it can only read .wav files. Obviously.
As for the cut-off sounds... If I remember correctly, the size of a sound sample is limited to 64k samples, in hardware. At 44KHz, that'd be around one and a half seconds. I can't see anything in the snd_sfx system that'd be able to compensate for that (buffer chaining, or whatever), so that might be your problem.
Dreamcast â„¢ - Were you using the stream stuff (snd_stream_*), or the sound effects stuff (snd_sfx_*)? The snd_stream stuff doesn't have any length limit, since it's just playing samples as they're generated by the main CPU.
You do have to keep feeding the buffers though, probably by using snd_stream_set_callback to set up a callback to generate some more samples.
The .wav loader is primitive, and it's quite possible that it'd break on a perfectly valid .wav file. Specifically, it doesn't use a proper RIFF parser, so it only works if the chunks in the file happen to be in the right place. It also doesn't do much in the way of error checking, so it'll probably break unpredictably in that case.
That could have been your problem.
Also, it can only read .wav files. Obviously.
As for the cut-off sounds... If I remember correctly, the size of a sound sample is limited to 64k samples, in hardware. At 44KHz, that'd be around one and a half seconds. I can't see anything in the snd_sfx system that'd be able to compensate for that (buffer chaining, or whatever), so that might be your problem.
Dreamcast â„¢ - Were you using the stream stuff (snd_stream_*), or the sound effects stuff (snd_sfx_*)? The snd_stream stuff doesn't have any length limit, since it's just playing samples as they're generated by the main CPU.
You do have to keep feeding the buffers though, probably by using snd_stream_set_callback to set up a callback to generate some more samples.
- BlueCrab
- The Crabby Overlord
- Posts: 5663
- Joined: Mon May 27, 2002 11:31 am
- Location: Sailing the Skies of Arcadia
- Has thanked: 9 times
- Been thanked: 69 times
- Contact:
Re: Working with Sound Output using the AICA SPU
In addition to setting up the callback, note that the snd_stream stuff doesn't poll automatically to call that callback. You need to periodically call snd_stream_poll on the stream otherwise you'll never have any more data fed in. Its probably easiest to set up a thread to do this or something (that's how libtremor and liboggvorbisplay do it).
-
- DCEmu Freak
- Posts: 81
- Joined: Fri Jul 27, 2007 2:23 am
- Has thanked: 2 times
- Been thanked: 4 times
Re: Working with Sound Output using the AICA SPU
This is the function I created for playback:
Each sound is played only after a button is pressed on the controller (there's a catch to only send on a button down event which resets on a button up event, so sending too many requests isn't the problem).
Code: Select all
int hWave;
void loadPlaySound(uch *path)
{ hWave = snd_sfx_load(path);
snd_sfx_play(hWave, 0xff, 128);
snd_sfx_unload(hWave);
}
- BlueCrab
- The Crabby Overlord
- Posts: 5663
- Joined: Mon May 27, 2002 11:31 am
- Location: Sailing the Skies of Arcadia
- Has thanked: 9 times
- Been thanked: 69 times
- Contact:
Re: Working with Sound Output using the AICA SPU
You're immediately unloading the sound right after calling play. That's not a very good idea, since if you call that twice in quick succession, you're likely to run into problems where you're overwriting the buffer that's being played. You shouldn't call snd_sfx_unload() until the sound is finished playing.
Also, as BA already said, with the snd_sfx_* stuff you're limited in the length of what you can play.
Also, as BA already said, with the snd_sfx_* stuff you're limited in the length of what you can play.
- Bouz
- DCEmu Junior
- Posts: 46
- Joined: Mon May 10, 2010 3:42 pm
- Location: St. Bauzille de Putois (France)
- Has thanked: 0
- Been thanked: 0
Re: Working with Sound Output using the AICA SPU
Hi,
I have been working on an alternative AICA driver for the DC, that allows uploading S3M and WAV files in the AICA memory (2MB) and play them in parallel (multiple S3M files can be played at the same time with crescendo / descresendo, WAV files over S3M files, ...).
I have published a demo on www.dc-france.com before the site died, but nothing since.
I really plan to work on that project in the coming weeks and make an updated version available if someone is still interested in that work.
I have been working on an alternative AICA driver for the DC, that allows uploading S3M and WAV files in the AICA memory (2MB) and play them in parallel (multiple S3M files can be played at the same time with crescendo / descresendo, WAV files over S3M files, ...).
I have published a demo on www.dc-france.com before the site died, but nothing since.
I really plan to work on that project in the coming weeks and make an updated version available if someone is still interested in that work.
- PH3NOM
- DC Developer
- Posts: 576
- Joined: Fri Jun 18, 2010 9:29 pm
- Has thanked: 0
- Been thanked: 5 times
Re: Working with Sound Output using the AICA SPU
@BlackAura and BlueCrab -
Thanks for your responses! You guys are legendary.
Thats confirmed the limit of the wave file size that can be played with snd_sfx_load is 65536 bytes.
Why cant we use the full 2mb of SRAM?
I had a hdd fail on me, and I lost my K:OS development environment, including almost all of the sources I was working on.
I have set up a new install of K:OS and will have to start over, but it wont take long the second time around. I still plan to make something of this.
@Bouz -
Yeah that driver sounds very interesting. You should definitely finish the updated version!
Thanks for your responses! You guys are legendary.
Thats confirmed the limit of the wave file size that can be played with snd_sfx_load is 65536 bytes.
Why cant we use the full 2mb of SRAM?
I had a hdd fail on me, and I lost my K:OS development environment, including almost all of the sources I was working on.
I have set up a new install of K:OS and will have to start over, but it wont take long the second time around. I still plan to make something of this.
@Bouz -
Yeah that driver sounds very interesting. You should definitely finish the updated version!
- BlueCrab
- The Crabby Overlord
- Posts: 5663
- Joined: Mon May 27, 2002 11:31 am
- Location: Sailing the Skies of Arcadia
- Has thanked: 9 times
- Been thanked: 69 times
- Contact:
Re: Working with Sound Output using the AICA SPU
Well, you wouldn't be able to use the full 2MB, even if it weren't for other issues (since the program that the ARM runs to communicate with the SuperH does take up a bit of space). The real reason though is that the snd_sfx stuff isn't meant to be playing anything other than simple sound effects. As BlackAura said, the snd_sfx stuff doesn't do any buffer chaining or anything like that, so you're limited to what you can put in the registers to play directly. In this case, the registers in the AICA simply can't handle a sound that has more than 65534 samples (the loop start and loop end address registers are 16-bit registers -- those two together determine the length of the sound played when not looping the sound, also IIRC, the loop end address register doesn't allow a value of 0xFFFF, thus the limit of 65534 not 65535).PH3NOM wrote:Thats confirmed the limit of the wave file size that can be played with snd_sfx_load is 65536 bytes.
Why cant we use the full 2mb of SRAM?
Also, you're not limited to 65534 bytes, but 65534 samples. The difference is quite important, especially if you're doing ADPCM or 16-bit samples.
- PH3NOM
- DC Developer
- Posts: 576
- Joined: Fri Jun 18, 2010 9:29 pm
- Has thanked: 0
- Been thanked: 5 times
Re: Working with Sound Output using the AICA SPU
I thought this might be useful for some...
I have written an application to stream a wave file using the AICA SPU.
Get the full source here.
http://www.megaupload.com/?d=B4TX72MV
Any feedback appreciated!
I have written an application to stream a wave file using the AICA SPU.
Get the full source here.
http://www.megaupload.com/?d=B4TX72MV
Code: Select all
/*
** SPU_WAVE (C) PH3NOM 2011
** Based on modplug_test
** And the wave parser from snd_sfgmgr
*/
#include <kos.h>
#include "spu_wave.h"
uint32 fd;
uint16 sound_buffer[65536];
snd_stream_hnd_t shnd;
char filename[128];
int wave_stop() {
spu_status = WAVE_STATUS_DONE;
while( spu_status != WAVE_STATUS_NULL )
thd_pass();
printf("Successfully exited SPU_WAVE_STREAM\n");
return spu_status;
}
int wave_restart() {
if( spu_status == WAVE_STATUS_STREAMING ) {
spu_status = WAVE_STATUS_PAUSING;
while( spu_status != WAVE_STATUS_PAUSED )
thd_pass();
fs_seek(fd, 0x32, SEEK_SET);
spu_status = WAVE_STATUS_STREAMING;
}
else
printf("SPU WAVE: Cant Reset if not already streaming\n");
return spu_status;
}
void *wave_callback(snd_stream_hnd_t hnd, int len, int * actual)
{
if (fs_read(fd,sound_buffer,len)!= len )
spu_status = WAVE_STATUS_DONE;
*actual = len;
return sound_buffer;
}
void wave_thread ( ) {
uint32 len, hz;
uint16 chn, bitsize, fmt;
printf("spu_wave_stream: checking status...\n");
while( spu_status != WAVE_STATUS_NULL )
thd_pass();
printf("spu_wave_stream: beginning\n");
while( spu_status != WAVE_STATUS_ERROR && spu_status != WAVE_STATUS_DONE ) {
switch( spu_status ) {
case WAVE_STATUS_NULL:
snd_stream_init();
fd=fs_open(filename, O_RDONLY);
if (!fd) {
dbglog(DBG_WARNING, "spu_wave_stream:: file not opened\n");
spu_status = WAVE_STATUS_ERROR;
break;
}
else
spu_status = WAVE_STATUS_INITIALIZING;
case WAVE_STATUS_INITIALIZING:
/* Check file magic */
hz = 0;
fs_seek(fd, 8, SEEK_SET);
fs_read(fd, &hz, 4);
if (strncmp((char*)&hz, "WAVE", 4)) {
dbglog(DBG_WARNING, "spu_wave_stream:: file is not RIFF WAVE\n");
spu_status = WAVE_STATUS_ERROR;
break;
}
/* Read WAV header info */
fs_seek(fd, 0x14, SEEK_SET);
fs_read(fd, &fmt, 2);
fs_read(fd, &chn, 2);
fs_read(fd, &hz, 4);
fs_seek(fd, 0x22, SEEK_SET);
fs_read(fd, &bitsize, 2);
/* Read WAV data */
fs_seek(fd, 0x32, SEEK_SET);
len = fs_total(fd)-0x32;
int o;
o = 96*640 + 20;
char msg1[4][128];
#ifdef VERBOSE
sprintf( msg1[0], "Channel Config: %s", chn==1 ? "mono" : "stereo" );
sprintf( msg1[1], "Frequency: %dHZ", hz );
sprintf( msg1[2], "Bit-Depth: %d bits/sample", bitsize );
bfont_draw_str(vram_s + o, 640, 1, "WAVE File Info:"); o += 640*24;
bfont_draw_str(vram_s + o, 640, 1, msg1[0]); o += 640*24;
bfont_draw_str(vram_s + o, 640, 1, msg1[1]); o += 640*24;
bfont_draw_str(vram_s + o, 640, 1, msg1[2]); o += 640*24;
#endif
if (fs_read(fd,sound_buffer,65536)!=65536 ) {
spu_status = WAVE_STATUS_ERROR;
break;
}
shnd = snd_stream_alloc(wave_callback, SND_STREAM_BUFFER_MAX);
if( spu_status != WAVE_STATUS_ERROR )
spu_status = WAVE_STATUS_READY;
case WAVE_STATUS_READY:
snd_stream_start(shnd, hz, chn-1);
spu_status = WAVE_STATUS_STREAMING;
case WAVE_STATUS_STREAMING:
while( spu_status != WAVE_STATUS_DONE ) {
if( spu_status == WAVE_STATUS_PAUSING ) {
spu_status = WAVE_STATUS_PAUSED;
while( spu_status != WAVE_STATUS_STREAMING )
thd_pass();
}
snd_stream_poll(shnd);
thd_sleep(50);
}
}
}
printf("spu_wave_stream: finished\n");
snd_stream_destroy(shnd);
snd_stream_shutdown();
fs_close(fd);
sq_clr( sound_buffer, 65536 );
spu_status = WAVE_STATUS_NULL;
}
int wave_stream( char * file_name ) {
sprintf( filename, "%s", file_name );
kthread_t * wave_thd;
wave_thd = thd_create( wave_thread, NULL );
return spu_status;
}
- These users thanked the author PH3NOM for the post:
- Christuserloeser
- lerabot
- Insane DCEmu
- Posts: 134
- Joined: Sun Nov 01, 2015 8:25 pm
- Has thanked: 2 times
- Been thanked: 19 times
Re: Working with Sound Output using the AICA SPU
Sorry for the huge necrobump.
I've been trying to get proper .wav file streaming on DC since OGG decoding is quite heavy on the CPU and, for some reason, the .mp3 lib is stuterring on my end.
If anyone has PH3NOM's source I'd love to use it.
trying my luck here...
I've been trying to get proper .wav file streaming on DC since OGG decoding is quite heavy on the CPU and, for some reason, the .mp3 lib is stuterring on my end.
If anyone has PH3NOM's source I'd love to use it.
trying my luck here...
- BB Hood
- DC Developer
- Posts: 189
- Joined: Fri Mar 30, 2007 12:09 am
- Has thanked: 41 times
- Been thanked: 10 times
Re: Working with Sound Output using the AICA SPU
Here is my libwav: https://github.com/andressbarajas/libwav
Here is an example of it in use: https://github.com/andressbarajas/dream ... eaming/WAV
And the audio page that links to it: https://dreamcast.wiki/Streaming_audio
Here is an example of it in use: https://github.com/andressbarajas/dream ... eaming/WAV
And the audio page that links to it: https://dreamcast.wiki/Streaming_audio
- PH3NOM
- DC Developer
- Posts: 576
- Joined: Fri Jun 18, 2010 9:29 pm
- Has thanked: 0
- Been thanked: 5 times
Re: Working with Sound Output using the AICA SPU
Hi there lerabot. I believe this is actually included in my project which can be found here: https://github.com/PH3NOM-PRO/in-the-li ... c/spu_wave. That said, I did not ending up using this method for the project, instead opting to use CDDA as that should completely bypass CPU, using DMA from the SPU to stream from CD directly. But if you really are interested, I have written a decoder for just about any audio codec you would likely want to use: https://github.com/PH3NOM-PRO/dreamcast-media-centerlerabot wrote: ↑Thu Aug 06, 2020 10:15 am Sorry for the huge necrobump.
I've been trying to get proper .wav file streaming on DC since OGG decoding is quite heavy on the CPU and, for some reason, the .mp3 lib is stuterring on my end.
If anyone has PH3NOM's source I'd love to use it.
trying my luck here...
Hmm, I see you have copied some of my code directly without any acknowledgement... thanks for the credit mate. https://github.com/PH3NOM-PRO/dreamcast ... c/snddrv.hBB Hood wrote: ↑Fri Aug 14, 2020 11:58 pm Here is my libwav: https://github.com/andressbarajas/libwav
Here is an example of it in use: https://github.com/andressbarajas/dream ... eaming/WAV
And the audio page that links to it: https://dreamcast.wiki/Streaming_audio
- BB Hood
- DC Developer
- Posts: 189
- Joined: Fri Mar 30, 2007 12:09 am
- Has thanked: 41 times
- Been thanked: 10 times
Re: Working with Sound Output using the AICA SPU
No ill will intended. I start with some source of yours as a base and then reworked it to take the approach that libmp3 and vorbisdisplay did. I see that I still kept CONST names and some variable names the same but I believed it was different enough that credit wasn't needed. I guess I was wrong. Where would you like credit? In the README? Source? Both?PH3NOM wrote: ↑Sun Aug 23, 2020 2:06 pmHmm, I see you have copied some of my code directly without any acknowledgement... thanks for the credit mate. https://github.com/PH3NOM-PRO/dreamcast ... c/snddrv.hBB Hood wrote: ↑Fri Aug 14, 2020 11:58 pm Here is my libwav: https://github.com/andressbarajas/libwav
Here is an example of it in use: https://github.com/andressbarajas/dream ... eaming/WAV
And the audio page that links to it: https://dreamcast.wiki/Streaming_audio