PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/legacy_one/trunk/djgppdos/I_sound.c

#
C | 569 lines | 326 code | 104 blank | 139 comment | 43 complexity | 048223cc8618325bc51cd7029d29088c MD5 | raw file
Possible License(s): GPL-2.0
  1. // Emacs style mode select -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id: I_sound.c 875 2011-11-01 00:13:44Z wesleyjohnson $
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
  8. //
  9. // This program is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public License
  11. // as published by the Free Software Foundation; either version 2
  12. // of the License, or (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. //
  20. // $Log: I_sound.c,v $
  21. // Revision 1.5 2003/07/13 13:18:59 hurdler
  22. // go RC1
  23. //
  24. // Revision 1.4 2001/03/30 17:12:52 bpereira
  25. // no message
  26. //
  27. // Revision 1.3 2000/03/06 15:32:56 hurdler
  28. // compiler warning removed
  29. //
  30. // Revision 1.2 2000/02/27 00:42:11 hurdler
  31. // fix CR+LF problem
  32. //
  33. // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
  34. // Initial import into CVS (v1.29 pr3)
  35. //
  36. //
  37. // DESCRIPTION:
  38. // interface level code for sound
  39. //
  40. //-----------------------------------------------------------------------------
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <stdarg.h>
  44. #include <math.h>
  45. #include "../doomdef.h"
  46. #include "../doomstat.h"
  47. #include "../i_system.h"
  48. #include "../i_sound.h"
  49. #include "../z_zone.h"
  50. #include "../m_argv.h"
  51. #include "../m_misc.h"
  52. #include "../w_wad.h"
  53. #include "../s_sound.h"
  54. #include "../console.h"
  55. //### let's try with Allegro ###
  56. #define alleg_mouse_unused
  57. #define alleg_timer_unused
  58. #define alleg_keyboard_unused
  59. #define alleg_joystick_unused
  60. #define alleg_gfx_driver_unused
  61. #define alleg_palette_unused
  62. #define alleg_graphics_unused
  63. #define alleg_vidmem_unused
  64. #define alleg_flic_unused
  65. //#define alleg_sound_unused we use it
  66. #define alleg_file_unused
  67. #define alleg_datafile_unused
  68. #define alleg_math_unused
  69. #define alleg_gui_unused
  70. #include <allegro.h>
  71. //### end of Allegro include ###
  72. #include "../qmus2mid.h"
  73. //#include "loadmus.h"
  74. //allegro has 256 virtual voices
  75. // warning should by a power of 2
  76. #define VIRTUAL_VOICES 256
  77. #define VOICESSHIFT 8
  78. // Needed for calling the actual sound output.
  79. #define SAMPLECOUNT 512
  80. //
  81. // this function converts raw 11khz, 8-bit data to a SAMPLE* that allegro uses
  82. // it is need cuz allegro only loads samples from wavs and vocs
  83. //added:11-01-98: now reads the frequency from the rawdata header.
  84. // dsdata points a 4 unsigned short header:
  85. // +0 : value 3 what does it mean?
  86. // +2 : sample rate, either 11025 or 22050.
  87. // +4 : number of samples, each sample is a single byte since it's 8bit
  88. // +6 : value 0
  89. SAMPLE *raw2SAMPLE(unsigned char *dsdata, int len)
  90. {
  91. SAMPLE *spl;
  92. spl=Z_Malloc(sizeof(SAMPLE),PU_STATIC,NULL);
  93. if(spl==NULL)
  94. I_Error("Raw2Sample : no more free mem");
  95. spl->bits = 8;
  96. spl->stereo = 0;
  97. spl->freq = *((unsigned short*)dsdata+1); //mostly 11025, but some at 22050.
  98. spl->len = len-8;
  99. spl->priority = 255; //priority;
  100. spl->loop_start = 0;
  101. spl->loop_end = len-8;
  102. spl->param = -1;
  103. spl->data=(void *)(dsdata+8); //skip the 8bytes header
  104. return spl;
  105. }
  106. // This function loads the sound data from the WAD lump,
  107. // for single sound.
  108. //
  109. void* I_GetSfx (sfxinfo_t* sfx)
  110. {
  111. byte* dssfx;
  112. int size;
  113. if (sfx->lumpnum<0)
  114. sfx->lumpnum = S_GetSfxLumpNum (sfx);
  115. size = W_LumpLength (sfx->lumpnum);
  116. dssfx = (byte*) W_CacheLumpNum (sfx->lumpnum, PU_STATIC);
  117. //_go32_dpmi_lock_data(dssfx,size);
  118. // convert raw data and header from Doom sfx to a SAMPLE for Allegro
  119. return (void *)raw2SAMPLE (dssfx, size);
  120. }
  121. void I_FreeSfx (sfxinfo_t* sfx)
  122. {
  123. byte* dssfx;
  124. if (sfx->lumpnum<0)
  125. return;
  126. // free sample data
  127. if( sfx->data )
  128. {
  129. dssfx = (byte*) ((SAMPLE *)sfx->data)->data - 8;
  130. Z_Free (dssfx);
  131. // Allegro SAMPLE structure
  132. Z_Free (sfx->data);
  133. }
  134. sfx->data = NULL;
  135. sfx->lumpnum = -1;
  136. }
  137. void I_SetSfxVolume(int volume)
  138. {
  139. if(nosoundfx)
  140. return;
  141. set_volume (cv_soundvolume.value*255/31,-1);
  142. }
  143. // MUSIC API - dummy. Some code from DOS version.
  144. void I_SetMusicVolume(int volume)
  145. {
  146. if(nomusic)
  147. return;
  148. // Now set volume on output device.
  149. set_volume (-1, cv_musicvolume.value*255/31);
  150. }
  151. //
  152. // Starting a sound means adding it
  153. // to the current list of active sounds
  154. // in the internal channels.
  155. // As the SFX info struct contains
  156. // e.g. a pointer to the raw data,
  157. // it is ignored.
  158. // As our sound handling does not handle
  159. // priority, it is ignored.
  160. // Pitching (that is, increased speed of playback)
  161. // is set, but currently not used by mixing.
  162. //
  163. int I_StartSound ( int id,
  164. int vol,
  165. int sep,
  166. int pitch,
  167. int priority )
  168. {
  169. int voice;
  170. if(nosoundfx)
  171. return 0;
  172. // UNUSED
  173. priority = 0;
  174. pitch=(pitch-128)/2+128;
  175. voice=play_sample(S_sfx[id].data,vol,sep,(pitch*1000)/128,0);
  176. // Returns a handle
  177. return (id<<VOICESSHIFT)+voice;
  178. }
  179. void I_StopSound (int handle)
  180. {
  181. // You need the handle returned by StartSound.
  182. // Would be looping all channels,
  183. // tracking down the handle,
  184. // an setting the channel to zero.
  185. int voice=handle & (VIRTUAL_VOICES-1);
  186. if(nosoundfx)
  187. return;
  188. if(voice_check(voice)==S_sfx[handle>>VOICESSHIFT].data)
  189. deallocate_voice(voice);
  190. }
  191. int I_SoundIsPlaying(int handle)
  192. {
  193. if(nosoundfx)
  194. return FALSE;
  195. if(voice_check(handle & (VIRTUAL_VOICES-1))==S_sfx[handle>>VOICESSHIFT].data)
  196. return TRUE;
  197. return FALSE;
  198. }
  199. //
  200. // This function loops all active (internal) sound
  201. // channels, retrieves a given number of samples
  202. // from the raw sound data, modifies it according
  203. // to the current (internal) channel parameters,
  204. // mixes the per channel samples into the global
  205. // mixbuffer, clamping it to the allowed range,
  206. // and sets up everything for transferring the
  207. // contents of the mixbuffer to the (two)
  208. // hardware channels (left and right, that is).
  209. //
  210. // allegro does this now
  211. //
  212. void I_UpdateSound( void )
  213. {
  214. }
  215. //
  216. // This would be used to write out the mixbuffer
  217. // during each game loop update.
  218. // Updates sound buffer and audio device at runtime.
  219. // It is called during Timer interrupt with SNDINTR.
  220. // Mixing now done synchronous, and
  221. // only output be done asynchronous?
  222. //
  223. void I_SubmitSound( void )
  224. {
  225. //this should no longer be necessary cuz allegro is doing all the sound mixing now
  226. }
  227. // cut and past from ALLEGRO he don't share it :(
  228. static inline int absolute_freq(int freq, SAMPLE *spl)
  229. {
  230. if (freq == 1000)
  231. return spl->freq;
  232. else
  233. return (spl->freq * freq) / 1000;
  234. }
  235. void I_UpdateSoundParams( int handle,
  236. int vol,
  237. int sep,
  238. int pitch)
  239. {
  240. // I fail too see that this is used.
  241. // Would be using the handle to identify
  242. // on which channel the sound might be active,
  243. // and resetting the channel parameters.
  244. int voice=handle & (VIRTUAL_VOICES-1);
  245. int numsfx=handle>>VOICESSHIFT;
  246. if(nosoundfx)
  247. return;
  248. if(voice_check(voice)==S_sfx[numsfx].data)
  249. {
  250. voice_set_volume(voice, vol);
  251. voice_set_pan(voice, sep);
  252. voice_set_frequency(voice, absolute_freq(pitch*1000/128
  253. , S_sfx[numsfx].data));
  254. }
  255. }
  256. void I_ShutdownSound(void)
  257. {
  258. // Wait till all pending sounds are finished.
  259. //added:03-01-98:
  260. if( !sound_started )
  261. return;
  262. //added:08-01-98: remove_sound() explicitly because we don't use
  263. // Allegro's allegro_exit();
  264. remove_sound();
  265. sound_started = false;
  266. }
  267. void I_StartupSound()
  268. {
  269. int sfxcard,midicard;
  270. char err[255];
  271. if (nosoundfx)
  272. sfxcard=DIGI_NONE;
  273. else
  274. sfxcard=DIGI_AUTODETECT;
  275. if (nomusic)
  276. midicard=MIDI_NONE;
  277. else
  278. midicard=MIDI_AUTODETECT; //DetectMusicCard();
  279. // Secure and configure sound device first.
  280. CONS_Printf("I_StartupSound: ");
  281. //Fab:25-04-98:note:install_sound will check for sound settings
  282. // in the sound.cfg or allegro.cfg, in the current directory,
  283. // or the directory pointed by 'ALLEGRO' env var.
  284. if (install_sound(sfxcard,midicard,NULL)!=0)
  285. {
  286. sprintf (err,"Sound init error : %s\n",allegro_error);
  287. CONS_Error (err);
  288. nosoundfx=true;
  289. }
  290. else
  291. CONS_Printf(" configured audio device\n" );
  292. //added:08-01-98:we use a similar startup/shutdown scheme as Allegro.
  293. I_AddExitFunc(I_ShutdownSound);
  294. sound_started = true;
  295. }
  296. //
  297. // MUSIC API.
  298. // Still no music done.
  299. // Remains. Dummies.
  300. //
  301. MIDI* currsong; //im assuming only 1 song will be played at once
  302. static int islooping=0;
  303. static int musicdies=-1;
  304. int music_started=0;
  305. char* musicbuffer;
  306. /* load_midi_mem:
  307. * Loads a standard MIDI file from memory, returning a pointer to
  308. * a MIDI structure, * or NULL on error.
  309. * It is the load_midi from Allegro modified to load it from memory
  310. */
  311. MIDI *load_midi_mem(char *mempointer,int *e)
  312. {
  313. int c;
  314. long data=0;
  315. char *fp;
  316. MIDI *midi;
  317. int num_tracks=0;
  318. fp = mempointer;
  319. if (!fp)
  320. return NULL;
  321. midi = malloc(sizeof(MIDI)); /* get some memory */
  322. if (!midi)
  323. return NULL;
  324. for (c=0; c<MIDI_TRACKS; c++) {
  325. midi->track[c].data = NULL;
  326. midi->track[c].len = 0;
  327. }
  328. fp+=4+4; // header size + 'chunk' size
  329. swab(fp,&data,2); // convert to intel-endian
  330. fp+=2; /* MIDI file type */
  331. if ((data != 0) && (data != 1)) // only type 0 and 1 are suported
  332. return NULL;
  333. swab(fp,&num_tracks,2); /* number of tracks */
  334. fp+=2;
  335. if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS))
  336. return NULL;
  337. swab(fp,&data,2); /* beat divisions */
  338. fp+=2;
  339. midi->divisions = ABS(data);
  340. for (c=0; c<num_tracks; c++) { /* read each track */
  341. if (memcmp(fp, "MTrk", 4))
  342. return NULL;
  343. fp+=4;
  344. // swab(fp,&data,4); don't work !!!!??
  345. ((char *)&data)[0]=fp[3];
  346. ((char *)&data)[1]=fp[2];
  347. ((char *)&data)[2]=fp[1];
  348. ((char *)&data)[3]=fp[0];
  349. fp+=4;
  350. midi->track[c].len = data;
  351. midi->track[c].data=fp;
  352. fp+=data;
  353. }
  354. lock_midi(midi);
  355. return midi;
  356. }
  357. #define MIDBUFFERSIZE 128*1024L
  358. void I_InitMusic(void)
  359. {
  360. if(nomusic)
  361. return;
  362. // initialisation of midicard by I_StartupSound
  363. musicbuffer=(char *)Z_Malloc(MIDBUFFERSIZE,PU_STATIC,NULL);
  364. _go32_dpmi_lock_data(musicbuffer,MIDBUFFERSIZE);
  365. I_AddExitFunc(I_ShutdownMusic);
  366. music_started = true;
  367. }
  368. void I_ShutdownMusic(void)
  369. {
  370. if( !music_started )
  371. return;
  372. I_StopSong(1);
  373. music_started=false;
  374. }
  375. void I_PlaySong(int handle, int looping)
  376. {
  377. if(nomusic)
  378. return;
  379. islooping=looping;
  380. musicdies = gametic + TICRATE*30;
  381. play_midi(currsong,looping);
  382. }
  383. void I_PauseSong (int handle)
  384. {
  385. if(nomusic)
  386. return;
  387. midi_pause();
  388. }
  389. void I_ResumeSong (int handle)
  390. {
  391. if(nomusic)
  392. return;
  393. midi_resume();
  394. }
  395. void I_StopSong(int handle)
  396. {
  397. if(nomusic)
  398. return;
  399. islooping = 0;
  400. musicdies = 0;
  401. stop_midi();
  402. }
  403. // Is the song playing?
  404. int I_QrySongPlaying(int handle)
  405. {
  406. if(nomusic)
  407. return 0;
  408. //return islooping || musicdies > gametic;
  409. return (midi_pos==-1);
  410. }
  411. void I_UnRegisterSong(int handle)
  412. {
  413. if(nomusic)
  414. return;
  415. // destroy_midi(currsong);
  416. }
  417. int I_RegisterSong(void* data,int len)
  418. {
  419. int e;
  420. ULONG midlenght;
  421. if(nomusic)
  422. return 1;
  423. if(memcmp(data,"MUS",3)==0)
  424. {
  425. // convert mus to mid with a wonderfull function
  426. // thanks to S.Bacquet for the source of qmus2mid
  427. // convert mus to mid and load it in memory
  428. if((e=qmus2mid((char *)data,musicbuffer,89,64,0,len,MIDBUFFERSIZE,&midlenght))!=0)
  429. {
  430. CONS_Printf("Cannot convert mus to mid, converterror :%d\n",e);
  431. return 0;
  432. }
  433. currsong=load_midi_mem(musicbuffer,&e);
  434. }
  435. else
  436. // supprot mid file in WAD !!!
  437. if(memcmp(data,"MThd",4)==0)
  438. {
  439. currsong=load_midi_mem(data,&e);
  440. }
  441. else
  442. {
  443. CONS_Printf("Music Lump is not MID or MUS lump\n");
  444. return 0;
  445. }
  446. if(currsong==NULL)
  447. {
  448. CONS_Printf("Not a valid mid file : %d\n",e);
  449. return 0;
  450. }
  451. return 1;
  452. }
  453. //Hurdler: TODO
  454. void I_StartFMODSong()
  455. {
  456. CONS_Printf("I_StartFMODSong: Not yet supported under DOS.\n");
  457. }
  458. void I_StopFMODSong()
  459. {
  460. CONS_Printf("I_StopFMODSong: Not yet supported under DOS.\n");
  461. }
  462. void I_SetFMODVolume(int volume)
  463. {
  464. CONS_Printf("I_SetFMODVolume: Not yet supported under DOS.\n");
  465. }