/* * Allegro Sound Driver for EMULib Sound system - The TI-NESulator Project * SndAlleg.C * * Created by Manoel Trapier * Copyright 2003-2008 986 Corp. All rights reserved. * * $LastChangedDate$ * $Author$ * $HeadURL$ * $Revision$ * */ #include /* Allegro includes */ #ifdef __APPLE__ #define USE_CONSOLE #include #else #define USE_CONSOLE #include #endif #include #include #include //#include //#include #include //#include #define AUDIO_CONV(A) (128+(A)) AUDIOSTREAM *stream; static pthread_t ThreadID; static int SoundRate = 0; static int MasterVolume = 64; static int MasterSwitch = (1<voice); if(Verbose) puts("OK"); return(Rate); } /** DSPLoop() ************************************************/ /** Main loop of the sound server. **/ /*************************************************************/ static void *DSPLoop(void *Arg) { int Wave[SND_BUFSIZE]; unsigned char *Buf; register int J,I,K,L,M,N,L1,L2,A1,A2,V; int FreqCount; N = L = A2 = 0; for(J=0;J>=1) if(CH[J].Freq&&(V=CH[J].Volume)&&(M&1)) switch(CH[J].Type) { case SND_NOISE: /* White Noise */ /* For high frequencies, recompute volume */ if(CH[J].Freq<=SoundRate) K=0x10000*CH[J].Freq/SoundRate; else { V=V*SoundRate/CH[J].Freq;K=0x10000; } L1=CH[J].Count; V<<=7; for(I=0;I0? (SoundRate<<15)/CH[J].Freq/CH[J].Rate : (SoundRate<<15)/CH[J].Freq/CH[J].Length; L1 = CH[J].Pos%CH[J].Length; L2 = CH[J].Count; A1 = CH[J].Data[L1]*V; /* If expecting interpolation... */ if(L2>15)+1; N = ((K-(L2&0x7FFF))>>15)+1; } /* Add waveform to the buffer */ for(I=0;I>15)+1; } } /* End counting */ CH[J].Pos = L1; CH[J].Count = L2; break; case SND_QS_DU0: /* Do not allow frequencies that are too high */ if(CH[J].Freq>=SoundRate/3) break; K=0x10000*CH[J].Freq/SoundRate; L1=CH[J].Count; V<<=7; for(I=0;I=SoundRate/3) break; K=0x10000*CH[J].Freq/SoundRate; L1=CH[J].Count; V<<=7; for(I=0;I=SoundRate/3) break; K=0x10000*CH[J].Freq/SoundRate; L1=CH[J].Count; V<<=7; for(I=0;I=SoundRate/3) break; K=0x10000*CH[J].Freq/SoundRate; L1=CH[J].Count; V<<=7; for(I=0;I=SoundRate/3) break; K=0x10000*CH[J].Freq/SoundRate; L1=CH[J].Count; V<<=7; for(I=0;I>16; I=I<-128? -128:I>127? 127:I; Buf[J]=AUDIO_CONV(I); Wave[J]=0; } free_audio_stream_buffer(stream); } } return(0); } /** InitSound() **********************************************/ /** Initialize DSP. Returns Rate on success, 0 otherwise. **/ /** Mode is 0 to skip initialization (will be silent). **/ /*************************************************************/ int InitSound(int Rate,int Verbose) { /* If sound was initialized, kill it */ TrashSound(); /* Silence requested */ if(Rate<=0) return(0); /* Synthesis rate should be at least 8kHz */ if(Rate<8192) Rate=44100; /* Initialize things */ SoundRate = 0; ThreadID = 0; Suspended = 0; /* Set driver functions */ SndDriver.SetSound = UnixSetSound; SndDriver.Drum = UnixDrum; SndDriver.SetChannels = UnixSetChannels; SndDriver.Sound = UnixSound; SndDriver.SetWave = UnixSetWave; if (install_sound(DIGI_AUTODETECT, MIDI_NONE, "") != 0) { console_printf(Console_Error, "%s!\n", allegro_error); return 1; } stream = play_audio_stream(SND_BUFSIZE, 8, FALSE, Rate, 255, 128); if (!stream) { console_printf(Console_Error, "Error creating audio stream!\n"); return 1; } voice_stop(stream->voice); /* Open sound device */ if(Verbose) puts("Starting sound server:"); if(!(Rate=OpenSoundDevice(Rate,Verbose))) return(0); /* Create DSPLoop() thread */ if(Verbose) console_printf(Console_Default, " Creating thread..."); if(pthread_create(&ThreadID,0,DSPLoop,0)) { if(Verbose) puts("FAILED");return(0); } /* Detach the thread */ pthread_detach(ThreadID); /* Done */ if(Verbose) puts("OK"); return(SoundRate=Rate); } /** TrashSound() *********************************************/ /** Shut DSP down. **/ /*************************************************************/ void TrashSound(void) { StopSound(); console_printf(Console_Default, "%s: Kill thread...\n", __func__); if(ThreadID) pthread_cancel(ThreadID); SoundRate = 0; ThreadID = 0; } /** UnixSound() **********************************************/ /** Generate sound of given frequency (Hz) and volume **/ /** (0..255) via given channel. **/ /*************************************************************/ void UnixSound(int Channel,int NewFreq,int NewVolume) { if((Channel<0)||(Channel>=SND_CHANNELS)) return; if(!NewVolume||!NewFreq) { NewVolume=0;NewFreq=0; } CH[Channel].Volume = NewVolume; CH[Channel].Freq = NewFreq; } /** UnixSetChannels() ****************************************/ /** Set master volume (0..255) and turn channels on/off. **/ /** Each bit in Toggle corresponds to a channel (1=on). **/ /*************************************************************/ void UnixSetChannels(int MVolume,int MSwitch) { /* Set new MasterSwitch value */ MasterSwitch = MSwitch; MasterVolume = MVolume; } /** UnixSetSound() *******************************************/ /** Set sound type (SND_NOISE/SND_MELODIC) for a given **/ /** channel. **/ /*************************************************************/ void UnixSetSound(int Channel,int NewType) { if((Channel<0)||(Channel>=SND_CHANNELS)) return; CH[Channel].Type = NewType; } /** UnixSetWave() ********************************************/ /** Set waveform for a given channel. The channel will be **/ /** marked with sound type SND_WAVE. Set Rate=0 if you want **/ /** waveform to be an instrument or set it to the waveform **/ /** own playback rate. **/ /*************************************************************/ void UnixSetWave(int Channel,const signed char *Data,int Length,int Rate) { if((Channel<0)||(Channel>=SND_CHANNELS)||(Length<=0)) return; CH[Channel].Type = SND_WAVE; CH[Channel].Length = Length; CH[Channel].Rate = Rate; CH[Channel].Pos = 0; CH[Channel].Count = 0; CH[Channel].Data = Data; } /** UnixDrum() ***********************************************/ /** Hit a drum of a given type with given force. **/ /*************************************************************/ void UnixDrum(int Type,int Force) { /* This function is currently empty */ }