Changeset 21358 for trunk/src/winmm/waveoutdart.cpp
- Timestamp:
- Feb 22, 2010, 2:44:21 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/winmm/waveoutdart.cpp
r10525 r21358 15 15 */ 16 16 17 18 /**************************************************************************** 19 * Includes * 20 ****************************************************************************/ 21 22 17 /******************************************************************************/ 18 // Includes 19 /******************************************************************************/ 23 20 24 21 #define INCL_BASE … … 41 38 #include "dbglocal.h" 42 39 40 /******************************************************************************/ 41 43 42 #ifndef min 44 43 #define min(a, b) ((a > b) ? b : a) … … 51 50 LONG APIENTRY WaveOutHandler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags); 52 51 53 static BOOL fFixedWaveBufferSize = FALSE; 52 #define DART_BUFCNT 64 53 #define DART_BUFSIZE 4096 54 55 /******************************************************************************/ 54 56 55 57 //#define DEBUG_DUMP_PCM … … 67 69 #endif 68 70 69 //****************************************************************************** 71 /******************************************************************************/ 72 73 static BOOL fFixedWaveBufferSize = FALSE; 74 75 /******************************************************************************/ 70 76 // ODIN_waveOutSetFixedBuffers 71 77 // … … 76 82 // purpose solution. 77 83 // 78 //****************************************************************************** 84 /******************************************************************************/ 85 79 86 void WIN32API ODIN_waveOutSetFixedBuffers() 80 87 { 81 88 fFixedWaveBufferSize = TRUE; 82 89 } 83 /******************************************************************************/ 84 /******************************************************************************/ 90 91 /******************************************************************************/ 92 /******************************************************************************/ 93 85 94 DartWaveOut::DartWaveOut(LPWAVEFORMATEX pwfx, ULONG fdwOpen, ULONG nCallback, ULONG dwInstance) 86 95 : WaveOut(pwfx, fdwOpen, nCallback, dwInstance) 87 96 { 88 MCI_GENERIC_PARMS GenericParms; 97 DeviceId = 0; 98 fMixerSetup = FALSE; 99 fUnderrun = FALSE; 100 curFillBuf = 0; 101 curPlayBuf = 0; 102 curFillPos = 0; 103 curPlayPos = 0; 104 ulBufSize = DART_BUFSIZE; 105 ulBufCount = DART_BUFCNT; 106 bytesPlayed = 0; 107 bytesCopied = 0; 108 bytesReturned = 0; 109 ulUnderrunBase = 0; 110 mixHandle = 0; 111 curhdr = NULL; 112 pmixWriteProc = 0; 113 MixBuffer = 0; 114 BufferParms = 0; 115 } 116 117 /******************************************************************************/ 118 /******************************************************************************/ 119 120 DartWaveOut::~DartWaveOut() 121 { 122 MCI_GENERIC_PARMS GenericParms = {0}; 123 124 State = STATE_STOPPED; 125 126 #ifdef DEBUG_DUMP_PCM 127 if (pcmfile) fclose(pcmfile); 128 #endif 129 130 if (DeviceId) { 131 // Stop the playback. 132 mymciSendCommand(DeviceId, MCI_STOP, 133 MCI_WAIT, 134 (PVOID)&GenericParms,0); 135 136 if (fMixerSetup) 137 mymciSendCommand(DeviceId, MCI_BUFFER, 138 MCI_WAIT | MCI_DEALLOCATE_MEMORY, 139 (PVOID)&BufferParms, 0); 140 141 // Close the device 142 mymciSendCommand(DeviceId, MCI_CLOSE, 143 MCI_WAIT, 144 (PVOID)&GenericParms, 0); 145 146 callback(WOM_CLOSE, 0, 0); 147 } 148 149 if (MixBuffer) 150 free(MixBuffer); 151 if (BufferParms) 152 free(BufferParms); 153 } 154 155 /******************************************************************************/ 156 /******************************************************************************/ 157 158 MMRESULT DartWaveOut::open() 159 { 89 160 MCI_AMP_OPEN_PARMS AmpOpenParms; 161 MCI_GENERIC_PARMS GenericParms = {0}; 162 MCI_MIXSETUP_PARMS MixSetupParms; 90 163 APIRET rc; 91 164 92 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0; 93 fMixerSetup = FALSE; 94 fUnderrun = FALSE; 95 ulUnderrunBase= 0; 96 97 ulBufSize = DART_BUFSIZE; 98 99 MixBuffer = (MCI_MIX_BUFFER *)malloc(PREFILLBUF_DART*sizeof(MCI_MIX_BUFFER)); 100 MixSetupParms = (MCI_MIXSETUP_PARMS *)malloc(sizeof(MCI_MIXSETUP_PARMS)); 165 MixBuffer = (MCI_MIX_BUFFER *)malloc(ulBufCount*sizeof(MCI_MIX_BUFFER)); 101 166 BufferParms = (MCI_BUFFER_PARMS *)malloc(sizeof(MCI_BUFFER_PARMS)); 102 if (!MixBuffer || !MixSetupParms|| !BufferParms) {167 if (!MixBuffer || !BufferParms) { 103 168 dprintf(("ERROR: malloc failed!!")); 104 ulError = MMSYSERR_NOMEM; 105 return; 106 } 107 108 // Setup the open structure, pass the playlist and tell MCI_OPEN to use it 109 memset(&AmpOpenParms,0,sizeof(AmpOpenParms)); 110 111 AmpOpenParms.usDeviceID = ( USHORT ) 0; 112 AmpOpenParms.pszDeviceType = ( PSZ ) MCI_DEVTYPE_AUDIO_AMPMIX; 113 114 rc = mymciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE, 115 (PVOID) &AmpOpenParms, 0); 116 117 DeviceId = AmpOpenParms.usDeviceID; 118 if(rc) { 169 return MMSYSERR_NOMEM; 170 } 171 172 // Setup the open structure, then open the device 173 memset(&AmpOpenParms, 0, sizeof(AmpOpenParms)); 174 AmpOpenParms.usDeviceID = 0; 175 AmpOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX; 176 177 rc = mymciSendCommand(0, MCI_OPEN, 178 MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE, 179 (PVOID)&AmpOpenParms, 0); 180 if (LOUSHORT(rc) != MCIERR_SUCCESS) { 119 181 dprintf(("MCI_OPEN failed\n")); 120 182 mciError(rc); 121 ulError = MMSYSERR_NODRIVER; 122 } 123 if(rc == 0) { 124 //Grab exclusive rights to device instance (NOT entire device) 125 GenericParms.hwndCallback = 0; //Not needed, so set to 0 126 rc = mymciSendCommand(DeviceId, MCI_ACQUIREDEVICE, MCI_EXCLUSIVE_INSTANCE, 127 (PVOID)&GenericParms, 0); 128 if(rc) { 129 dprintf(("MCI_ACQUIREDEVICE failed\n")); 130 mciError(rc); 131 ulError = MMSYSERR_NOTENABLED; 183 return MMSYSERR_NODRIVER; 184 } 185 DeviceId = AmpOpenParms.usDeviceID; 186 187 // Grab exclusive rights to device instance (NOT entire device) 188 rc = mymciSendCommand(DeviceId, MCI_ACQUIREDEVICE, 189 MCI_EXCLUSIVE_INSTANCE, 190 (PVOID)&GenericParms, 0); 191 if (LOUSHORT(rc) != MCIERR_SUCCESS) { 192 dprintf(("MCI_ACQUIREDEVICE failed\n")); 193 mciError(rc); 194 return MMSYSERR_NOTENABLED; 195 } 196 dprintf(("device acquired\n")); 197 dprintf(("bps %d, sps %d chan %d\n", BitsPerSample, SampleRate, nChannels)); 198 199 // Setup the mixer for playback of wave data 200 memset(&MixSetupParms, 0, sizeof(MixSetupParms)); 201 MixSetupParms.ulBitsPerSample = BitsPerSample; 202 MixSetupParms.ulSamplesPerSec = SampleRate; 203 MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM; 204 MixSetupParms.ulChannels = nChannels; 205 MixSetupParms.ulFormatMode = MCI_PLAY; 206 MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; 207 MixSetupParms.pmixEvent = WaveOutHandler; 208 209 rc = mymciSendCommand(DeviceId, MCI_MIXSETUP, 210 MCI_WAIT | MCI_MIXSETUP_INIT, 211 (PVOID)&MixSetupParms, 0); 212 213 if (LOUSHORT(rc) != MCIERR_SUCCESS) { 214 mciError(rc); 215 mymciSendCommand(DeviceId, MCI_RELEASEDEVICE, 216 MCI_WAIT, 217 (PVOID)&GenericParms, 0); 218 return MMSYSERR_NOTSUPPORTED; 219 } 220 221 // Save the mixer handle & the ptr to the write proc. 222 mixHandle = MixSetupParms.ulMixHandle; 223 pmixWriteProc = MixSetupParms.pmixWrite; 224 225 #ifdef DEBUG_DUMP_PCM 226 REC_STRUCT recinfo; 227 228 pcmfile = fopen("dartpcm.dat", "wb"); 229 recinfo.bits = BitsPerSample; 230 recinfo.rate = SampleRate; 231 recinfo.format = MCI_WAVE_FORMAT_PCM; 232 recinfo.numchan = nChannels; 233 fwrite(&recinfo, sizeof(recinfo), 1, pcmfile); 234 #endif 235 236 setVolume(volume); 237 callback(WOM_OPEN, 0, 0); 238 239 return MMSYSERR_NOERROR; 240 } 241 242 /******************************************************************************/ 243 /******************************************************************************/ 244 245 MMRESULT DartWaveOut::write(LPWAVEHDR pwh, UINT cbwh) 246 { 247 APIRET rc; 248 249 queuedbuffers++; 250 pwh->lpNext = NULL; 251 pwh->reserved = 0; 252 253 // Set up the BufferParms data structure and allocate 254 // device buffers from the Amp-Mixer 255 if (fMixerSetup == FALSE) 256 { 257 ulBufSize = pwh->dwBufferLength; 258 if (!ulBufSize || ulBufSize > 0x10000) 259 return MMSYSERR_INVALPARAM; 260 261 rc = initBuffers(); 262 if (rc != MMSYSERR_NOERROR) 263 return rc; 264 265 curhdr = pwh; 266 fMixerSetup = TRUE; 267 } 268 269 wmutex.enter(); 270 271 if (wavehdr) { 272 WAVEHDR *chdr = wavehdr; 273 while (chdr->lpNext) { 274 #ifdef DEBUG 275 if (chdr == pwh) dprintf(("adding already present buffer!!!!!")); 276 #endif 277 chdr = chdr->lpNext; 132 278 } 133 } 134 setVolume(volume); 135 136 if(!ulError) 137 callback(WOM_OPEN, 0, 0); 138 } 139 /******************************************************************************/ 140 /******************************************************************************/ 141 DartWaveOut::~DartWaveOut() 142 { 143 MCI_GENERIC_PARMS GenericParms; 144 145 State = STATE_STOPPED; 146 147 #ifdef DEBUG_DUMP_PCM 148 if(pcmfile) fclose(pcmfile); 149 #endif 150 151 if(!ulError) { 152 // Generic parameters 153 GenericParms.hwndCallback = 0; //hwndFrame 154 155 // Stop the playback. 156 mymciSendCommand(DeviceId, MCI_STOP,MCI_WAIT, (PVOID)&GenericParms,0); 157 158 mymciSendCommand(DeviceId, MCI_BUFFER, 159 MCI_WAIT | MCI_DEALLOCATE_MEMORY, 160 (PVOID)&BufferParms, 0); 161 162 // Generic parameters 163 GenericParms.hwndCallback = 0; //hwndFrame 164 165 // Close the device 166 mymciSendCommand(DeviceId, MCI_CLOSE, MCI_WAIT, (PVOID)&GenericParms, 0); 167 } 168 169 if(!ulError) 279 chdr->lpNext = pwh; 280 } 281 else wavehdr = pwh; 282 283 //don't start playback if paused 284 if (!fUnderrun && State != STATE_STOPPED) { 285 //write new data to the DART buffers (if there's any room left) 286 if (State == STATE_PLAYING) 287 writeBuffer(); //must be called before (re)starting playback 288 wmutex.leave(); 289 return MMSYSERR_NOERROR; 290 } 291 292 writeBuffer(); //must be called before (re)starting playback 293 State = STATE_PLAYING; 294 fUnderrun = FALSE; 295 wmutex.leave(); 296 297 //write buffers to DART; starts playback 298 dprintf(("WINMM: transfer all buffers to DART")); 299 300 USHORT selTIB = RestoreOS2FS(); // save current FS selector 301 pmixWriteProc(mixHandle, MixBuffer, ulBufCount); 302 SetFS(selTIB); // switch back to the saved FS selector 303 304 dprintf(("Dart playing\n")); 305 306 return MMSYSERR_NOERROR; 307 } 308 309 /******************************************************************************/ 310 /******************************************************************************/ 311 312 MMRESULT DartWaveOut::initBuffers() 313 { 314 APIRET rc; 315 MCI_GENERIC_PARMS GenericParms = {0}; 316 int orgbufsize = ulBufSize; // on entry, ulBufSize == pwh->dwBufferLength 317 318 #if 1 319 //by default we need to select a small enough buffer 320 //to be able to signal buffer completion in time 321 if (fFixedWaveBufferSize == FALSE) 170 322 { 171 callback(WOM_CLOSE, 0, 0); 172 } 173 174 if(MixBuffer) 175 free(MixBuffer); 176 if(MixSetupParms) 177 free(MixSetupParms); 178 if(BufferParms) 179 free(BufferParms); 180 } 181 /******************************************************************************/ 182 /******************************************************************************/ 183 MMRESULT DartWaveOut::write(LPWAVEHDR pwh, UINT cbwh) 184 { 185 MCI_GENERIC_PARMS GenericParms = {0}; 186 APIRET rc; 187 int i, buflength; 188 189 queuedbuffers++; 190 if(fMixerSetup == FALSE) 191 { 192 dprintf(("device acquired\n")); 193 /* Set the MixSetupParms data structure to match the loaded file. 194 * This is a global that is used to setup the mixer. 195 */ 196 memset(MixSetupParms, 0, sizeof( MCI_MIXSETUP_PARMS ) ); 197 198 MixSetupParms->ulBitsPerSample = BitsPerSample; 199 MixSetupParms->ulSamplesPerSec = SampleRate; 200 MixSetupParms->ulFormatTag = MCI_WAVE_FORMAT_PCM; 201 MixSetupParms->ulChannels = nChannels; 202 203 dprintf(("bps %d, sps %d chan %d\n", BitsPerSample, SampleRate, nChannels)); 204 205 #ifdef DEBUG_DUMP_PCM 206 REC_STRUCT recinfo; 207 208 pcmfile = fopen("dartpcm.dat", "wb"); 209 recinfo.bits = BitsPerSample; 210 recinfo.rate = SampleRate; 211 recinfo.format = MCI_WAVE_FORMAT_PCM; 212 recinfo.numchan = nChannels; 213 fwrite(&recinfo, sizeof(recinfo), 1, pcmfile); 214 #endif 215 /* Setup the mixer for playback of wave data 216 */ 217 MixSetupParms->ulFormatMode = MCI_PLAY; 218 MixSetupParms->ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; 219 MixSetupParms->pmixEvent = WaveOutHandler; 220 221 rc = mymciSendCommand(DeviceId, 222 MCI_MIXSETUP, 223 MCI_WAIT | MCI_MIXSETUP_INIT, 224 (PVOID)MixSetupParms, 225 0); 226 227 if ( rc != MCIERR_SUCCESS ) { 228 mciError(rc); 229 mymciSendCommand(DeviceId, MCI_RELEASEDEVICE, MCI_WAIT, 230 (PVOID)&GenericParms, 0); 231 return(MMSYSERR_NOTSUPPORTED); 323 int consumerate = getAvgBytesPerSecond(); 324 int minbufsize = consumerate/32; 325 326 ulBufSize /= 2; 327 if (ulBufSize > minbufsize) { 328 dprintf(("set buffer size to %d bytes (org size = %d)", minbufsize, orgbufsize)); 329 ulBufSize = minbufsize; 232 330 } 233 234 /* 235 * Set up the BufferParms data structure and allocate 236 * device buffers from the Amp-Mixer 237 */ 238 dprintf(("mix setup %d, %d\n", pwh->dwBufferLength, pwh->dwBufferLength)); 239 240 #if 1 241 if(fFixedWaveBufferSize == FALSE) 242 {//by default we need to select a small enough buffer to be able to 243 //signal buffer completion in time 244 int consumerate = getAvgBytesPerSecond(); 245 int minbufsize = consumerate/32; 246 247 ulBufSize = pwh->dwBufferLength/2; 248 if(ulBufSize > minbufsize) { 249 dprintf(("set buffer size to %d bytes (org size = %d)", minbufsize, pwh->dwBufferLength)); 250 ulBufSize = minbufsize; 251 } 252 } 253 else ulBufSize = pwh->dwBufferLength; 331 } 254 332 #else 255 if(pwh->dwBufferLength >= 512 && pwh->dwBufferLength <= 1024) 256 ulBufSize = pwh->dwBufferLength; 257 else ulBufSize = 1024; 258 #endif 259 MixSetupParms->ulBufferSize = ulBufSize; 260 261 BufferParms->ulNumBuffers = PREFILLBUF_DART; 262 BufferParms->ulBufferSize = MixSetupParms->ulBufferSize; 263 BufferParms->pBufList = MixBuffer; 264 265 for(i=0;i<PREFILLBUF_DART;i++) { 266 MixBuffer[i].ulUserParm = (ULONG)this; 267 } 268 269 rc = mymciSendCommand(DeviceId, 270 MCI_BUFFER, 271 MCI_WAIT | MCI_ALLOCATE_MEMORY, 272 (PVOID)BufferParms, 273 0); 274 275 if(ULONG_LOWD(rc) != MCIERR_SUCCESS) { 276 mciError(rc); 277 mymciSendCommand(DeviceId, MCI_RELEASEDEVICE, MCI_WAIT, 278 (PVOID)&GenericParms, 0); 279 return(MMSYSERR_NOTSUPPORTED); 280 } 281 282 wmutex.enter(); 283 fMixerSetup = TRUE; 284 285 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0; 286 bytesPlayed = bytesCopied = bytesReturned = 0; 287 288 for(i=0;i<PREFILLBUF_DART;i++) { 289 memset(MixBuffer[i].pBuffer, 0, MixBuffer[i].ulBufferLength); 290 } 291 dprintf(("Dart opened, bufsize = %d\n", MixBuffer[0].ulBufferLength)); 292 293 wavehdr = pwh; 294 curhdr = pwh; 295 pwh->lpNext = NULL; 296 pwh->reserved = 0; 297 298 if(State != STATE_STOPPED) {//don't start playback if paused 299 wmutex.leave(); 300 return(MMSYSERR_NOERROR); 301 } 302 303 writeBuffer(); //must be called before (re)starting playback 304 305 dprintf(("MixSetupParms = %X\n", MixSetupParms)); 306 State = STATE_PLAYING; 307 fUnderrun = FALSE; 308 wmutex.leave(); 309 310 //write buffers to DART; starts playback 311 dprintf(("WINMM: transfer all buffers to DART")); 312 USHORT selTIB = RestoreOS2FS(); // save current FS selector 313 314 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, 315 MixBuffer, 316 PREFILLBUF_DART); 317 SetFS(selTIB); // switch back to the saved FS selector 318 dprintf(("Dart playing\n")); 319 } 320 else 321 { 322 pwh->lpNext = NULL; 323 pwh->reserved = 0; 324 wmutex.enter(); 325 if(wavehdr) { 326 WAVEHDR *chdr = wavehdr; 327 while(chdr->lpNext) { 328 #ifdef DEBUG 329 if(chdr == pwh) dprintf(("adding already present buffer!!!!!")); 330 #endif 331 chdr = chdr->lpNext; 332 } 333 chdr->lpNext = pwh; 334 } 335 else wavehdr = pwh; 336 337 if(!fUnderrun && State != STATE_STOPPED) {//don't start playback if paused 338 //write new data to the DART buffers (if there's any room left) 339 if(State == STATE_PLAYING) { 340 writeBuffer(); //must be called before (re)starting playback 341 } 342 wmutex.leave(); 343 return(MMSYSERR_NOERROR); 344 } 345 writeBuffer(); //must be called before (re)starting playback 346 State = STATE_PLAYING; 347 fUnderrun = FALSE; 348 wmutex.leave(); 349 350 //write buffers to DART; starts playback 351 dprintf(("WINMM: transfer all buffers to DART")); 352 USHORT selTIB = RestoreOS2FS(); // save current FS selector 353 354 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, 355 MixBuffer, 356 PREFILLBUF_DART); 357 SetFS(selTIB); // switch back to the saved FS selector 358 359 dprintf(("Dart playing\n")); 360 } 361 return(MMSYSERR_NOERROR); 362 } 363 /******************************************************************************/ 364 /******************************************************************************/ 333 if (ulBufSize < 512 || ulBufSize > 1024) 334 ulBufSize = 1024; 335 #endif 336 337 dprintf(("buffer setup - WAVE size = %d, DART size = %d\n", 338 orgbufsize, ulBufSize)); 339 340 BufferParms->ulNumBuffers = ulBufCount; 341 BufferParms->ulBufferSize = ulBufSize; 342 BufferParms->pBufList = MixBuffer; 343 344 rc = mymciSendCommand(DeviceId, MCI_BUFFER, 345 MCI_WAIT | MCI_ALLOCATE_MEMORY, 346 (PVOID)BufferParms, 0); 347 348 if (LOUSHORT(rc) != MCIERR_SUCCESS) { 349 mciError(rc); 350 mymciSendCommand(DeviceId, MCI_RELEASEDEVICE, 351 MCI_WAIT, 352 (PVOID)&GenericParms, 0); 353 return MMSYSERR_NOTSUPPORTED; 354 } 355 356 // DART may not have allocated all the buffers requested. 357 ulBufCount = BufferParms->ulNumBuffers; 358 359 for (int i = 0; i < ulBufCount; i++) { 360 MixBuffer[i].ulUserParm = (ULONG)this; 361 memset(MixBuffer[i].pBuffer, 0, MixBuffer[i].ulBufferLength); 362 } 363 dprintf(("Dart opened, bufsize = %d\n", MixBuffer[0].ulBufferLength)); 364 365 return MMSYSERR_NOERROR; 366 } 367 368 /******************************************************************************/ 369 /******************************************************************************/ 370 365 371 MMRESULT DartWaveOut::pause() 366 372 { 367 MCI_GENERIC_PARMS Params;373 MCI_GENERIC_PARMS GenericParms = {0}; 368 374 369 375 dprintf(("WINMM: DartWaveOut::pause")); 370 376 371 377 wmutex.enter(); 372 if (State != STATE_PLAYING) {378 if (State != STATE_PLAYING) { 373 379 State = STATE_PAUSED; 374 380 wmutex.leave(); 375 return (MMSYSERR_NOERROR);381 return MMSYSERR_NOERROR; 376 382 } 377 383 … … 379 385 wmutex.leave(); 380 386 381 memset(&Params, 0, sizeof(Params));382 383 387 // Pause playback. 384 mymciSendCommand(DeviceId, MCI_PAUSE, MCI_WAIT, (PVOID)&Params, 0); 385 386 return(MMSYSERR_NOERROR); 387 } 388 /******************************************************************************/ 389 /******************************************************************************/ 388 mymciSendCommand(DeviceId, MCI_PAUSE, 389 MCI_WAIT, 390 (PVOID)&GenericParms, 0); 391 392 return MMSYSERR_NOERROR; 393 } 394 395 /******************************************************************************/ 396 /******************************************************************************/ 397 390 398 MMRESULT DartWaveOut::resume() 391 399 { 392 MCI_GENERIC_PARMS Params;393 400 int i, curbuf; 394 401 … … 396 403 397 404 wmutex.enter(); 398 if (State != STATE_PAUSED) {405 if (State != STATE_PAUSED) { 399 406 wmutex.leave(); 400 return (MMSYSERR_NOERROR);407 return MMSYSERR_NOERROR; 401 408 } 402 409 State = STATE_PLAYING; … … 405 412 //Only write buffers to dart if mixer has been initialized; if not, then 406 413 //the first buffer write will do this for us. 407 if (fMixerSetup == TRUE)414 if (fMixerSetup == TRUE) 408 415 { 409 416 wmutex.enter(); 410 417 State = STATE_PLAYING; 411 418 fUnderrun = FALSE; 412 curbuf = curPlayBuf;419 curbuf = curPlayBuf; 413 420 writeBuffer(); //must be called before (re)starting playback 414 421 wmutex.leave(); 415 422 416 // MCI_MIXSETUP_PARMS->pMixWrite does alter FS: selector!417 423 USHORT selTIB = GetFS(); // save current FS selector 418 419 for(i=0;i<PREFILLBUF_DART;i++) 424 for (i = 0; i < ulBufCount; i++) 420 425 { 421 426 dprintf(("restart: write buffer at %x size %d", MixBuffer[curbuf].pBuffer, MixBuffer[curbuf].ulBufferLength)); 422 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, &MixBuffer[curbuf], 1);423 if (++curbuf == PREFILLBUF_DART)427 pmixWriteProc(mixHandle, &MixBuffer[curbuf], 1); 428 if (++curbuf == ulBufCount) 424 429 curbuf = 0; 425 430 } 426 431 SetFS(selTIB); // switch back to the saved FS selector 427 432 } 428 return(MMSYSERR_NOERROR); 429 } 430 /******************************************************************************/ 431 /******************************************************************************/ 433 return MMSYSERR_NOERROR; 434 } 435 436 /******************************************************************************/ 437 /******************************************************************************/ 438 432 439 MMRESULT DartWaveOut::stop() 433 440 { 434 MCI_GENERIC_PARMS Params;441 MCI_GENERIC_PARMS GenericParms = {0}; 435 442 436 443 dprintf(("DartWaveOut::stop %s", (State == STATE_PLAYING) ? "playing" : "stopped")); 437 if(State != STATE_PLAYING) 438 return(MMSYSERR_HANDLEBUSY); 439 440 memset(&Params, 0, sizeof(Params)); 444 if (State != STATE_PLAYING) 445 return MMSYSERR_HANDLEBUSY; 441 446 442 447 // Stop the playback. 443 mymciSendCommand(DeviceId, MCI_STOP, MCI_WAIT, (PVOID)&Params, 0); 448 mymciSendCommand(DeviceId, MCI_STOP, 449 MCI_WAIT, 450 (PVOID)&GenericParms, 0); 444 451 445 452 State = STATE_STOPPED; … … 449 456 bytesPlayed = bytesCopied = bytesReturned = 0; 450 457 451 return(MMSYSERR_NOERROR); 452 } 453 /******************************************************************************/ 454 /******************************************************************************/ 458 return MMSYSERR_NOERROR; 459 } 460 461 /******************************************************************************/ 462 /******************************************************************************/ 463 455 464 MMRESULT DartWaveOut::reset() 456 465 { 457 MCI_GENERIC_PARMS Params;466 MCI_GENERIC_PARMS GenericParms = {0}; 458 467 LPWAVEHDR tmpwavehdr; 459 468 460 469 dprintf(("DartWaveOut::reset %s", (State == STATE_PLAYING) ? "playing" : "stopped")); 461 if(State != STATE_PLAYING) 462 return(MMSYSERR_HANDLEBUSY); 463 464 memset(&Params, 0, sizeof(Params)); 470 if (State != STATE_PLAYING) 471 return MMSYSERR_HANDLEBUSY; 465 472 466 473 wmutex.enter(); … … 469 476 470 477 // Stop the playback. 471 mymciSendCommand(DeviceId, MCI_STOP, MCI_WAIT, (PVOID)&Params, 0); 478 mymciSendCommand(DeviceId, MCI_STOP, 479 MCI_WAIT, 480 (PVOID)&GenericParms, 0); 472 481 473 482 wmutex.enter(); 474 while (wavehdr)483 while (wavehdr) 475 484 { 476 485 wavehdr->dwFlags |= WHDR_DONE; … … 494 503 495 504 wmutex.leave(); 496 return(MMSYSERR_NOERROR); 497 } 498 /******************************************************************************/ 499 /******************************************************************************/ 505 return MMSYSERR_NOERROR; 506 } 507 508 /******************************************************************************/ 509 /******************************************************************************/ 510 500 511 ULONG DartWaveOut::getPosition() 501 512 { 502 MCI_STATUS_PARMS mciStatus = {0};503 ULONG rc, nrbytes;504 505 if (State == STATE_STOPPED) {513 MCI_STATUS_PARMS StatusParms = {0}; 514 ULONG rc, nrbytes; 515 516 if (State == STATE_STOPPED) { 506 517 dprintf(("Not playing; return 0 position")); 507 518 return ulUnderrunBase; 508 519 } 509 520 510 mciStatus.ulItem = MCI_STATUS_POSITION; 511 rc = mymciSendCommand(DeviceId, MCI_STATUS, MCI_STATUS_ITEM|MCI_WAIT, (PVOID)&mciStatus, 0); 512 if((rc & 0xFFFF) == MCIERR_SUCCESS) { 513 nrbytes = (ULONG)(((double)mciStatus.ulReturn * (double)getAvgBytesPerSecond())/1000.0); 514 return ulUnderrunBase+nrbytes; 515 } 516 mciError(rc); 517 return 0xFFFFFFFF; 518 } 519 /******************************************************************************/ 520 /******************************************************************************/ 521 BOOL DartWaveOut::queryFormat(ULONG formatTag, ULONG nChannels, 522 ULONG nSamplesPerSec, ULONG wBitsPerSample) 523 { 524 MCI_WAVE_GETDEVCAPS_PARMS mciAudioCaps; 525 MCI_GENERIC_PARMS GenericParms; 526 MCI_OPEN_PARMS mciOpenParms; /* open parms for MCI_OPEN */ 527 int i, freqbits = 0; 528 ULONG rc, DeviceId; 529 BOOL winrc; 530 531 dprintf(("DartWaveOut::queryFormat %x srate=%d, nchan=%d, bps=%d", formatTag, nSamplesPerSec, nChannels, wBitsPerSample)); 532 533 memset(&mciOpenParms, /* Object to fill with zeros. */ 534 0, /* Value to place into the object. */ 535 sizeof( mciOpenParms ) ); /* How many zero's to use. */ 536 537 mciOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_WAVEFORM_AUDIO; 538 539 rc = mymciSendCommand( (USHORT) 0, 540 MCI_OPEN, 541 MCI_WAIT | MCI_OPEN_TYPE_ID, 542 (PVOID) &mciOpenParms, 543 0); 544 if((rc & 0xFFFF) != MCIERR_SUCCESS) { 521 StatusParms.ulItem = MCI_STATUS_POSITION; 522 rc = mymciSendCommand(DeviceId, MCI_STATUS, 523 MCI_STATUS_ITEM|MCI_WAIT, 524 (PVOID)&StatusParms, 0); 525 if (LOUSHORT(rc) != MCIERR_SUCCESS) { 545 526 mciError(rc); 546 return(FALSE); 547 } 548 DeviceId = mciOpenParms.usDeviceID; 549 550 memset( &mciAudioCaps , 0, sizeof(MCI_WAVE_GETDEVCAPS_PARMS)); 551 552 mciAudioCaps.ulBitsPerSample = wBitsPerSample; 553 mciAudioCaps.ulFormatTag = DATATYPE_WAVEFORM; 554 mciAudioCaps.ulSamplesPerSec = nSamplesPerSec; 555 mciAudioCaps.ulChannels = nChannels; 556 mciAudioCaps.ulFormatMode = MCI_PLAY; 557 mciAudioCaps.ulItem = MCI_GETDEVCAPS_WAVE_FORMAT; 558 559 rc = mymciSendCommand(DeviceId, /* Device ID */ 560 MCI_GETDEVCAPS, 561 MCI_WAIT | MCI_GETDEVCAPS_EXTENDED | MCI_GETDEVCAPS_ITEM, 562 (PVOID) &mciAudioCaps, 563 0); 564 if((rc & 0xFFFF) != MCIERR_SUCCESS) { 527 return 0xFFFFFFFF; 528 } 529 530 nrbytes = (ULONG)(((double)StatusParms.ulReturn * (double)getAvgBytesPerSecond())/1000.0); 531 return (ulUnderrunBase + nrbytes); 532 } 533 534 /******************************************************************************/ 535 /******************************************************************************/ 536 537 MMRESULT DartWaveOut::setVolume(ULONG ulVol) 538 { 539 APIRET rc; 540 ULONG ulVolR = ((ulVol >> 16) * 100) / 0xFFFF; 541 ULONG ulVolL = ((ulVol & 0xffff) * 100) / 0xFFFF; 542 MCI_SET_PARMS SetParms = {0}; 543 544 dprintf(("DartWaveOut::setVolume %d %d", ulVolL, ulVolR)); 545 volume = ulVol; 546 547 // Some drivers can't set left & right volumes independently 548 #ifdef GOOD_AUDIO_CARD_DRIVER 549 SetParms.ulAudio = MCI_SET_AUDIO_LEFT; 550 SetParms.ulLevel = ulVolL; 551 552 rc = mymciSendCommand(DeviceId, MCI_SET, 553 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME, 554 &SetParms, 0); 555 if (LOUSHORT(rc) != MCIERR_SUCCESS) 565 556 mciError(rc); 566 winrc = FALSE; 567 } 568 else winrc = TRUE; 569 570 // Close the device 571 mymciSendCommand(DeviceId,MCI_CLOSE,MCI_WAIT,(PVOID)&GenericParms,0); 572 return(winrc); 573 } 574 /******************************************************************************/ 575 /******************************************************************************/ 576 void DartWaveOut::mciError(ULONG ulError) 557 558 SetParms.ulAudio = MCI_SET_AUDIO_RIGHT; 559 SetParms.ulLevel = ulVolR; 560 #else 561 SetParms.ulAudio = MCI_SET_AUDIO_ALL; 562 SetParms.ulLevel = (ulVolR + ulVolL) / 2; 563 #endif 564 565 rc = mymciSendCommand(DeviceId, MCI_SET, 566 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME, 567 &SetParms, 0); 568 if (LOUSHORT(rc) != MCIERR_SUCCESS) 569 mciError(rc); 570 571 return MMSYSERR_NOERROR; 572 } 573 574 /******************************************************************************/ 575 /******************************************************************************/ 576 577 void DartWaveOut::mciError(ULONG rc) 577 578 { 578 579 #ifdef DEBUG 579 580 char szError[256] = ""; 580 581 581 mymciGetErrorString( ulError, szError, sizeof(szError));582 mymciGetErrorString(rc, szError, sizeof(szError)); 582 583 dprintf(("WINMM: DartWaveOut: %s\n", szError)); 583 584 #endif 584 585 } 586 585 587 //****************************************************************************** 586 588 //****************************************************************************** 589 587 590 void DartWaveOut::handler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) 588 591 { 589 ULONG buflength;590 WAVEHDR *whdr, *prevhdr = NULL;592 ULONG buflength; 593 WAVEHDR *whdr, *prevhdr = NULL; 591 594 592 595 dprintf2(("WINMM: handler %d; buffers left %d", curPlayBuf, queuedbuffers)); 593 if (ulFlags == MIX_STREAM_ERROR) {594 if (ulStatus == ERROR_DEVICE_UNDERRUN) {596 if (ulFlags == MIX_STREAM_ERROR) { 597 if (ulStatus == ERROR_DEVICE_UNDERRUN) { 595 598 dprintf(("WINMM: WaveOut handler UNDERRUN! state %s", (State == STATE_PLAYING) ? "playing" : "stopped")); 596 if (State == STATE_PLAYING) {599 if (State == STATE_PLAYING) { 597 600 fUnderrun = TRUE; 598 601 //save current position for when we continue later … … 605 608 return; 606 609 } 607 if (State != STATE_PLAYING) {610 if (State != STATE_PLAYING) 608 611 return; 609 }610 612 611 613 wmutex.enter(); … … 613 615 bytesPlayed += MixBuffer[curPlayBuf].ulBufferLength; 614 616 615 //update our buffer index 616 if(curPlayBuf == PREFILLBUF_DART-1) 617 curPlayBuf = 0; 618 else curPlayBuf++; 617 // update our buffer index 618 if (++curPlayBuf >= ulBufCount) 619 curPlayBuf = 0; 619 620 620 621 fUnderrun = FALSE; 621 622 622 623 whdr = wavehdr; 623 while(whdr) { 624 if(whdr->reserved == WHDR_DONE) 625 { 626 if(bytesPlayed < bytesReturned + whdr->dwBufferLength) { 627 dprintf2(("Buffer marked done, but not yet played completely (play %d/%d, cop %d, ret %d)", bytesPlayed, getPosition(), bytesCopied, bytesReturned)); 628 break; //not yet done 629 } 630 631 dprintf2(("WINMM: handler buf %X done (play %d/%d, cop %d, ret %d)", whdr, bytesPlayed, getPosition(), bytesCopied, bytesReturned)); 632 queuedbuffers--; 633 634 whdr->dwFlags &= ~WHDR_INQUEUE; 635 whdr->dwFlags |= WHDR_DONE; 636 whdr->reserved = 0; 637 638 if(prevhdr == NULL) 639 wavehdr = whdr->lpNext; 640 else prevhdr->lpNext = whdr->lpNext; 641 642 whdr->lpNext = NULL; 643 644 bytesReturned += whdr->dwBufferLength; 645 wmutex.leave(); 646 647 callback(WOM_DONE, (ULONG)whdr, 0); 648 649 wmutex.enter(); 624 while (whdr) { 625 if (whdr->reserved != WHDR_DONE) 626 break; 627 628 if (bytesPlayed < bytesReturned + whdr->dwBufferLength) { 629 dprintf2(("Buffer marked done, but not yet played completely (play %d/%d, cop %d, ret %d)", bytesPlayed, getPosition(), bytesCopied, bytesReturned)); 630 break; //not yet done 650 631 } 651 else break; 632 633 dprintf2(("WINMM: handler buf %X done (play %d/%d, cop %d, ret %d)", whdr, bytesPlayed, getPosition(), bytesCopied, bytesReturned)); 634 queuedbuffers--; 635 636 whdr->dwFlags &= ~WHDR_INQUEUE; 637 whdr->dwFlags |= WHDR_DONE; 638 whdr->reserved = 0; 639 640 if (prevhdr == NULL) 641 wavehdr = whdr->lpNext; 642 else prevhdr->lpNext = whdr->lpNext; 643 644 whdr->lpNext = NULL; 645 646 bytesReturned += whdr->dwBufferLength; 647 648 wmutex.leave(); 649 callback(WOM_DONE, (ULONG)whdr, 0); 650 wmutex.enter(); 652 651 653 652 prevhdr = whdr; … … 655 654 } 656 655 657 if (wavehdr == NULL) {658 // last buffer played -> no new ones -> return now656 if (wavehdr == NULL) { 657 // last buffer played -> no new ones -> return now 659 658 dprintf(("WINMM: WaveOut handler LAST BUFFER PLAYED! state %s (play %d (%d), cop %d, ret %d)", (State == STATE_PLAYING) ? "playing" : "stopped", bytesPlayed, getPosition(), bytesCopied, bytesReturned)); 660 if (getPosition() > bytesPlayed) {659 if (getPosition() > bytesPlayed) { 661 660 dprintf(("WINMM: WaveOut handler UNDERRUN! state %s", (State == STATE_PLAYING) ? "playing" : "stopped")); 662 661 //save current position for when we continue later … … 671 670 writeBuffer(); 672 671 673 sendbuffer:674 672 wmutex.leave(); 675 673 … … 677 675 dprintf2(("WINMM: handler transfer buffer %d", pBuffer - MixBuffer)); 678 676 USHORT selTIB = RestoreOS2FS(); // save current FS selector 679 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, pBuffer, 1);677 pmixWriteProc(mixHandle, pBuffer, 1); 680 678 SetFS(selTIB); // switch back to the saved FS selector 681 679 682 680 dprintf2(("WINMM: handler DONE")); 683 681 } 684 /******************************************************************************/ 685 /******************************************************************************/ 682 683 /******************************************************************************/ 684 /******************************************************************************/ 685 686 686 void DartWaveOut::writeBuffer() 687 687 { 688 688 ULONG buflength; 689 689 690 if (!fUnderrun && State == STATE_PLAYING && wavehdr == NULL && curFillBuf == curPlayBuf) {690 if (!fUnderrun && State == STATE_PLAYING && wavehdr == NULL && curFillBuf == curPlayBuf) { 691 691 dprintf2(("writeBuffer: no more room for more audio data")); 692 692 return; //no room left 693 693 } 694 694 695 if (curhdr == NULL)695 if (curhdr == NULL) 696 696 curhdr = wavehdr; 697 697 698 while (curhdr && (curhdr->reserved == WHDR_DONE)) {698 while (curhdr && (curhdr->reserved == WHDR_DONE)) { 699 699 curhdr = curhdr->lpNext; 700 700 } 701 701 702 if (curhdr == NULL) {702 if (curhdr == NULL) 703 703 return; //no unprocessed buffers left 704 } 705 706 if(State == STATE_PLAYING && curFillBuf == curPlayBuf) 704 705 if (State == STATE_PLAYING && curFillBuf == curPlayBuf) 707 706 { 708 707 dprintf(("curFillBuf == curPlayBuf; no more room (%d,%d)", curFillBuf, curPlayBuf)); … … 712 711 dprintf2(("WINMM: handler cur (%d,%d), fill (%d,%d)\n", curPlayBuf, curPlayPos, curFillBuf, curFillPos)); 713 712 714 while (curhdr) {713 while (curhdr) { 715 714 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos, 716 715 (ULONG)curhdr->dwBufferLength - curFillPos); … … 727 726 bytesCopied += buflength; 728 727 729 if (curFillPos == curhdr->dwBufferLength) {728 if (curFillPos == curhdr->dwBufferLength) { 730 729 dprintf2(("Buffer %d done ptr %x size %d %x %x %x %x %x %x", curFillBuf, curhdr->lpData, curhdr->dwBufferLength, curhdr->dwBytesRecorded, curhdr->dwUser, curhdr->dwFlags, curhdr->dwLoops, curhdr->lpNext, curhdr->reserved)); 731 730 … … 733 732 curhdr->reserved = WHDR_DONE; 734 733 //search for next unprocessed buffer 735 while (curhdr && (curhdr->reserved == WHDR_DONE))734 while (curhdr && (curhdr->reserved == WHDR_DONE)) 736 735 curhdr = curhdr->lpNext; 737 736 } 738 if (curPlayPos == MixBuffer[curFillBuf].ulBufferLength) {737 if (curPlayPos == MixBuffer[curFillBuf].ulBufferLength) { 739 738 curPlayPos = 0; 740 739 741 if (++curFillBuf == PREFILLBUF_DART) {740 if (++curFillBuf >= ulBufCount) 742 741 curFillBuf = 0; 743 } 744 if (curFillBuf == curPlayBuf)742 743 if (curFillBuf == curPlayBuf) 745 744 break; //no more room left 746 745 } 747 746 } 748 747 } 749 /******************************************************************************/ 750 /******************************************************************************/ 748 749 /******************************************************************************/ 750 /******************************************************************************/ 751 751 752 LONG APIENTRY WaveOutHandler(ULONG ulStatus, 752 753 PMCI_MIX_BUFFER pBuffer, … … 759 760 760 761 ptib2 = (PTIB2)_getTIBvalue(offsetof(TIB, tib_ptib2)); 761 if (ptib2 && HIBYTE(ptib2->tib2_ulpri) != PRTYC_TIMECRITICAL &&762 if (ptib2 && HIBYTE(ptib2->tib2_ulpri) != PRTYC_TIMECRITICAL && 762 763 LOBYTE(ptib2->tib2_ulpri) != PRTYD_MAXIMUM) 763 764 { … … 765 766 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0); 766 767 } 767 if (pBuffer && pBuffer->ulUserParm)768 if (pBuffer && pBuffer->ulUserParm) 768 769 { 769 770 dwave = (DartWaveOut *)pBuffer->ulUserParm; 770 771 dwave->handler(ulStatus, pBuffer, ulFlags); 771 772 } 772 return(TRUE); 773 } 774 775 /******************************************************************************/ 776 /******************************************************************************/ 777 MMRESULT DartWaveOut::setVolume(ULONG ulVol) 778 { 779 ULONG ulVolR = (((ulVol & 0xffff0000) >> 16 )*100)/0xFFFF; // Right Volume 780 ULONG ulVolL = ((ulVol& 0x0000ffff)*100)/0xFFFF; // Left Volume 781 MCI_SET_PARMS msp = {0}; 782 783 dprintf(("DartWaveOut::setVolume %d %d", ulVolL, ulVolR)); 784 volume = ulVol; 785 786 // PD: My card (ESS 1868 PnP) driver can't change only 787 // one channel Left or Right :-( 788 // 789 #ifdef GOOD_AUDIO_CARD_DRIVER 790 791 msp.ulAudio = MCI_SET_AUDIO_LEFT; 792 msp.ulLevel = ulVolL; 793 794 mymciSendCommand(DeviceId, MCI_SET, 795 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME, 796 &msp, 0); 797 798 msp.ulAudio = MCI_SET_AUDIO_RIGHT; 799 msp.ulLevel = ulVolR; 800 801 #else 802 msp.ulAudio = MCI_SET_AUDIO_ALL; 803 msp.ulLevel = max(ulVolR,ulVolL); 804 #endif 805 806 mymciSendCommand(DeviceId, MCI_SET, 807 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME, 808 &msp, 0); 809 return 0; 810 } 811 /******************************************************************************/ 812 /******************************************************************************/ 813 773 return TRUE; 774 } 775 776 /******************************************************************************/ 777 /******************************************************************************/ 778
Note:
See TracChangeset
for help on using the changeset viewer.