/** EMULib Emulation Library *********************************/ /** **/ /** SndUnix.c **/ /** **/ /** This file contains standard sound generation routines **/ /** for Unix using /dev/dsp and /dev/audio. **/ /** **/ /** Copyright (C) Marat Fayzullin 1996-2002 **/ /** You are not allowed to distribute this software **/ /** commercially. Please, notify me, if you make any **/ /** changes to this file. **/ /*************************************************************/ #ifdef UNIX #include "Sound.h" #include #include #include #include #include #include #ifdef SUN_AUDIO #include #include #include #define AUDIO_CONV(A) (ULAW[0xFF&(128+(A))]) static unsigned char ULAW[256] = { 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 83, 85, 87, 89, 91, 93, 95, 99, 103, 107, 111, 119, 255, 247, 239, 235, 231, 227, 223, 221, 219, 217, 215, 213, 211, 209, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 219, 217, 215, 213, 211, 209, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 191, 190, 190, 189, 189, 188, 188, 187, 187, 186, 186, 185, 185, 184, 184, 183, 183, 182, 182, 181, 181, 180, 180, 179, 179, 178, 178, 177, 177, 176, 176, 175, 175, 175, 175, 174, 174, 174, 174, 173, 173, 173, 173, 172, 172, 172, 172, 171, 171, 171, 171, 170, 170, 170, 170, 169, 169, 169, 169, 168, 168, 168, 168, 167, 167, 167, 167, 166, 166, 166, 166, 165, 165, 165, 165, 164, 164, 164, 164, 163, 163 }; #else /* SUN_AUDIO */ #ifdef __FreeBSD__ #include #endif #ifdef __NetBSD__ #include #endif #ifdef __linux__ #include #endif #define AUDIO_CONV(A) (128+(A)) #endif /* SUN_AUDIO */ static pthread_t ThreadID; static int SoundFD; static int SoundRate = 0; static int MasterVolume = 64; static int MasterSwitch = (1<>16)>=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; } if(SoundFD==-1) sleep(1); else { #ifdef 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,Buf,SND_BUFSIZE); #else /* We'll block here until next DMA buffer becomes free. It happens ** once per (1<=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,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 */ } #endif /* UNIX */