SNDSRC.C 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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: SNDSRC.C
  17. author: James R. Dose
  18. date: March 26, 1994
  19. Low level routines to support the Disney Sound Source.
  20. (c) Copyright 1994 James R. Dose. All Rights Reserved.
  21. **********************************************************************/
  22. #define STEREO 1
  23. #define SIXTEEN_BIT 2
  24. #define MONO_8BIT 0
  25. #define STEREO_8BIT ( STEREO )
  26. #define MONO_16BIT ( SIXTEEN_BIT )
  27. #define STEREO_16BIT ( STEREO | SIXTEEN_BIT )
  28. #include <stdlib.h>
  29. #include <dos.h>
  30. #include <conio.h>
  31. #include "dpmi.h"
  32. #include "task_man.h"
  33. #include "sndcards.h"
  34. #include "user.h"
  35. #include "sndsrc.h"
  36. #define TRUE ( 1 == 1 )
  37. #define FALSE ( !TRUE )
  38. static int SS_Installed = FALSE;
  39. static int SS_Port = SS_DefaultPort;
  40. static int SS_OffCommand = 0xc;
  41. static char *SS_BufferStart;
  42. static char *SS_BufferEnd;
  43. static char *SS_CurrentBuffer;
  44. static int SS_BufferNum = 0;
  45. static int SS_NumBuffers = 0;
  46. static int SS_TotalBufferSize = 0;
  47. static int SS_TransferLength = 0;
  48. static int SS_CurrentLength = 0;
  49. static char *SS_SoundPtr;
  50. volatile int SS_SoundPlaying;
  51. static task *SS_Timer;
  52. void ( *SS_CallBack )( void );
  53. int SS_ErrorCode = SS_Ok;
  54. #define SS_SetErrorCode( status ) \
  55. SS_ErrorCode = ( status );
  56. /*---------------------------------------------------------------------
  57. Function: SS_ErrorString
  58. Returns a pointer to the error message associated with an error
  59. number. A -1 returns a pointer the current error.
  60. ---------------------------------------------------------------------*/
  61. char *SS_ErrorString
  62. (
  63. int ErrorNumber
  64. )
  65. {
  66. char *ErrorString;
  67. switch( ErrorNumber )
  68. {
  69. case SS_Error :
  70. ErrorString = SS_ErrorString( SS_ErrorCode );
  71. break;
  72. case SS_Ok :
  73. ErrorString = "Sound Source ok.";
  74. break;
  75. case SS_NotFound :
  76. ErrorString = "Could not detect Sound Source.";
  77. break;
  78. case SS_NoSoundPlaying :
  79. ErrorString = "No sound playing in SndSrc.";
  80. break;
  81. case SS_DPMI_Error :
  82. ErrorString = "DPMI Error in SndSrc.";
  83. break;
  84. default :
  85. ErrorString = "Unknown Sound Source error code.";
  86. break;
  87. }
  88. return( ErrorString );
  89. }
  90. /**********************************************************************
  91. Memory locked functions:
  92. **********************************************************************/
  93. #define SS_LockStart SS_ServiceInterrupt
  94. /*---------------------------------------------------------------------
  95. Function: SS_ServiceInterrupt
  96. Handles interrupt generated by sound card at the end of a voice
  97. transfer. Calls the user supplied callback function.
  98. ---------------------------------------------------------------------*/
  99. static void SS_ServiceInterrupt
  100. (
  101. task *Task
  102. )
  103. {
  104. int port = SS_Port;
  105. int count;
  106. count = 0;
  107. while( ( inp( port + 1 ) & 0x40 ) == 0 )
  108. {
  109. outp( port, *SS_SoundPtr++ );
  110. outp( port + 2, SS_OffCommand );
  111. outp( port + 2, 4 );
  112. SS_CurrentLength--;
  113. if ( SS_CurrentLength == 0 )
  114. {
  115. // Keep track of current buffer
  116. SS_CurrentBuffer += SS_TransferLength;
  117. SS_BufferNum++;
  118. if ( SS_BufferNum >= SS_NumBuffers )
  119. {
  120. SS_BufferNum = 0;
  121. SS_CurrentBuffer = SS_BufferStart;
  122. }
  123. SS_CurrentLength = SS_TransferLength;
  124. SS_SoundPtr = SS_CurrentBuffer;
  125. // Call the caller's callback function
  126. if ( SS_CallBack != NULL )
  127. {
  128. SS_CallBack();
  129. }
  130. }
  131. count++;
  132. // Only do at most 14 samples per tick
  133. if ( count > 13 )
  134. {
  135. break;
  136. }
  137. }
  138. }
  139. /*---------------------------------------------------------------------
  140. Function: SS_StopPlayback
  141. Ends the transfer of digitized sound to the Sound Source.
  142. ---------------------------------------------------------------------*/
  143. void SS_StopPlayback
  144. (
  145. void
  146. )
  147. {
  148. if ( SS_SoundPlaying )
  149. {
  150. TS_Terminate( SS_Timer );
  151. outp( SS_Port, 0x80 );
  152. outp( SS_Port + 2, SS_OffCommand );
  153. outp( SS_Port + 2, 4 );
  154. SS_SoundPlaying = FALSE;
  155. SS_BufferStart = NULL;
  156. }
  157. }
  158. /*---------------------------------------------------------------------
  159. Function: SS_GetCurrentPos
  160. Returns the offset within the current sound being played.
  161. ---------------------------------------------------------------------*/
  162. int SS_GetCurrentPos
  163. (
  164. void
  165. )
  166. {
  167. int offset;
  168. if ( !SS_SoundPlaying )
  169. {
  170. SS_SetErrorCode( SS_NoSoundPlaying );
  171. return( SS_Warning );
  172. }
  173. offset = ( int )( ( ( unsigned long )SS_SoundPtr ) -
  174. ( ( unsigned long )SS_CurrentBuffer ) );
  175. return( offset );
  176. }
  177. /*---------------------------------------------------------------------
  178. Function: SS_LockEnd
  179. Used for determining the length of the functions to lock in memory.
  180. ---------------------------------------------------------------------*/
  181. static void SS_LockEnd
  182. (
  183. void
  184. )
  185. {
  186. }
  187. /*---------------------------------------------------------------------
  188. Function: SS_BeginBufferedPlayback
  189. Begins multibuffered playback of digitized sound on the Sound Source.
  190. ---------------------------------------------------------------------*/
  191. int SS_BeginBufferedPlayback
  192. (
  193. char *BufferStart,
  194. int BufferSize,
  195. int NumDivisions,
  196. void ( *CallBackFunc )( void )
  197. )
  198. {
  199. if ( SS_SoundPlaying )
  200. {
  201. SS_StopPlayback();
  202. }
  203. SS_SetCallBack( CallBackFunc );
  204. SS_BufferStart = BufferStart;
  205. SS_CurrentBuffer = BufferStart;
  206. SS_SoundPtr = BufferStart;
  207. SS_TotalBufferSize = BufferSize;
  208. SS_BufferEnd = BufferStart + BufferSize;
  209. SS_TransferLength = BufferSize / NumDivisions;
  210. SS_CurrentLength = SS_TransferLength;
  211. SS_BufferNum = 0;
  212. SS_NumBuffers = NumDivisions;
  213. SS_SoundPlaying = TRUE;
  214. // SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 438, 1, NULL );
  215. SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 510, 1, NULL );
  216. TS_Dispatch();
  217. return( SS_Ok );
  218. }
  219. /*---------------------------------------------------------------------
  220. Function: SS_GetPlaybackRate
  221. Returns the rate at which the digitized sound will be played in
  222. hertz.
  223. ---------------------------------------------------------------------*/
  224. int SS_GetPlaybackRate
  225. (
  226. void
  227. )
  228. {
  229. return( SS_SampleRate );
  230. }
  231. /*---------------------------------------------------------------------
  232. Function: SS_SetMixMode
  233. Sets the sound card to play samples in mono or stereo.
  234. ---------------------------------------------------------------------*/
  235. int SS_SetMixMode
  236. (
  237. int mode
  238. )
  239. {
  240. mode = MONO_8BIT;
  241. return( mode );
  242. }
  243. /*---------------------------------------------------------------------
  244. Function: SS_SetPort
  245. Selects which port to use to write to the Sound Source.
  246. ---------------------------------------------------------------------*/
  247. int SS_SetPort
  248. (
  249. int port
  250. )
  251. {
  252. if ( SS_Installed )
  253. {
  254. SS_Shutdown();
  255. }
  256. SS_Port = port;
  257. return( SS_Ok );
  258. }
  259. /*---------------------------------------------------------------------
  260. Function: SS_SetCallBack
  261. Specifies the user function to call at the end of a sound transfer.
  262. ---------------------------------------------------------------------*/
  263. void SS_SetCallBack
  264. (
  265. void ( *func )( void )
  266. )
  267. {
  268. SS_CallBack = func;
  269. }
  270. /*---------------------------------------------------------------------
  271. Function: SS_TestTimer
  272. Used as a delay in SS_TestSoundSource.
  273. ---------------------------------------------------------------------*/
  274. void SS_TestTimer
  275. (
  276. task *Task
  277. )
  278. {
  279. ( *( int * )( Task->data ) )++;
  280. }
  281. /*---------------------------------------------------------------------
  282. Function: SS_TestSoundSource
  283. Detect if the Sound Source is located at the specified port.
  284. ---------------------------------------------------------------------*/
  285. int SS_TestSoundSource
  286. (
  287. int port
  288. )
  289. {
  290. int present;
  291. task *timer;
  292. volatile int ticks;
  293. int i;
  294. present = FALSE;
  295. timer = TS_ScheduleTask( SS_TestTimer, 140, 1, &ticks );
  296. TS_Dispatch();
  297. outp( port + 2, 4 );
  298. ticks = 0;
  299. while( ticks < 4 )
  300. {
  301. // Do nothing for a while
  302. }
  303. TS_Terminate( timer );
  304. if ( ( inp( port + 1 ) & 0x40 ) == 0 )
  305. {
  306. for( i = 32; i > 0; i-- )
  307. {
  308. outp( port, 0x80 );
  309. outp( port + 2, SS_OffCommand );
  310. outp( port + 2, 4 );
  311. }
  312. if ( inp( port + 1 ) & 0x40 )
  313. {
  314. present = TRUE;
  315. }
  316. }
  317. outp( port + 2, SS_OffCommand );
  318. return( present );
  319. }
  320. /*---------------------------------------------------------------------
  321. Function: SS_DetectSoundSource
  322. Detects which port the Sound Source is located.
  323. ---------------------------------------------------------------------*/
  324. int SS_DetectSoundSource
  325. (
  326. void
  327. )
  328. {
  329. if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT1 ) )
  330. {
  331. SS_Port = SS_Port1;
  332. return( TRUE );
  333. }
  334. if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT2 ) )
  335. {
  336. SS_Port = SS_Port2;
  337. return( TRUE );
  338. }
  339. if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT3 ) )
  340. {
  341. SS_Port = SS_Port3;
  342. return( TRUE );
  343. }
  344. if ( SS_TestSoundSource( SS_Port1 ) )
  345. {
  346. SS_Port = SS_Port1;
  347. return( TRUE );
  348. }
  349. if ( SS_TestSoundSource( SS_Port2 ) )
  350. {
  351. SS_Port = SS_Port2;
  352. return( TRUE );
  353. }
  354. if ( SS_TestSoundSource( SS_Port3 ) )
  355. {
  356. SS_Port = SS_Port3;
  357. return( TRUE );
  358. }
  359. return( FALSE );
  360. }
  361. /*---------------------------------------------------------------------
  362. Function: SS_Init
  363. Initializes the Sound Source prepares the module to play digitized
  364. sounds.
  365. ---------------------------------------------------------------------*/
  366. int SS_Init
  367. (
  368. int soundcard
  369. )
  370. {
  371. int status;
  372. if ( SS_Installed )
  373. {
  374. SS_Shutdown();
  375. }
  376. if ( ( soundcard == TandySoundSource ) ||
  377. ( USER_CheckParameter( SELECT_TANDY_SOUNDSOURCE ) ) )
  378. {
  379. // Tandy
  380. SS_OffCommand = 0x0e;
  381. }
  382. else
  383. {
  384. // Disney
  385. SS_OffCommand = 0x0c;
  386. }
  387. status = SS_DetectSoundSource();
  388. if ( !status )
  389. {
  390. SS_SetErrorCode( SS_NotFound );
  391. return( SS_Warning );
  392. }
  393. status = SS_LockMemory();
  394. if ( status != SS_Ok )
  395. {
  396. SS_UnlockMemory();
  397. return( status );
  398. }
  399. status = SS_Ok;
  400. outp( SS_Port + 2, 4 );
  401. SS_SoundPlaying = FALSE;
  402. SS_SetCallBack( NULL );
  403. SS_BufferStart = NULL;
  404. SS_Installed = TRUE;
  405. SS_SetErrorCode( status );
  406. return( status );
  407. }
  408. /*---------------------------------------------------------------------
  409. Function: SS_Shutdown
  410. Ends transfer of sound data to the Sound Source.
  411. ---------------------------------------------------------------------*/
  412. void SS_Shutdown
  413. (
  414. void
  415. )
  416. {
  417. // Halt the transfer
  418. SS_StopPlayback();
  419. outp( SS_Port + 2, SS_OffCommand );
  420. SS_SoundPlaying = FALSE;
  421. SS_BufferStart = NULL;
  422. SS_SetCallBack( NULL );
  423. SS_UnlockMemory();
  424. SS_Installed = FALSE;
  425. }
  426. /*---------------------------------------------------------------------
  427. Function: SS_UnlockMemory
  428. Unlocks all neccessary data.
  429. ---------------------------------------------------------------------*/
  430. void SS_UnlockMemory
  431. (
  432. void
  433. )
  434. {
  435. DPMI_UnlockMemoryRegion( SS_LockStart, SS_LockEnd );
  436. DPMI_Unlock( SS_Installed );
  437. DPMI_Unlock( SS_Port );
  438. DPMI_Unlock( SS_OffCommand );
  439. DPMI_Unlock( SS_BufferStart );
  440. DPMI_Unlock( SS_BufferEnd );
  441. DPMI_Unlock( SS_CurrentBuffer );
  442. DPMI_Unlock( SS_BufferNum );
  443. DPMI_Unlock( SS_NumBuffers );
  444. DPMI_Unlock( SS_TotalBufferSize );
  445. DPMI_Unlock( SS_TransferLength );
  446. DPMI_Unlock( SS_CurrentLength );
  447. DPMI_Unlock( SS_SoundPtr );
  448. DPMI_Unlock( SS_SoundPlaying );
  449. DPMI_Unlock( SS_Timer );
  450. DPMI_Unlock( SS_CallBack );
  451. DPMI_Unlock( SS_ErrorCode );
  452. }
  453. /*---------------------------------------------------------------------
  454. Function: SS_LockMemory
  455. Locks all neccessary data.
  456. ---------------------------------------------------------------------*/
  457. int SS_LockMemory
  458. (
  459. void
  460. )
  461. {
  462. int status;
  463. status = DPMI_LockMemoryRegion( SS_LockStart, SS_LockEnd );
  464. status |= DPMI_Lock( SS_Installed );
  465. status |= DPMI_Lock( SS_Port );
  466. status |= DPMI_Lock( SS_OffCommand );
  467. status |= DPMI_Lock( SS_BufferStart );
  468. status |= DPMI_Lock( SS_BufferEnd );
  469. status |= DPMI_Lock( SS_CurrentBuffer );
  470. status |= DPMI_Lock( SS_BufferNum );
  471. status |= DPMI_Lock( SS_NumBuffers );
  472. status |= DPMI_Lock( SS_TotalBufferSize );
  473. status |= DPMI_Lock( SS_TransferLength );
  474. status |= DPMI_Lock( SS_CurrentLength );
  475. status |= DPMI_Lock( SS_SoundPtr );
  476. status |= DPMI_Lock( SS_SoundPlaying );
  477. status |= DPMI_Lock( SS_Timer );
  478. status |= DPMI_Lock( SS_CallBack );
  479. status |= DPMI_Lock( SS_ErrorCode );
  480. if ( status != DPMI_Ok )
  481. {
  482. SS_UnlockMemory();
  483. SS_SetErrorCode( SS_DPMI_Error );
  484. return( SS_Error );
  485. }
  486. return( SS_Ok );
  487. }