PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/v1.14.104/gameio/loadsounds.cpp

https://github.com/simX/d2x-xl
C++ | 495 lines | 394 code | 62 blank | 39 comment | 81 complexity | b67eaf162d4d687b815a3f44dc1a107a MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  11. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
  12. */
  13. #ifdef HAVE_CONFIG_H
  14. #include <conf.h>
  15. #endif
  16. #ifdef _WIN32
  17. # include <windows.h>
  18. #endif
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include "pstypes.h"
  23. #include "strutil.h"
  24. #include "descent.h"
  25. #include "gr.h"
  26. #include "u_mem.h"
  27. #include "iff.h"
  28. #include "mono.h"
  29. #include "error.h"
  30. #include "sounds.h"
  31. #include "songs.h"
  32. #include "loadgamedata.h"
  33. #include "bmread.h"
  34. #include "hash.h"
  35. #include "args.h"
  36. #include "palette.h"
  37. #include "gamefont.h"
  38. #include "rle.h"
  39. #include "screens.h"
  40. #include "piggy.h"
  41. #include "gamemine.h"
  42. #include "textures.h"
  43. #include "texmerge.h"
  44. #include "paging.h"
  45. #include "game.h"
  46. #include "text.h"
  47. #include "cfile.h"
  48. #include "menu.h"
  49. #include "byteswap.h"
  50. #include "findfile.h"
  51. #include "makesig.h"
  52. #include "effects.h"
  53. #include "wall.h"
  54. #include "weapon.h"
  55. #include "error.h"
  56. #include "grdef.h"
  57. #include "gamepal.h"
  58. //#define NO_DUMP_SOUNDS 1 //if set, dump bitmaps but not sounds
  59. int RequestCD (void);
  60. extern char CDROM_dir [];
  61. CHashTable soundNames [2];
  62. static tSoundFile sounds [2][MAX_SOUND_FILES];
  63. static int nSoundFilesNew = 0;
  64. //------------------------------------------------------------------------------
  65. /*
  66. * reads a tPIGSoundHeader structure from a CFile
  67. */
  68. void PIGSoundHeaderRead (tPIGSoundHeader *dsh, CFile& cf)
  69. {
  70. cf.Read (dsh->name, 8, 1);
  71. dsh->length = cf.ReadInt ();
  72. dsh->data_length = cf.ReadInt ();
  73. dsh->offset = cf.ReadInt ();
  74. }
  75. //------------------------------------------------------------------------------
  76. void PiggyInitSound (void)
  77. {
  78. memset (gameData.pig.sound.sounds, 0, sizeof (gameData.pig.sound.sounds));
  79. }
  80. //------------------------------------------------------------------------------
  81. int PiggyRegisterSound (char *szFileName, int bFromFile, bool bCustom)
  82. {
  83. int i = gameData.pig.sound.nSoundFiles [gameStates.app.bD1Mission];
  84. Assert (i < MAX_SOUND_FILES);
  85. strncpy (sounds [gameStates.app.bD1Mission][i].name, szFileName, 12);
  86. soundNames [gameStates.app.bD1Mission].Insert (sounds [gameStates.app.bD1Mission][i].name, i);
  87. if (!bFromFile)
  88. nSoundFilesNew++;
  89. (gameData.pig.sound.nSoundFiles [gameStates.app.bD1Mission])++;
  90. return i;
  91. }
  92. //------------------------------------------------------------------------------
  93. int PiggyFindSound (const char * name)
  94. {
  95. int i = soundNames [gameStates.app.bD1Mission].Search (name);
  96. if (i < 0)
  97. return -1;
  98. return i;
  99. }
  100. //------------------------------------------------------------------------------
  101. void FreeSoundReplacements (void)
  102. {
  103. CSoundSample *dsP;
  104. int i, j;
  105. PrintLog ("unloading custom sounds\n");
  106. for (i = 0; i < 2; i++)
  107. for (j = 0, dsP = gameData.pig.sound.sounds [i].Buffer (); j < MAX_SOUND_FILES; j++, dsP++)
  108. if (dsP->bCustom) {
  109. dsP->data [1].Destroy ();
  110. dsP->bCustom = 0;
  111. }
  112. }
  113. //------------------------------------------------------------------------------
  114. int LoadSoundReplacements (const char *pszFilename)
  115. {
  116. CFile cf;
  117. char szId [4];
  118. int nLoadedSounds;
  119. int i, j, l;
  120. int b11K = (gameOpts->sound.audioSampleRate == SAMPLE_RATE_11K);
  121. tPIGSoundHeader dsh;
  122. CSoundSample* dsP;
  123. size_t nHeaderOffs, nDataOffs;
  124. char szFilename [SHORT_FILENAME_LEN];
  125. if (gameOpts->sound.bHires [0])
  126. return -1;
  127. //first, free up data allocated for old bitmaps
  128. PrintLog (" loading replacement sounds\n");
  129. //FreeSoundReplacements ();
  130. CFile::ChangeFilenameExtension (szFilename, pszFilename, ".dtx");
  131. if (!cf.Open (szFilename, gameFolders.szDataDir, "rb", 0))
  132. return -1;
  133. if (cf.Read (szId, 1, sizeof (szId)) != sizeof (szId)) {
  134. cf.Close ();
  135. return -1;
  136. }
  137. if (strncmp (szId, "DTX2", sizeof (szId))) {
  138. cf.Close ();
  139. return -1;
  140. }
  141. nLoadedSounds = cf.ReadInt ();
  142. if (!b11K)
  143. nLoadedSounds *= 2;
  144. nHeaderOffs = cf.Tell ();
  145. nDataOffs = nHeaderOffs + nLoadedSounds * sizeof (tPIGSoundHeader);
  146. for (i = b11K ? 0 : nLoadedSounds / 2; i < nLoadedSounds; i++) {
  147. cf.Seek ((long) (nHeaderOffs + i * sizeof (tPIGSoundHeader)), SEEK_SET);
  148. PIGSoundHeaderRead (&dsh, cf);
  149. j = PiggyFindSound (dsh.name);
  150. if (j < 0)
  151. continue;
  152. dsP = gameData.pig.sound.sounds [gameStates.app.bD1Mission] + j;
  153. l = dsh.length;
  154. if (!dsP->data [1].Create (l))
  155. continue;
  156. cf.Seek ((long) (nDataOffs + dsh.offset), SEEK_SET);
  157. if (dsP->data [1].Read (cf, l) != (size_t) l) {
  158. cf.Close ();
  159. dsP->data [1].Destroy ();
  160. return -1;
  161. }
  162. dsP->bCustom = 1;
  163. dsP->nLength [1] = l;
  164. }
  165. cf.Close ();
  166. return 1;
  167. }
  168. //------------------------------------------------------------------------------
  169. int LoadHiresSound (CSoundSample* soundP, char* pszSoundName, bool bCustom)
  170. {
  171. CFile cf;
  172. char szSoundFile [FILENAME_LEN];
  173. sprintf (szSoundFile, "%s.wav", pszSoundName);
  174. if (!((*gameFolders.szSoundDir [5] && cf.Open (szSoundFile, gameFolders.szSoundDir [5], "rb", 0)) ||
  175. (*gameFolders.szSoundDir [4] && cf.Open (szSoundFile, gameFolders.szSoundDir [4], "rb", 0)) ||
  176. ((bCustom || gameOpts->sound.bHires [0]) && cf.Open (szSoundFile, gameFolders.szSoundDir [HIRES_SOUND_FOLDER (gameStates.sound.bD1Sound)], "rb", 0))))
  177. return 0;
  178. if (0 >= (soundP->nLength [0] = cf.Length ())) {
  179. cf.Close ();
  180. return 0;
  181. }
  182. if (!soundP->data [0].Create (soundP->nLength [0])) {
  183. cf.Close ();
  184. return 0;
  185. }
  186. if (soundP->data [0].Read (cf, soundP->nLength [0]) != uint (soundP->nLength [0])) {
  187. soundP->data [0].Destroy ();
  188. soundP->nLength [0] = 0;
  189. cf.Close ();
  190. return 0;
  191. }
  192. cf.Close ();
  193. soundP->bHires = 1;
  194. return 1;
  195. }
  196. //------------------------------------------------------------------------------
  197. int SetupSounds (CFile& cf, int nSounds, int nSoundStart, bool bCustom, bool bUseLowRes)
  198. {
  199. tPIGSoundHeader sndh;
  200. CSoundSample* soundP;
  201. int i, j;
  202. int nHeaderSize = nSounds * sizeof (tPIGSoundHeader);
  203. char szSoundName [16];
  204. int nLoadedSounds [2] = {0, 0};
  205. /*---*/PrintLog (" Loading sound data (%d sounds)\n", nSounds);
  206. cf.Seek (nSoundStart, SEEK_SET);
  207. #if USE_OPENAL
  208. memset (&sound.buffer, 0xFF, sizeof (sound.buffer));
  209. #endif
  210. if (!bCustom) {
  211. gameData.pig.sound.nSoundFiles [gameStates.app.bD1Mission] = 0;
  212. soundNames [gameStates.app.bD1Mission].Destroy ();
  213. soundNames [gameStates.app.bD1Mission].Create (MAX_SOUND_FILES);
  214. }
  215. for (i = 0; i < nSounds; i++) {
  216. PIGSoundHeaderRead (&sndh, cf);
  217. memcpy (szSoundName, sndh.name, 8);
  218. szSoundName [8] = 0;
  219. if (0 > (j = bCustom ? PiggyFindSound (szSoundName) : i))
  220. continue;
  221. soundP = &gameData.pig.sound.soundP [j];
  222. if (!bUseLowRes && LoadHiresSound (soundP, szSoundName, bCustom)) {
  223. nLoadedSounds [1]++;
  224. soundP->nOffset [0] = 0;
  225. }
  226. else {
  227. soundP->bHires = 0;
  228. soundP->nLength [0] = sndh.length;
  229. soundP->data [0].Create (sndh.length);
  230. soundP->nOffset [0] = sndh.offset + nHeaderSize + nSoundStart;
  231. nLoadedSounds [0]++;
  232. }
  233. memcpy (soundP->szName, szSoundName, sizeof (soundP->szName));
  234. soundP->bCustom = 0;
  235. if (!bCustom)
  236. PiggyRegisterSound (szSoundName, 1, bCustom);
  237. }
  238. return (nLoadedSounds [1] << 16) | nLoadedSounds [0];
  239. }
  240. //------------------------------------------------------------------------------
  241. int PiggySoundIsNeeded (int nSound)
  242. {
  243. #if 1
  244. return 1;
  245. #else
  246. int i;
  247. if (!gameStates.sound.audio.bLoMem)
  248. return 1;
  249. for (i = 0; i < MAX_SOUNDS; i++) {
  250. if ((AltSounds [gameStates.app.bD1Mission][i] < 255) && (Sounds [gameStates.app.bD1Mission][AltSounds [gameStates.app.bD1Mission][i]] == nSound))
  251. return 1;
  252. }
  253. return 0;
  254. #endif
  255. }
  256. //------------------------------------------------------------------------------
  257. #if USE_OPENAL
  258. int PiggyBufferSound (CSoundSample *soundP)
  259. {
  260. if (!gameOpts->sound.bUseOpenAL)
  261. return 0;
  262. if (soundP->buffer != 0xFFFFFFFF) {
  263. alDeleteBuffers (1, &soundP->buffer);
  264. soundP->buffer = 0xFFFFFFFF;
  265. }
  266. alGenBuffers (1, &soundP->buffer);
  267. if (alGetError () != AL_NO_ERROR) {
  268. soundP->buffer = 0xFFFFFFFF;
  269. gameOpts->sound.bUseOpenAL = 0;
  270. return 0;
  271. }
  272. alBufferData (soundP->buffer, AL_FORMAT_MONO8, soundP->data [0], soundP->nLength [0], gameOpts->sound.audioSampleRate);
  273. if (alGetError () != AL_NO_ERROR) {
  274. gameOpts->sound.bUseOpenAL = 0;
  275. return 0;
  276. }
  277. return 1;
  278. }
  279. #endif
  280. //------------------------------------------------------------------------------
  281. void LoadSounds (CFile& cf, bool bCustom)
  282. {
  283. CSoundSample* soundP = &gameData.pig.sound.soundP [0];
  284. for (int i = gameData.pig.sound.nSoundFiles [gameStates.app.bD1Mission]; i; i--, soundP++) {
  285. if (soundP->nOffset [bCustom] > 0) {
  286. //if (PiggySoundIsNeeded (i))
  287. {
  288. cf.Seek (soundP->nOffset [bCustom], SEEK_SET);
  289. soundP->data [bCustom].Read (cf, soundP->nLength [bCustom]);
  290. #if USE_OPENAL
  291. PiggyBufferSound (soundP);
  292. #endif
  293. }
  294. }
  295. }
  296. }
  297. //------------------------------------------------------------------------------
  298. int LoadD2Sounds (bool bCustom)
  299. {
  300. if (!(gameData.pig.sound.nType || bCustom))
  301. return 1;
  302. CFile cf;
  303. int sndId, sndVersion;
  304. int nSounds;
  305. int nLoadedSounds;
  306. bool bUseLowRes = false;
  307. char szFile [FILENAME_LEN];
  308. char* pszFile, * pszFolder;
  309. if (gameStates.app.bNostalgia)
  310. gameOpts->sound.bHires [0] = 0;
  311. else
  312. gameOpts->sound.bHires [0] = gameOpts->sound.bHires [1];
  313. if (bCustom) {
  314. if (!*gameFolders.szModName)
  315. return 0;
  316. sprintf (szFile, "%s%s", gameFolders.szModName, (gameOpts->sound.audioSampleRate >= SAMPLE_RATE_22K) ? ".s22" : ".s11");
  317. pszFile = szFile;
  318. pszFolder = gameFolders.szModDir [1];
  319. if (!(bUseLowRes = cf.Exist (pszFile, pszFolder, 0) != 0)) {
  320. pszFile = DefaultSoundFile ();
  321. pszFolder = gameFolders.szDataDir;
  322. if (gameData.missions.nCurrentLevel < 0)
  323. sprintf (gameFolders.szSoundDir [5], "%s/slevel%02d", gameFolders.szSoundDir [4], -gameData.missions.nCurrentLevel);
  324. else
  325. sprintf (gameFolders.szSoundDir [5], "%s/level%02d", gameFolders.szSoundDir [4], gameData.missions.nCurrentLevel);
  326. }
  327. }
  328. else {
  329. pszFile = DefaultSoundFile ();
  330. pszFolder = gameFolders.szDataDir;
  331. }
  332. if (!cf.Open (pszFile, pszFolder, "rb", 0))
  333. return 0;
  334. if (gameStates.app.bDemoData)
  335. gameOpts->sound.soundSampleRate = SAMPLE_RATE_11K;
  336. else {
  337. //make sure soundfile is valid nType file & is up-to-date
  338. sndId = cf.ReadInt ();
  339. sndVersion = cf.ReadInt ();
  340. if ((sndId != SNDFILE_ID) || (sndVersion != SNDFILE_VERSION)) {
  341. cf.Close (); //out of date sound file
  342. return 0;
  343. }
  344. nSounds = cf.ReadInt ();
  345. nLoadedSounds = SetupSounds (cf, nSounds, cf.Tell (), bCustom, bUseLowRes);
  346. if (bCustom)
  347. gameOpts->sound.bHires [0] = (nLoadedSounds & 0xffff) ? 0 : 2;
  348. else if (gameOpts->sound.bHires [0] && ((nLoadedSounds >> 16) < nSounds))
  349. gameOpts->sound.bHires [0] = 0;
  350. }
  351. LoadSounds (cf, false);
  352. cf.Close ();
  353. return nLoadedSounds != 0;
  354. }
  355. //------------------------------------------------------------------------------
  356. #if USE_SDL_MIXER
  357. # ifdef __macosx__
  358. # include <SDL_mixer/SDL_mixer.h>
  359. # else
  360. # include <SDL_mixer.h>
  361. # endif
  362. tAddonSound addonSounds [MAX_ADDON_SOUND_FILES] = {
  363. {NULL, "00:missileflight-small.wav"},
  364. {NULL, "01:missileflight-big.wav"},
  365. {NULL, "02:vulcan-firing.wav"},
  366. {NULL, "03:gauss-firing.wav"},
  367. {NULL, "04:gatling-speedup.wav"},
  368. {NULL, "05:flareburning.wav"},
  369. {NULL, "06:lowping.wav"},
  370. {NULL, "07:highping.wav"},
  371. {NULL, "08:lightning.wav"},
  372. {NULL, "09:slowdown.wav"},
  373. {NULL, "10:speedup.wav"},
  374. {NULL, "11:airbubbles.wav"},
  375. {NULL, "12:zoom1.wav"},
  376. {NULL, "13:zoom2.wav"},
  377. {NULL, "14:headlight.wav"}
  378. };
  379. //------------------------------------------------------------------------------
  380. const char *AddonSoundName (int nSound)
  381. {
  382. return ((nSound < 0) || (nSound >= MAX_ADDON_SOUND_FILES)) ? "" : addonSounds [nSound].szSoundFile;
  383. }
  384. //------------------------------------------------------------------------------
  385. Mix_Chunk *LoadAddonSound (const char *pszSoundFile, ubyte *bBuiltIn)
  386. {
  387. Mix_Chunk *chunkP;
  388. char szWAV [FILENAME_LEN];
  389. int i;
  390. CFile cf;
  391. if (!::isdigit (*pszSoundFile))
  392. i = -1;
  393. else {
  394. i = atoi (pszSoundFile);
  395. if (i >= MAX_ADDON_SOUND_FILES)
  396. return NULL;
  397. if (bBuiltIn)
  398. *bBuiltIn = 1;
  399. if ((chunkP = addonSounds [i].chunkP))
  400. return chunkP;
  401. pszSoundFile += 3;
  402. }
  403. if (!(cf.Extract (pszSoundFile, gameFolders.szDataDir, 0, "d2x-temp.wav") ||
  404. cf.Extract (pszSoundFile, gameFolders.szSoundDir [HIRES_SOUND_FOLDER (gameStates.sound.bD1Sound)], 0, "d2x-temp.wav")))
  405. return NULL;
  406. sprintf (szWAV, "%s%sd2x-temp.wav", gameFolders.szCacheDir, *gameFolders.szCacheDir ? "/" : "");
  407. if (!(chunkP = Mix_LoadWAV (szWAV)))
  408. return NULL;
  409. if (i >= 0)
  410. addonSounds [i].chunkP = chunkP;
  411. if (bBuiltIn)
  412. *bBuiltIn = (i >= 0);
  413. return chunkP;
  414. }
  415. //------------------------------------------------------------------------------
  416. void LoadAddonSounds (void)
  417. {
  418. for (int i = 0; i < int (sizeofa (addonSounds)); i++)
  419. LoadAddonSound (AddonSoundName (i));
  420. }
  421. //------------------------------------------------------------------------------
  422. void FreeAddonSounds (void)
  423. {
  424. for (int i = 0; i < MAX_ADDON_SOUND_FILES; i++) {
  425. if (addonSounds [i].chunkP) {
  426. Mix_FreeChunk (addonSounds [i].chunkP);
  427. addonSounds [i].chunkP = NULL;
  428. }
  429. }
  430. }
  431. #endif
  432. //------------------------------------------------------------------------------
  433. //eof