SndUnixT.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /** EMULib Emulation Library *********************************/
  2. /** **/
  3. /** SndUnix.c **/
  4. /** **/
  5. /** This file contains standard sound generation routines **/
  6. /** for Unix using /dev/dsp and /dev/audio. **/
  7. /** **/
  8. /** Copyright (C) Marat Fayzullin 1996-2002 **/
  9. /** You are not allowed to distribute this software **/
  10. /** commercially. Please, notify me, if you make any **/
  11. /** changes to this file. **/
  12. /*************************************************************/
  13. //#include "Sound.h"
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <unistd.h>
  17. #include <fcntl.h>
  18. #include <pthread.h>
  19. #include <sys/ioctl.h>
  20. #include <os_dependent.h>
  21. #if 0
  22. #ifdef SUN_AUDIO
  23. #include <sys/audioio.h>
  24. #include <sys/conf.h>
  25. #include <stropts.h>
  26. #define AUDIO_CONV(A) (ULAW[0xFF&(128+(A))])
  27. static unsigned char ULAW[256] =
  28. {
  29. 31, 31, 31, 32, 32, 32, 32, 33,
  30. 33, 33, 33, 34, 34, 34, 34, 35,
  31. 35, 35, 35, 36, 36, 36, 36, 37,
  32. 37, 37, 37, 38, 38, 38, 38, 39,
  33. 39, 39, 39, 40, 40, 40, 40, 41,
  34. 41, 41, 41, 42, 42, 42, 42, 43,
  35. 43, 43, 43, 44, 44, 44, 44, 45,
  36. 45, 45, 45, 46, 46, 46, 46, 47,
  37. 47, 47, 47, 48, 48, 49, 49, 50,
  38. 50, 51, 51, 52, 52, 53, 53, 54,
  39. 54, 55, 55, 56, 56, 57, 57, 58,
  40. 58, 59, 59, 60, 60, 61, 61, 62,
  41. 62, 63, 63, 64, 65, 66, 67, 68,
  42. 69, 70, 71, 72, 73, 74, 75, 76,
  43. 77, 78, 79, 81, 83, 85, 87, 89,
  44. 91, 93, 95, 99, 103, 107, 111, 119,
  45. 255, 247, 239, 235, 231, 227, 223, 221,
  46. 219, 217, 215, 213, 211, 209, 207, 206,
  47. 205, 204, 203, 202, 201, 200, 199, 198,
  48. 219, 217, 215, 213, 211, 209, 207, 206,
  49. 205, 204, 203, 202, 201, 200, 199, 198,
  50. 197, 196, 195, 194, 193, 192, 191, 191,
  51. 190, 190, 189, 189, 188, 188, 187, 187,
  52. 186, 186, 185, 185, 184, 184, 183, 183,
  53. 182, 182, 181, 181, 180, 180, 179, 179,
  54. 178, 178, 177, 177, 176, 176, 175, 175,
  55. 175, 175, 174, 174, 174, 174, 173, 173,
  56. 173, 173, 172, 172, 172, 172, 171, 171,
  57. 171, 171, 170, 170, 170, 170, 169, 169,
  58. 169, 169, 168, 168, 168, 168, 167, 167,
  59. 167, 167, 166, 166, 166, 166, 165, 165,
  60. 165, 165, 164, 164, 164, 164, 163, 163
  61. };
  62. #else /* SUN_AUDIO */
  63. #ifdef __FreeBSD__
  64. #include <machine/soundcard.h>
  65. #endif
  66. #ifdef __NetBSD__
  67. #include <soundcard.h>
  68. #endif
  69. #ifdef __linux__
  70. #include <sys/soundcard.h>
  71. #endif
  72. #define AUDIO_CONV(A) (128+(A))
  73. #endif /* SUN_AUDIO */
  74. static pthread_t ThreadID;
  75. static int SoundFD;
  76. static int SoundRate = 0;
  77. static int MasterVolume = 64;
  78. static int MasterSwitch = (1<<SND_CHANNELS)-1;
  79. static int LoopFreq = 25;
  80. static int NoiseGen = 1;
  81. static int Suspended = 0;
  82. static struct
  83. {
  84. int Type; /* Channel type (SND_*) */
  85. int Freq; /* Channel frequency (Hz) */
  86. int Volume; /* Channel volume (0..255) */
  87. signed char *Data; /* Wave data (-128..127 each) */
  88. int Length; /* Wave length in Data */
  89. int Rate; /* Wave playback rate (or 0Hz) */
  90. int Pos; /* Wave current position in Data */
  91. int Count; /* Phase counter */
  92. } CH[SND_CHANNELS];
  93. static void UnixSetWave(int Channel, signed char *Data,int Length,int Freq);
  94. static void UnixSetSound(int Channel,int NewType);
  95. static void UnixDrum(int Type,int Force);
  96. static void UnixSetChannels(int Volume,int Switch);
  97. static void UnixSound(int Channel,int NewFreq,int NewVolume);
  98. static int OpenSoundDevice(int Rate,int Verbose);
  99. static void *DSPLoop(void *Arg);
  100. /** StopSound() **********************************************/
  101. /** Temporarily suspend sound. **/
  102. /*************************************************************/
  103. void StopSound(void) { Suspended=1; }
  104. /** ResumeSound() ********************************************/
  105. /** Resume sound after StopSound(). **/
  106. /*************************************************************/
  107. void ResumeSound(void) { Suspended=0; }
  108. /** OpenSoundDevice() ****************************************/
  109. /** Open /dev/dsp with a given level of sound quality. **/
  110. /** Returns 0 if failed or sound quality (Mode). **/
  111. /*************************************************************/
  112. static int OpenSoundDevice(int Rate,int Verbose)
  113. {
  114. int I,J,K;
  115. #ifdef SUN_AUDIO
  116. if(Verbose) console_printf(Console_Default, " Opening /dev/audio...");
  117. if((SoundFD=open("/dev/audio",O_WRONLY | O_NONBLOCK))==-1)
  118. {
  119. if(Verbose) puts("FAILED");
  120. return(0);
  121. }
  122. /*
  123. ** Sun's specific initialization should be here...
  124. ** We assume, that it's set to 8000Hz u-law mono right now.
  125. */
  126. #else /* SUN_AUDIO */
  127. /* At first, we need to open /dev/dsp: */
  128. if(Verbose) console_printf(Console_Default, " Opening /dev/dsp...");
  129. I=((SoundFD=open("/dev/dsp",O_WRONLY))<0);
  130. /* Set 8-bit sound */
  131. if(!I)
  132. {
  133. if(Verbose) console_printf(Console_Default, "OK\n Setting mode: 8bit...");
  134. J=AFMT_U8;
  135. I=(ioctl(SoundFD,SNDCTL_DSP_SETFMT,&J)<0);
  136. }
  137. /* Set mono sound */
  138. if(!I)
  139. {
  140. if(Verbose) console_printf(Console_Default, "mono...");
  141. J=0;
  142. I=(ioctl(SoundFD,SNDCTL_DSP_STEREO,&J)<0);
  143. }
  144. /* Set sampling rate */
  145. if(!I)
  146. {
  147. if(Verbose) console_printf(Console_Default, "OK\n Setting sampling rate: %dHz...",Rate);
  148. I=(ioctl(SoundFD,SNDCTL_DSP_SPEED,&Rate)<0);
  149. if(Verbose) console_printf(Console_Default, "(got %dHz)...",Rate);
  150. }
  151. /* Here we set the number of buffers to use */
  152. if(!I)
  153. {
  154. if(Verbose)
  155. printf
  156. (
  157. "OK\n Adjusting buffers: %d buffers %d bytes each...",
  158. SND_BUFFERS,1<<SND_BITS
  159. );
  160. /* Set buffer length and number of buffers */
  161. J=K=SND_BITS|(SND_BUFFERS<<16);
  162. I=(ioctl(SoundFD,SNDCTL_DSP_SETFRAGMENT,&J)<0);
  163. /* Buffer length as n, not 2^n! */
  164. if((J&0xFFFF)<16) J=(J&0xFFFF0000)|(1<<(J&0xFFFF));
  165. K=(1<<SND_BITS)|(SND_BUFFERS<<16);
  166. /* If something went wrong... */
  167. if(J!=K)
  168. {
  169. if((J>>16)<SND_BUFFERS) I=-1;
  170. if((J&0xFFFF)!=(1<<SND_BITS)) I=-1;
  171. }
  172. }
  173. /* If something failed, fall out */
  174. if(I) { if(Verbose) puts("FAILED");return(0); }
  175. #endif /* SUN_AUDIO */
  176. if(Verbose) puts("OK");
  177. return(Rate);
  178. }
  179. /** DSPLoop() ************************************************/
  180. /** Main loop of the sound server. **/
  181. /*************************************************************/
  182. static void *DSPLoop(void *Arg)
  183. {
  184. int Wave[SND_BUFSIZE];
  185. unsigned char Buf[SND_BUFSIZE];
  186. register int J,I,K,L,M,N,L1,L2,A1,A2,V;
  187. int FreqCount;
  188. int ret;
  189. L = N = A2 = 0;
  190. for(J=0;J<SND_CHANNELS;J++)
  191. {
  192. CH[J].Type = SND_MELODIC;
  193. CH[J].Count = 0;
  194. CH[J].Volume = 0;
  195. CH[J].Freq = 0;
  196. }
  197. FreqCount=SoundRate/SND_BUFSIZE;
  198. for(;;FreqCount-=LoopFreq)
  199. {
  200. /* If suspending sound... */
  201. if(Suspended)
  202. {
  203. /* Close sound device */
  204. #ifndef SUN_AUDIO
  205. ioctl(SoundFD,SNDCTL_DSP_RESET);
  206. #endif
  207. close(SoundFD);
  208. /* Suspend execution until Suspended=0 */
  209. while(Suspended) sleep(1);
  210. /* Reopen sound device */
  211. SoundRate=OpenSoundDevice(SoundRate,0);
  212. }
  213. /* Waveform generator */
  214. for(J=0,M=MasterSwitch;M&&(J<SND_CHANNELS);J++,M>>=1)
  215. if(CH[J].Freq&&(V=CH[J].Volume)&&(M&1))
  216. switch(CH[J].Type)
  217. {
  218. case SND_NOISE: /* White Noise */
  219. /* For high frequencies, recompute volume */
  220. if(CH[J].Freq<=SoundRate) K=0x10000*CH[J].Freq/SoundRate;
  221. else { V=V*SoundRate/CH[J].Freq;K=0x10000; }
  222. L1=CH[J].Count;
  223. V<<=7;
  224. for(I=0;I<SND_BUFSIZE;I++)
  225. {
  226. L1+=K;
  227. if(L1&0xFFFF0000)
  228. {
  229. L1&=0xFFFF;
  230. if((NoiseGen<<=1)&0x80000000) NoiseGen^=0x08000001;
  231. }
  232. Wave[I]+=NoiseGen&1? V:-V;
  233. }
  234. CH[J].Count=L1;
  235. break;
  236. case SND_WAVE: /* Custom Waveform */
  237. /* Waveform data must have correct length! */
  238. if(CH[J].Length<=0) break;
  239. /* Start counting */
  240. K = CH[J].Rate>0? (SoundRate<<15)/CH[J].Freq/CH[J].Rate
  241. : (SoundRate<<15)/CH[J].Freq/CH[J].Length;
  242. L1 = CH[J].Pos%CH[J].Length;
  243. L2 = CH[J].Count;
  244. A1 = CH[J].Data[L1]*V;
  245. /* If expecting interpolation... */
  246. if(L2<K)
  247. {
  248. /* Compute interpolation parameters */
  249. A2 = CH[J].Data[(L1+1)%CH[J].Length]*V;
  250. L = (L2>>15)+1;
  251. N = ((K-(L2&0x7FFF))>>15)+1;
  252. }
  253. /* Add waveform to the buffer */
  254. for(I=0;I<SND_BUFSIZE;I++)
  255. if(L2<K)
  256. {
  257. /* Interpolate linearly */
  258. Wave[I]+=A1+L*(A2-A1)/N;
  259. /* Next waveform step */
  260. L2+=0x8000;
  261. /* Next interpolation step */
  262. L++;
  263. }
  264. else
  265. {
  266. L1 = (L1+L2/K)%CH[J].Length;
  267. L2 = (L2%K)+0x8000;
  268. A1 = CH[J].Data[L1]*V;
  269. Wave[I]+=A1;
  270. /* If expecting interpolation... */
  271. if(L2<K)
  272. {
  273. /* Compute interpolation parameters */
  274. A2 = CH[J].Data[(L1+1)%CH[J].Length]*V;
  275. L = 1;
  276. N = ((K-L2)>>15)+1;
  277. }
  278. }
  279. /* End counting */
  280. CH[J].Pos = L1;
  281. CH[J].Count = L2;
  282. break;
  283. case SND_QS_DU0:
  284. /* Do not allow frequencies that are too high */
  285. if(CH[J].Freq>=SoundRate/3) break;
  286. K=0x10000*CH[J].Freq/SoundRate;
  287. L1=CH[J].Count;
  288. V<<=7;
  289. for(I=0;I<SND_BUFSIZE;I++)
  290. {
  291. L2=L1+K;
  292. Wave[I]+=L1&0x2000?(L2&0x8000? V:0):(L2&0x8000? 0:-V);
  293. L1=L2;
  294. }
  295. CH[J].Count=L1;
  296. break;
  297. case SND_QS_DU1:
  298. /* Do not allow frequencies that are too high */
  299. if(CH[J].Freq>=SoundRate/3) break;
  300. K=0x10000*CH[J].Freq/SoundRate;
  301. L1=CH[J].Count;
  302. V<<=7;
  303. for(I=0;I<SND_BUFSIZE;I++)
  304. {
  305. L2=L1+K;
  306. Wave[I]+=L1&0x4000?(L2&0x8000? V:0):(L2&0x8000? 0:-V);
  307. L1=L2;
  308. }
  309. CH[J].Count=L1;
  310. break;
  311. case SND_QS_DU3:
  312. /* Do not allow frequencies that are too high */
  313. if(CH[J].Freq>=SoundRate/3) break;
  314. K=0x10000*CH[J].Freq/SoundRate;
  315. L1=CH[J].Count;
  316. V<<=7;
  317. for(I=0;I<SND_BUFSIZE;I++)
  318. {
  319. L2=L1+K;
  320. Wave[I]+=L1&0xC000?(L2&0x4000? V:0):(L2&0xC000? 0:-V);
  321. L1=L2;
  322. }
  323. CH[J].Count=L1;
  324. break;
  325. case SND_QS_DU2:
  326. case SND_MELODIC: /* Melodic Sound */
  327. default: /* Default Sound */
  328. /* Do not allow frequencies that are too high */
  329. if(CH[J].Freq>=SoundRate/3) break;
  330. K=0x10000*CH[J].Freq/SoundRate;
  331. L1=CH[J].Count;
  332. V<<=7;
  333. for(I=0;I<SND_BUFSIZE;I++)
  334. {
  335. L2=L1+K;
  336. Wave[I]+=L1&0x8000? (L2&0x8000? V:0):(L2&0x8000? 0:-V);
  337. L1=L2;
  338. }
  339. CH[J].Count=L1;
  340. break;
  341. case SND_TRIANGLE: /* Default Sound */
  342. /* Do not allow frequencies that are too high */
  343. if(CH[J].Freq>=SoundRate/3) break;
  344. K=0x10000*CH[J].Freq/SoundRate;
  345. L1=CH[J].Count;
  346. V<<=7;
  347. for(I=0;I<SND_BUFSIZE;I++)
  348. {
  349. L2=L1+K;
  350. Wave[I]+= L1&0x2000?V:-V /*(L2&0x8000? V:0):(L2&0x8000? 0:-V)*/;
  351. L1=L2;
  352. }
  353. CH[J].Count=L1;
  354. break;
  355. }
  356. /* Mix and convert waveforms */
  357. for(J=0;J<SND_BUFSIZE;J++)
  358. {
  359. I=(Wave[J]*MasterVolume)>>16;
  360. I=I<-128? -128:I>127? 127:I;
  361. Buf[J]=AUDIO_CONV(I);
  362. Wave[J]=0;
  363. }
  364. if(SoundFD==-1) sleep(1);
  365. else
  366. {
  367. #ifdef SUN_AUDIO
  368. /* Flush output first, don't care about return status. After this
  369. ** write next buffer of audio data. This method produces a horrible
  370. ** click on each buffer :( Any ideas, how to fix this?
  371. */
  372. ioctl(SoundFD,AUDIO_DRAIN);
  373. write(SoundFD,Buf,SND_BUFSIZE);
  374. #else
  375. /* We'll block here until next DMA buffer becomes free. It happens
  376. ** once per (1<<SND_BITS)/SoundRate seconds.
  377. */
  378. ret = write(SoundFD,Buf,SND_BUFSIZE);
  379. #endif
  380. }
  381. }
  382. return(0);
  383. }
  384. /** InitSound() **********************************************/
  385. /** Initialize DSP. Returns Rate on success, 0 otherwise. **/
  386. /** Mode is 0 to skip initialization (will be silent). **/
  387. /*************************************************************/
  388. int InitSound(int Rate,int Verbose)
  389. {
  390. /* If sound was initialized, kill it */
  391. TrashSound();
  392. /* Silence requested */
  393. if(Rate<=0) return(0);
  394. /* Synthesis rate should be at least 8kHz */
  395. if(Rate<8192) Rate=44100;
  396. /* Initialize things */
  397. SoundRate = 0;
  398. SoundFD = -1;
  399. ThreadID = 0;
  400. Suspended = 0;
  401. /* Set driver functions */
  402. SndDriver.SetSound = UnixSetSound;
  403. SndDriver.Drum = UnixDrum;
  404. SndDriver.SetChannels = UnixSetChannels;
  405. SndDriver.Sound = UnixSound;
  406. SndDriver.SetWave = UnixSetWave;
  407. /* Open sound device */
  408. if(Verbose) puts("Starting sound server:");
  409. if(!(Rate=OpenSoundDevice(Rate,Verbose))) return(0);
  410. /* Create DSPLoop() thread */
  411. if(Verbose) console_printf(Console_Default, " Creating thread...");
  412. if(pthread_create(&ThreadID,0,DSPLoop,0))
  413. { if(Verbose) puts("FAILED");return(0); }
  414. /* Detach the thread */
  415. pthread_detach(ThreadID);
  416. /* Done */
  417. if(Verbose) puts("OK");
  418. return(SoundRate=Rate);
  419. }
  420. /** TrashSound() *********************************************/
  421. /** Shut DSP down. **/
  422. /*************************************************************/
  423. void TrashSound(void)
  424. {
  425. StopSound();
  426. console_printf(Console_Default, "%s: Kill thread...\n", __func__);
  427. if(ThreadID) pthread_cancel(ThreadID);
  428. console_printf(Console_Default, "%s: close /dev/xxx ...\n", __func__);
  429. if(SoundFD!=-1) close(SoundFD);
  430. SoundRate = 0;
  431. SoundFD = -1;
  432. ThreadID = 0;
  433. }
  434. /** UnixSound() **********************************************/
  435. /** Generate sound of given frequency (Hz) and volume **/
  436. /** (0..255) via given channel. **/
  437. /*************************************************************/
  438. void UnixSound(int Channel,int NewFreq,int NewVolume)
  439. {
  440. if((Channel<0)||(Channel>=SND_CHANNELS)) return;
  441. if(!NewVolume||!NewFreq) { NewVolume=0;NewFreq=0; }
  442. CH[Channel].Volume = NewVolume;
  443. CH[Channel].Freq = NewFreq;
  444. }
  445. /** UnixSetChannels() ****************************************/
  446. /** Set master volume (0..255) and turn channels on/off. **/
  447. /** Each bit in Toggle corresponds to a channel (1=on). **/
  448. /*************************************************************/
  449. void UnixSetChannels(int MVolume,int MSwitch)
  450. {
  451. /* Set new MasterSwitch value */
  452. MasterSwitch = MSwitch;
  453. MasterVolume = MVolume;
  454. }
  455. /** UnixSetSound() *******************************************/
  456. /** Set sound type (SND_NOISE/SND_MELODIC) for a given **/
  457. /** channel. **/
  458. /*************************************************************/
  459. void UnixSetSound(int Channel,int NewType)
  460. {
  461. if((Channel<0)||(Channel>=SND_CHANNELS)) return;
  462. CH[Channel].Type = NewType;
  463. }
  464. /** UnixSetWave() ********************************************/
  465. /** Set waveform for a given channel. The channel will be **/
  466. /** marked with sound type SND_WAVE. Set Rate=0 if you want **/
  467. /** waveform to be an instrument or set it to the waveform **/
  468. /** own playback rate. **/
  469. /*************************************************************/
  470. void UnixSetWave(int Channel, signed char *Data, int Length, int Freq)
  471. {
  472. if((Channel<0)||(Channel>=SND_CHANNELS)||(Length<=0)) return;
  473. CH[Channel].Type = SND_WAVE;
  474. CH[Channel].Length = Length;
  475. CH[Channel].Rate = Freq;
  476. CH[Channel].Pos = 0;
  477. CH[Channel].Count = 0;
  478. CH[Channel].Data = Data;
  479. }
  480. /** UnixDrum() ***********************************************/
  481. /** Hit a drum of a given type with given force. **/
  482. /*************************************************************/
  483. void UnixDrum(int Type,int Force)
  484. {
  485. /* This function is currently empty */
  486. }
  487. #endif