static void *ThrHandler(void *Arg) { #ifndef NO_SOUND int J; // Spin until audiSo has been trashed for(RPtr=WPtr=0; SndRate&&SndData&&(SoundFD>=0);) { #if defined(PULSE_AUDIO) if(SoundFD) pa_simple_write(SoundFD,SndData+RPtr,SND_BUFSIZE*sizeof(sample),0); #elif defined(SUN_AUDIO) // Flush output first, don't care about return status. After this // write next buffer of audio data. This method produces a horrible // click on each buffer :( Any ideas, how to fix this? ioctl(SoundFD,AUDIO_DRAIN); write(SoundFD,SndData+RPtr,SND_BUFSIZE*sizeof(sample)); #elif defined(__PLAYBOOK__) #else // We'll block here until next DMA buffer becomes free. It happens // once per SND_BUFSIZE/SndRate seconds. write(SoundFD,SndData+RPtr,SND_BUFSIZE*sizeof(sample)); #endif // Advance buffer pointer, clearing the buffer for(J=0; J<SND_BUFSIZE; ++J) SndData[RPtr++]=AUDIO_CONV(0); if(RPtr>=SndSize) RPtr=0; } #endif return(0); }
/* note: gain is specified as gain*16 */ static int make_mixer_table (int gain) { int count = NUM_VOICES * 128; int i; /* allocate memory */ mixer_table = malloc (256 * NUM_VOICES); if (!mixer_table) return 1; /* find the middle of the table */ mixer_lookup = mixer_table + (NUM_VOICES * 128); /* fill in the table */ for (i = 0; i < count; i++) { int val = i * gain / (NUM_VOICES * 16); if (val > 127) val = 127; mixer_lookup[ i] = AUDIO_CONV(val); mixer_lookup[-i] = AUDIO_CONV(-val); } return 0; }
unsigned int WriteAudio(sample *Data,unsigned int Length) { unsigned int J; // Require audio to be initialized if(!SndRate) return(0); // Copy audio samples for(J=0; (J<Length)&&(RPtr!=WPtr); ++J) { SndData[WPtr++]=AUDIO_CONV(Data[J]); if(WPtr>=SndSize) WPtr=0; } // Return number of samples copied return(J); }
unsigned int InitAudio(unsigned int Rate,unsigned int Latency) { #ifndef NO_SOUND int I,J,K; // Shut down audio, just to be sure TrashAudio(); #ifndef __PLAYBOOK__ SoundFD = -1; Thr = 0; #else SDL_AudioSpec AudioFormat; #endif SndRate = 0; SndSize = 0; SndData = 0; RPtr = 0; WPtr = 0; AudioPaused = 0; // Have to have at least 8kHz sampling rate and 1ms buffer if((Rate<8000)||!Latency) return(0); // Compute number of sound buffers SndSize=Rate*Latency/1000; // Allocate audio buffers SndData=(sample *)malloc(SndSize*sizeof(sample)); if(!SndData) { TrashSound(); return(0); } #if defined(__PLAYBOOK__) SDL_InitSubSystem (SDL_INIT_AUDIO); /* Set SDL audio settings */ AudioFormat.freq = Rate; AudioFormat.format = sizeof(sample)>1? AUDIO_S16:AUDIO_S8; AudioFormat.channels = 1; AudioFormat.samples = SndSize/2; AudioFormat.callback = sdl_audio_callback; AudioFormat.userdata = 0; printf ("SDL sound driver initializing...\n"); printf (" --> (Frequency: %dhz, Latency: %dms)...", AudioFormat.freq, (AudioFormat.samples * 1000 / AudioFormat.freq) << 1); if (SDL_OpenAudio (&AudioFormat, NULL) < 0) { printf ("Failed\n"); free(SndData); SndData = NULL; return 0; } printf ("OK\n"); // Clear audio buffers for(J=0; J<SndSize; ++J) SndData[J]=AUDIO_CONV(0); // Thread expects valid SndRate!=0 at the start SndRate=Rate; SDL_PauseAudio (0); #elif defined(PULSE_AUDIO) { // Configure PulseAudio sound pa_sample_spec PASpec; PASpec.format = sizeof(sample)>1? PA_SAMPLE_S16LE:PA_SAMPLE_U8; PASpec.rate = Rate; PASpec.channels = 1; // Try opening PulseAudio if(!(SoundFD=pa_simple_new(0,"EMULib",PA_STREAM_PLAYBACK,0,"playback",&PASpec,0,0,0))) { SoundFD=-1; return(0); } } #elif defined(ESD_AUDIO) // ESD options for playing wave audio J=ESD_MONO|ESD_STREAM|ESD_PLAY|(sizeof(sample)>1? ESD_BITS16:ESD_BITS8); // Open ESD socket, fall back to /dev/dsp is no ESD if((SoundFD=esd_play_stream_fallback(J,Rate,0,0))<0) return(0); #elif defined(SUN_AUDIO) // Open Sun's audio device if((SoundFD=open("/dev/audio",O_WRONLY|O_NONBLOCK))<0) return(0); // Sun's specific initialization should be here... // We assume, that it's set to 8000Hz u-law mono right now. #else // !SUN_AUDIO // Open /dev/dsp audio device if((SoundFD=open("/dev/dsp",O_WRONLY))<0) return(0); // Set sound format J=sizeof(sample)>1? AFMT_S16_NE:AFMT_U8; I=ioctl(SoundFD,SNDCTL_DSP_SETFMT,&J)<0; // Set mono sound J=0; I|=ioctl(SoundFD,SNDCTL_DSP_STEREO,&J)<0; // Set sampling rate I|=ioctl(SoundFD,SNDCTL_DSP_SPEED,&Rate)<0; // Set buffer length and number of buffers J=K=SND_BITS|(SndSize<<16); I|=ioctl(SoundFD,SNDCTL_DSP_SETFRAGMENT,&J)<0; // Buffer length as n, not 2^n! if((J&0xFFFF)<=16) J=(J&0xFFFF0000)|(1<<(J&0xFFFF)); K=SND_BUFSIZE|(SndSize<<16); // Check audio parameters I|=(J!=K)&&(((J>>16)<SndSize)||((J&0xFFFF)!=SND_BUFSIZE)); // If something went wrong, drop out if(I) { TrashSound(); return(0); } #endif // !SUN_AUDIO // Create audio thread #ifndef __PLAYBOOK__ // SndSize now means the total buffer size SndSize*=SND_BUFSIZE; // Clear audio buffers for(J=0; J<SndSize; ++J) SndData[J]=AUDIO_CONV(0); // Thread expects valid SndRate!=0 at the start SndRate=Rate; if(pthread_create(&Thr,0,ThrHandler,0)) { TrashSound(); SndRate=0; return(0); } #endif // Done, return effective audio rate return(SndRate); #else return 0; #endif }