PCFX.C 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. Copyright (C) 1994-1995 Apogee Software, Ltd.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. /**********************************************************************
  16. module: PCFX.C
  17. author: James R. Dose
  18. date: April 1, 1994
  19. Low level routines to support PC sound effects created by Muse.
  20. (c) Copyright 1994 James R. Dose. All Rights Reserved.
  21. **********************************************************************/
  22. #include <dos.h>
  23. #include <stdlib.h>
  24. #include <conio.h>
  25. #include "dpmi.h"
  26. #include "task_man.h"
  27. #include "interrup.h"
  28. #include "pcfx.h"
  29. #define TRUE ( 1 == 1 )
  30. #define FALSE ( !TRUE )
  31. static void PCFX_Service( task *Task );
  32. static long PCFX_LengthLeft;
  33. static char *PCFX_Sound = NULL;
  34. static int PCFX_LastSample;
  35. static short PCFX_Lookup[ 256 ];
  36. static int PCFX_UseLookupFlag = FALSE;
  37. static int PCFX_Priority;
  38. static unsigned long PCFX_CallBackVal;
  39. static void ( *PCFX_CallBackFunc )( unsigned long ) = NULL;
  40. static int PCFX_TotalVolume = PCFX_MaxVolume;
  41. static task *PCFX_ServiceTask = NULL;
  42. static int PCFX_VoiceHandle = PCFX_MinVoiceHandle;
  43. int PCFX_Installed = FALSE;
  44. int PCFX_ErrorCode = PCFX_Ok;
  45. #define PCFX_SetErrorCode( status ) \
  46. PCFX_ErrorCode = ( status );
  47. /*---------------------------------------------------------------------
  48. Function: PCFX_ErrorString
  49. Returns a pointer to the error message associated with an error
  50. number. A -1 returns a pointer the current error.
  51. ---------------------------------------------------------------------*/
  52. char *PCFX_ErrorString
  53. (
  54. int ErrorNumber
  55. )
  56. {
  57. char *ErrorString;
  58. switch( ErrorNumber )
  59. {
  60. case PCFX_Warning :
  61. case PCFX_Error :
  62. ErrorString = PCFX_ErrorString( PCFX_ErrorCode );
  63. break;
  64. case PCFX_Ok :
  65. ErrorString = "PC FX ok.";
  66. break;
  67. case PCFX_NoVoices :
  68. ErrorString = "No free voices available to PC FX.";
  69. break;
  70. case PCFX_VoiceNotFound :
  71. ErrorString = "No voice with matching handle found.";
  72. break;
  73. case PCFX_DPMI_Error :
  74. ErrorString = "DPMI Error in PCFX.";
  75. break;
  76. default :
  77. ErrorString = "Unknown PC FX error code.";
  78. break;
  79. }
  80. return( ErrorString );
  81. }
  82. /**********************************************************************
  83. Memory locked functions:
  84. **********************************************************************/
  85. #define PCFX_LockStart PCFX_Stop
  86. /*---------------------------------------------------------------------
  87. Function: PCFX_Stop
  88. Halts playback of the currently playing sound effect.
  89. ---------------------------------------------------------------------*/
  90. int PCFX_Stop
  91. (
  92. int handle
  93. )
  94. {
  95. unsigned flags;
  96. if ( ( handle != PCFX_VoiceHandle ) || ( PCFX_Sound == NULL ) )
  97. {
  98. PCFX_SetErrorCode( PCFX_VoiceNotFound );
  99. return( PCFX_Warning );
  100. }
  101. flags = DisableInterrupts();
  102. // Turn off speaker
  103. outp( 0x61, inp( 0x61 ) & 0xfc );
  104. PCFX_Sound = NULL;
  105. PCFX_LengthLeft = 0;
  106. PCFX_Priority = 0;
  107. PCFX_LastSample = 0;
  108. RestoreInterrupts( flags );
  109. if ( PCFX_CallBackFunc )
  110. {
  111. PCFX_CallBackFunc( PCFX_CallBackVal );
  112. }
  113. return( PCFX_Ok );
  114. }
  115. /*---------------------------------------------------------------------
  116. Function: PCFX_Service
  117. Task Manager routine to perform the playback of a sound effect.
  118. ---------------------------------------------------------------------*/
  119. static void PCFX_Service
  120. (
  121. task *Task
  122. )
  123. {
  124. unsigned value;
  125. if ( PCFX_Sound )
  126. {
  127. if ( PCFX_UseLookupFlag )
  128. {
  129. value = PCFX_Lookup[ *PCFX_Sound ];
  130. PCFX_Sound++;
  131. }
  132. else
  133. {
  134. value = *( short int * )PCFX_Sound;
  135. PCFX_Sound += sizeof( short int );
  136. }
  137. if ( ( PCFX_TotalVolume > 0 ) && ( value != PCFX_LastSample ) )
  138. {
  139. PCFX_LastSample = value;
  140. if ( value )
  141. {
  142. outp( 0x43, 0xb6 );
  143. outp( 0x42, value );
  144. outp( 0x42, value >> 8 );
  145. outp( 0x61, inp( 0x61 ) | 0x3 );
  146. }
  147. else
  148. {
  149. outp( 0x61, inp( 0x61 ) & 0xfc );
  150. }
  151. }
  152. if ( --PCFX_LengthLeft == 0 )
  153. {
  154. PCFX_Stop( PCFX_VoiceHandle );
  155. }
  156. }
  157. }
  158. /*---------------------------------------------------------------------
  159. Function: PCFX_VoiceAvailable
  160. Checks if a voice can be play at the specified priority.
  161. ---------------------------------------------------------------------*/
  162. int PCFX_VoiceAvailable
  163. (
  164. int priority
  165. )
  166. {
  167. if ( priority < PCFX_Priority )
  168. {
  169. return( FALSE );
  170. }
  171. return( TRUE );
  172. }
  173. /*---------------------------------------------------------------------
  174. Function: PCFX_Play
  175. Starts playback of a Muse sound effect.
  176. ---------------------------------------------------------------------*/
  177. int PCFX_Play
  178. (
  179. PCSound *sound,
  180. int priority,
  181. unsigned long callbackval
  182. )
  183. {
  184. unsigned flags;
  185. if ( priority < PCFX_Priority )
  186. {
  187. PCFX_SetErrorCode( PCFX_NoVoices );
  188. return( PCFX_Warning );
  189. }
  190. PCFX_Stop( PCFX_VoiceHandle );
  191. PCFX_VoiceHandle++;
  192. if ( PCFX_VoiceHandle < PCFX_MinVoiceHandle )
  193. {
  194. PCFX_VoiceHandle = PCFX_MinVoiceHandle;
  195. }
  196. flags = DisableInterrupts();
  197. PCFX_LengthLeft = sound->length;
  198. if ( !PCFX_UseLookupFlag )
  199. {
  200. PCFX_LengthLeft >>= 1;
  201. }
  202. PCFX_Priority = priority;
  203. PCFX_Sound = &sound->data;
  204. PCFX_CallBackVal = callbackval;
  205. RestoreInterrupts( flags );
  206. return( PCFX_VoiceHandle );
  207. }
  208. /*---------------------------------------------------------------------
  209. Function: PCFX_SoundPlaying
  210. Checks if a sound effect is currently playing.
  211. ---------------------------------------------------------------------*/
  212. int PCFX_SoundPlaying
  213. (
  214. int handle
  215. )
  216. {
  217. int status;
  218. status = FALSE;
  219. if ( ( handle == PCFX_VoiceHandle ) && ( PCFX_LengthLeft > 0 ) )
  220. {
  221. status = TRUE;
  222. }
  223. return( status );
  224. }
  225. /*---------------------------------------------------------------------
  226. Function: PCFX_SetTotalVolume
  227. Sets the total volume of the sound effects.
  228. ---------------------------------------------------------------------*/
  229. int PCFX_SetTotalVolume
  230. (
  231. int volume
  232. )
  233. {
  234. unsigned flags;
  235. flags = DisableInterrupts();
  236. volume = max( volume, 0 );
  237. volume = min( volume, PCFX_MaxVolume );
  238. PCFX_TotalVolume = volume;
  239. if ( volume == 0 )
  240. {
  241. outp( 0x61, inp( 0x61 ) & 0xfc );
  242. }
  243. RestoreInterrupts( flags );
  244. return( PCFX_Ok );
  245. }
  246. /*---------------------------------------------------------------------
  247. Function: PCFX_GetTotalVolume
  248. Returns the total volume of the sound effects.
  249. ---------------------------------------------------------------------*/
  250. int PCFX_GetTotalVolume
  251. (
  252. void
  253. )
  254. {
  255. return( PCFX_TotalVolume );
  256. }
  257. /*---------------------------------------------------------------------
  258. Function: PCFX_LockEnd
  259. Used for determining the length of the functions to lock in memory.
  260. ---------------------------------------------------------------------*/
  261. static void PCFX_LockEnd
  262. (
  263. void
  264. )
  265. {
  266. }
  267. /*---------------------------------------------------------------------
  268. Function: PCFX_UseLookup
  269. Sets up a pitch lookup table for PC sound effects.
  270. ---------------------------------------------------------------------*/
  271. void PCFX_UseLookup
  272. (
  273. int use,
  274. unsigned value
  275. )
  276. {
  277. int pitch;
  278. int index;
  279. PCFX_Stop( PCFX_VoiceHandle );
  280. PCFX_UseLookupFlag = use;
  281. if ( use )
  282. {
  283. pitch = 0;
  284. for( index = 0; index < 256; index++ )
  285. {
  286. PCFX_Lookup[ index ] = pitch;
  287. pitch += value;
  288. }
  289. }
  290. }
  291. /*---------------------------------------------------------------------
  292. Function: PCFX_SetCallBack
  293. Set the function to call when a voice stops.
  294. ---------------------------------------------------------------------*/
  295. void PCFX_SetCallBack
  296. (
  297. void ( *function )( unsigned long )
  298. )
  299. {
  300. PCFX_CallBackFunc = function;
  301. }
  302. /*---------------------------------------------------------------------
  303. Function: PCFX_Init
  304. Initializes the sound effect engine.
  305. ---------------------------------------------------------------------*/
  306. int PCFX_Init
  307. (
  308. void
  309. )
  310. {
  311. int status;
  312. if ( PCFX_Installed )
  313. {
  314. PCFX_Shutdown();
  315. }
  316. status = PCFX_LockMemory();
  317. if ( status != PCFX_Ok )
  318. {
  319. PCFX_UnlockMemory();
  320. return( status );
  321. }
  322. PCFX_UseLookup( TRUE, 60 );
  323. PCFX_Stop( PCFX_VoiceHandle );
  324. PCFX_ServiceTask = TS_ScheduleTask( &PCFX_Service, 140, 2, NULL );
  325. TS_Dispatch();
  326. PCFX_CallBackFunc = NULL;
  327. PCFX_Installed = TRUE;
  328. PCFX_SetErrorCode( PCFX_Ok );
  329. return( PCFX_Ok );
  330. }
  331. /*---------------------------------------------------------------------
  332. Function: PCFX_Shutdown
  333. Ends the use of the sound effect engine.
  334. ---------------------------------------------------------------------*/
  335. int PCFX_Shutdown
  336. (
  337. void
  338. )
  339. {
  340. if ( PCFX_Installed )
  341. {
  342. PCFX_Stop( PCFX_VoiceHandle );
  343. TS_Terminate( PCFX_ServiceTask );
  344. PCFX_UnlockMemory();
  345. PCFX_Installed = FALSE;
  346. }
  347. PCFX_SetErrorCode( PCFX_Ok );
  348. return( PCFX_Ok );
  349. }
  350. /*---------------------------------------------------------------------
  351. Function: PCFX_UnlockMemory
  352. Unlocks all neccessary data.
  353. ---------------------------------------------------------------------*/
  354. void PCFX_UnlockMemory
  355. (
  356. void
  357. )
  358. {
  359. DPMI_UnlockMemoryRegion( PCFX_LockStart, PCFX_LockEnd );
  360. DPMI_Unlock( PCFX_LengthLeft );
  361. DPMI_Unlock( PCFX_Sound );
  362. DPMI_Unlock( PCFX_LastSample );
  363. DPMI_Unlock( PCFX_Lookup );
  364. DPMI_Unlock( PCFX_UseLookupFlag );
  365. DPMI_Unlock( PCFX_Priority );
  366. DPMI_Unlock( PCFX_CallBackVal );
  367. DPMI_Unlock( PCFX_CallBackFunc );
  368. DPMI_Unlock( PCFX_TotalVolume );
  369. DPMI_Unlock( PCFX_ServiceTask );
  370. DPMI_Unlock( PCFX_VoiceHandle );
  371. DPMI_Unlock( PCFX_Installed );
  372. DPMI_Unlock( PCFX_ErrorCode );
  373. }
  374. /*---------------------------------------------------------------------
  375. Function: PCFX_LockMemory
  376. Locks all neccessary data.
  377. ---------------------------------------------------------------------*/
  378. int PCFX_LockMemory
  379. (
  380. void
  381. )
  382. {
  383. int status;
  384. status = DPMI_LockMemoryRegion( PCFX_LockStart, PCFX_LockEnd );
  385. status |= DPMI_Lock( PCFX_LengthLeft );
  386. status |= DPMI_Lock( PCFX_Sound );
  387. status |= DPMI_Lock( PCFX_LastSample );
  388. status |= DPMI_Lock( PCFX_Lookup );
  389. status |= DPMI_Lock( PCFX_UseLookupFlag );
  390. status |= DPMI_Lock( PCFX_Priority );
  391. status |= DPMI_Lock( PCFX_CallBackVal );
  392. status |= DPMI_Lock( PCFX_CallBackFunc );
  393. status |= DPMI_Lock( PCFX_TotalVolume );
  394. status |= DPMI_Lock( PCFX_ServiceTask );
  395. status |= DPMI_Lock( PCFX_VoiceHandle );
  396. status |= DPMI_Lock( PCFX_Installed );
  397. status |= DPMI_Lock( PCFX_ErrorCode );
  398. if ( status != DPMI_Ok )
  399. {
  400. PCFX_UnlockMemory();
  401. PCFX_SetErrorCode( PCFX_DPMI_Error );
  402. return( PCFX_Error );
  403. }
  404. return( PCFX_Ok );
  405. }