|
|
1.1 ! root 1: /* ! 2: Hatari ! 3: */ ! 4: ! 5: #include "main.h" ! 6: #include "audio.h" ! 7: #include "debug.h" ! 8: #include "dialog.h" ! 9: #include "errlog.h" ! 10: #include "memAlloc.h" ! 11: #include "misc.h" ! 12: #include "sound.h" ! 13: #include "view.h" ! 14: ! 15: #define WRITE_INIT_POS ((SoundPlayBackFrequencies[OutputAudioFreqIndex]/50)*2) /* Write 2/50th ahead of write position */ ! 16: ! 17: /* 11Khz, 22Khz, 44Khz playback */ ! 18: int SoundPlayBackFrequencies[] = { ! 19: 11025, /* PLAYBACK_LOW */ ! 20: 22050, /* PLAYBACK_MEDIUM */ ! 21: 44100, /* PLAYBACK_HIGH */ ! 22: }; ! 23: ! 24: /* Bytes to download on each odd/even frame - as 11Khz does not divide by 50 exactly */ ! 25: int SoundPlayBackFreqFrameLengths[][2] = { ! 26: 221,220, /* 220.5 */ ! 27: 441,441, /* 441 */ ! 28: 882,882, /* 882 */ ! 29: }; ! 30: ! 31: BOOL bDisableDirectSound=FALSE; ! 32: //LPDIRECTSOUND lpDS = NULL; ! 33: //LPDIRECTSOUNDBUFFER lpDSBPrimBuffer = NULL; ! 34: BOOL bDirectSoundWorking=FALSE; /* Is sound OK */ ! 35: volatile BOOL bPlayingBuffer = FALSE; /* Is playing buffer? Start when start processing ST */ ! 36: int WriteOffset=0; /* Write offset into buffer */ ! 37: int OutputAudioFreqIndex=FREQ_44Khz; /* Playback rate(11Khz,22Khz or 44Khz) */ ! 38: float PlayVolume=0.0f; ! 39: BOOL bAquireWritePosition=FALSE; ! 40: int PrimaryBufferSize; /* Size of primary buffer */ ! 41: ! 42: ! 43: /* FIXME: Rewrite those functions: */ ! 44: ! 45: //----------------------------------------------------------------------- ! 46: /* ! 47: Create object for Direct Sound. Return TRUE if all OK ! 48: We use direct access to the primary buffer, set to an unsigned 8-bit mono stream ! 49: */ ! 50: void DAudio_Init(void) ! 51: { ! 52: #if 0 ! 53: DSCAPS dscaps; ! 54: HRESULT dsRetVal; ! 55: ! 56: // Is enabled? ! 57: if (bDisableDirectSound) { ! 58: // Stop any Direct Sound access ! 59: ErrLog_File("DirectSound: Disabled\n"); ! 60: bDirectSoundWorking = FALSE; ! 61: return; ! 62: } ! 63: ! 64: // Create the main DirectSound object, using default driver ! 65: dsRetVal = DirectSoundCreate(NULL, &lpDS, NULL); ! 66: if(dsRetVal!=DS_OK) { ! 67: ErrLog_File("ERROR DirectSound: Unable to 'DirectSoundCreate', error code %d\n",dsRetVal); ! 68: bDirectSoundWorking = FALSE; ! 69: return; ! 70: } ! 71: ErrLog_File("DirectSound: 'DirectSoundCreate' - OK\n"); ! 72: ! 73: // Report capabilities of sound card/driver ! 74: dscaps.dwSize = sizeof(DSCAPS); ! 75: dsRetVal = lpDS->GetCaps(&dscaps); ! 76: if(dsRetVal==DS_OK) { ! 77: // Report general list which we may use ! 78: ErrLog_File("DirectSound: Capabilities:-\n"); ! 79: if (dscaps.dwFlags&DSCAPS_EMULDRIVER) ! 80: ErrLog_File("\tEmulatedDriver(WARNING: This may cause Hatari to play back sounds incorrectly\n"); ! 81: if (dscaps.dwFlags&DSCAPS_PRIMARY16BIT) ! 82: ErrLog_File("\t16-Bit\n"); ! 83: if (dscaps.dwFlags&DSCAPS_PRIMARY8BIT) ! 84: ErrLog_File("\t8-Bit\n"); ! 85: if (dscaps.dwFlags&DSCAPS_PRIMARYMONO) ! 86: ErrLog_File("\tMono\n"); ! 87: if (dscaps.dwFlags&DSCAPS_PRIMARYSTEREO) ! 88: ErrLog_File("\tStereo\n"); ! 89: ! 90: // Are good enough? ! 91: if ( !((dscaps.dwFlags&DSCAPS_PRIMARY8BIT) && (dscaps.dwFlags&DSCAPS_PRIMARYMONO)) ) { ! 92: // No, MUST have 8-Bit/Mono ! 93: ErrLog_File("ERROR DirectSound: Your sound card does not support the playback mode required(8-Bit/Mono)\n"); ! 94: bDirectSoundWorking = FALSE; ! 95: return; ! 96: } ! 97: } ! 98: ! 99: // Create sound buffer, return if error ! 100: DAudio_CreateSoundBuffer(); ! 101: #endif ! 102: } ! 103: ! 104: //----------------------------------------------------------------------- ! 105: /* ! 106: Free object created for Direct Sound ! 107: */ ! 108: void DAudio_UnInit(void) ! 109: { ! 110: #if 0 ! 111: // Free Direct Sound ! 112: DAudio_FreeSoundBuffer(); ! 113: if( lpDS ) { ! 114: lpDS->Release(); lpDS = NULL; ! 115: } ! 116: #endif ! 117: } ! 118: ! 119: //----------------------------------------------------------------------- ! 120: /* ! 121: Create sound buffer to write samples into ! 122: */ ! 123: BOOL DAudio_CreateSoundBuffer(void) ! 124: { ! 125: #if 0 ! 126: WAVEFORMATEX pwfx; ! 127: DSBUFFERDESC dsbdesc; ! 128: DSBCAPS dsbcaps; ! 129: HRESULT dsRetVal; ! 130: ! 131: // Set up wave format structure ! 132: memset(&pwfx, 0, sizeof(WAVEFORMATEX)); ! 133: pwfx.wFormatTag = WAVE_FORMAT_PCM; ! 134: pwfx.nChannels = 1; // Mono ! 135: pwfx.nSamplesPerSec = SoundPlayBackFrequencies[OutputAudioFreqIndex]; ! 136: pwfx.wBitsPerSample = 8; // 8 Bit unsigned ! 137: pwfx.nBlockAlign = (pwfx.nChannels*pwfx.wBitsPerSample)/8; ! 138: pwfx.nAvgBytesPerSec = pwfx.nSamplesPerSec*pwfx.nBlockAlign; ! 139: pwfx.cbSize = 0; ! 140: memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); ! 141: dsbdesc.dwSize = sizeof(DSBUFFERDESC); ! 142: // Use direct access for Primary Buffer else sound drivers can cause corrupted sound and ! 143: // also declare 'STICKFOCUS' otherwise cannot continue sound when loose focus! ! 144: dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS; ! 145: // Buffer size is determined by sound hardware. ! 146: dsbdesc.dwBufferBytes = 0; ! 147: dsbdesc.lpwfxFormat = NULL; // Must be NULL for primary buffers ! 148: ! 149: // Obtain write-primary cooperative level ! 150: dsRetVal = lpDS->SetCooperativeLevel(hWnd, DSSCL_WRITEPRIMARY); ! 151: if(dsRetVal!=DS_OK) { ! 152: ErrLog_File("ERROR DirectSound: Unable to 'SetCooperativeLevel', error code %d\n",dsRetVal); ! 153: lpDS->Release(); lpDS = NULL; ! 154: bDirectSoundWorking = FALSE; ! 155: return(FALSE); ! 156: } ! 157: ! 158: // Create sound buffer ! 159: dsRetVal = lpDS->CreateSoundBuffer(&dsbdesc,&lpDSBPrimBuffer,NULL); ! 160: if(dsRetVal!=DS_OK) { ! 161: ErrLog_File("ERROR DirectSound: Unable to 'CreateSoundBuffer', error code %d\n",dsRetVal); ! 162: lpDS->Release(); lpDS = NULL; ! 163: bDirectSoundWorking = FALSE; ! 164: return(FALSE); ! 165: } ! 166: ! 167: // Succeeded. Set primary buffer to desired format. ! 168: dsRetVal = lpDSBPrimBuffer->SetFormat(&pwfx); ! 169: if(dsRetVal!=DS_OK) { ! 170: ErrLog_File("ERROR DirectSound: Unable to 'SetFormat', error code %d\n",dsRetVal); ! 171: lpDS->Release(); lpDS = NULL; ! 172: lpDSBPrimBuffer->Release(); lpDSBPrimBuffer = NULL; ! 173: bDirectSoundWorking = FALSE; ! 174: return(FALSE); ! 175: } ! 176: ! 177: // Get buffer size ! 178: dsbcaps.dwSize = sizeof(DSBCAPS); ! 179: lpDSBPrimBuffer->GetCaps(&dsbcaps); ! 180: PrimaryBufferSize = dsbcaps.dwBufferBytes; ! 181: ! 182: // All OK ! 183: bDirectSoundWorking = TRUE; ! 184: // And begin ! 185: DAudio_ResetBuffer(); ! 186: ! 187: return(TRUE); ! 188: #endif ! 189: } ! 190: ! 191: //----------------------------------------------------------------------- ! 192: /* ! 193: Free sound buffer ! 194: */ ! 195: void DAudio_FreeSoundBuffer(void) ! 196: { ! 197: #if 0 ! 198: if (lpDSBPrimBuffer) { ! 199: // Stop ! 200: DAudio_StopBuffer(); ! 201: // And free ! 202: lpDSBPrimBuffer->Release(); lpDSBPrimBuffer = NULL; ! 203: } ! 204: #endif ! 205: } ! 206: ! 207: //----------------------------------------------------------------------- ! 208: /* ! 209: Re-Create sound buffer to write samples into, will stop existing and restart with new frequency ! 210: */ ! 211: void DAudio_ReCreateDirectSoundBuffer(void) ! 212: { ! 213: #if 0 ! 214: if (lpDS) { ! 215: // Stop and delete old buffer ! 216: DAudio_FreeSoundBuffer(); ! 217: ! 218: // Clear sample buffer, so plays silence ! 219: Sound_ClearMixBuffer(); ! 220: ! 221: // And create new one(will use new 'OutputAudioFreq' value) ! 222: DAudio_CreateSoundBuffer(); ! 223: } ! 224: #endif ! 225: } ! 226: ! 227: //----------------------------------------------------------------------- ! 228: /* ! 229: Set DirectSound playback frequency variable, pass as PLAYBACK_xxxx ! 230: */ ! 231: void DAudio_SetOutputAudioFreq(int Frequency) ! 232: { ! 233: // Set new frequency, index into SoundPlayBackFrequencies[] ! 234: OutputAudioFreqIndex = Frequency; ! 235: } ! 236: ! 237: //----------------------------------------------------------------------- ! 238: /* ! 239: Reset sound buffer, so plays from correct position ! 240: */ ! 241: void DAudio_ResetBuffer(void) ! 242: { ! 243: // Get new 'write' position on next frame ! 244: bAquireWritePosition = TRUE; ! 245: } ! 246: ! 247: //----------------------------------------------------------------------- ! 248: /* ! 249: Stop sound buffer ! 250: */ ! 251: void DAudio_StopBuffer(void) ! 252: { ! 253: #if 0 ! 254: // Stop from playing ! 255: if (lpDSBPrimBuffer) ! 256: lpDSBPrimBuffer->Stop(); ! 257: bPlayingBuffer = FALSE; ! 258: #endif ! 259: } ! 260: ! 261: //----------------------------------------------------------------------- ! 262: /* ! 263: Scale sample value(-128...127) according to 'PlayVolume' setting ! 264: */ ! 265: char DAudio_ModifyVolume(char Sample) ! 266: { ! 267: // If full volume, just use current value ! 268: if (PlayVolume==1.0f) ! 269: return(Sample); ! 270: ! 271: // Else, scale volume ! 272: Sample = (char)((float)Sample*PlayVolume); ! 273: ! 274: return(Sample); ! 275: } ! 276: ! 277: //----------------------------------------------------------------------- ! 278: /* ! 279: Write samples into Direct Sound buffer at 'Offset', taking care to wrap around. Pass NULL to write zero's ! 280: */ ! 281: void DAudio_WriteSamplesIntoBuffer(char *pSamples,int Index,int Length,int RampSetting) ! 282: { ! 283: #if 0 ! 284: void *lpWrite1, *lpWrite2; ! 285: unsigned char *pBuffer; ! 286: DWORD dwLenBytes1, dwLenBytes2; ! 287: HRESULT dsRetVal; ! 288: int i,WriteCursor,CursorDiff; ! 289: ! 290: // Modify ramp volume - ramp down if sound not enabled or not in windows mouse mode ! 291: if ( (((RampSetting==RAMP_DOWN) || (!ConfigureParams.Sound.bEnableSound)) && (PlayVolume>0.0f)) || bWindowsMouseMode ) { ! 292: PlayVolume -= RAMP_DOWN_VOLUME_LEVEL; ! 293: if (PlayVolume<=0.0f) ! 294: PlayVolume = 0.0f; ! 295: } ! 296: else if ( (RampSetting==RAMP_UP) && (PlayVolume<1.0f) ) { ! 297: PlayVolume += RAMP_UP_VOLUME_LEVEL; ! 298: if (PlayVolume>=1.0f) ! 299: PlayVolume = 1.0f; ! 300: } ! 301: ! 302: if (lpDSBPrimBuffer) { ! 303: // Do need to reset 'write' position? ! 304: if (bAquireWritePosition) { ! 305: // Get current write position ! 306: lpDSBPrimBuffer->GetCurrentPosition(NULL,(DWORD *)&WriteCursor); ! 307: WriteOffset = WriteCursor+WRITE_INIT_POS; // + little gap ! 308: bAquireWritePosition = FALSE; ! 309: } ! 310: ! 311: // Lock sound buffer to get pointers ! 312: lpWrite1 = lpWrite2 = NULL; ! 313: dwLenBytes1 = dwLenBytes2 = 0; ! 314: dsRetVal = lpDSBPrimBuffer->Lock( WriteOffset, Length, &lpWrite1, &dwLenBytes1, &lpWrite2, &dwLenBytes2, 0 ); ! 315: if (dsRetVal==DSERR_BUFFERLOST) { ! 316: // Lost focus of buffer, restore and try to lock again ! 317: lpDSBPrimBuffer->Restore(); ! 318: dsRetVal = lpDSBPrimBuffer->Lock( WriteOffset, Length, &lpWrite1, &dwLenBytes1, &lpWrite2, &dwLenBytes2, 0 ); ! 319: } ! 320: ! 321: // All OK? ! 322: if (dsRetVal==DS_OK) { ! 323: // Write first section, convert to 'unsigned' and write '128'(unsigned) if passed NULL ! 324: if ( (dwLenBytes1>0) && (lpWrite1) ) { ! 325: if (pSamples) { ! 326: pBuffer = (unsigned char *)lpWrite1; ! 327: for(i=0; i<(int)dwLenBytes1; i++) { ! 328: *pBuffer++ = DAudio_ModifyVolume(pSamples[Index])+128; ! 329: Index = (Index+1)&4095; ! 330: } ! 331: } ! 332: else ! 333: memset(lpWrite1,128,dwLenBytes1); ! 334: } ! 335: // And second, if needed ! 336: if ( (dwLenBytes2>0) && (lpWrite2) ) { ! 337: if (pSamples) { ! 338: pBuffer = (unsigned char *)lpWrite2; ! 339: for(i=0; i<(int)dwLenBytes2; i++) { ! 340: *pBuffer++ = DAudio_ModifyVolume(pSamples[Index])+128; ! 341: Index = (Index+1)&4095; ! 342: } ! 343: } ! 344: else ! 345: memset(lpWrite2,128,dwLenBytes2); ! 346: } ! 347: ! 348: // Now unlock the buffer. ! 349: dsRetVal = lpDSBPrimBuffer->Unlock( (LPVOID)lpWrite1, dwLenBytes1,(LPVOID)lpWrite2, dwLenBytes2 ); ! 350: } ! 351: ! 352: // Update write buffer ! 353: if (pSamples) { ! 354: WriteOffset += Length; ! 355: if (WriteOffset>=PrimaryBufferSize) ! 356: WriteOffset -= PrimaryBufferSize; ! 357: } ! 358: ! 359: // Are we playing? ! 360: if (!bPlayingBuffer) { ! 361: lpDSBPrimBuffer->Play( 0, 0, DSBPLAY_LOOPING ); ! 362: DAudio_ResetBuffer(); ! 363: ! 364: bPlayingBuffer = TRUE; ! 365: } ! 366: else { ! 367: // Check here for play/write pointers getting away from each other and set 'bAquireWritePosition' to reset ! 368: lpDSBPrimBuffer->GetCurrentPosition(NULL,(DWORD *)&WriteCursor); ! 369: // If the writecursor is too-far away from where we think it should be cause a reset ! 370: CursorDiff = WriteOffset-WriteCursor; ! 371: // Check for overlap ! 372: if (CursorDiff<0) ! 373: CursorDiff = (WriteOffset+PrimaryBufferSize)-WriteCursor; ! 374: // So, does need reset? ! 375: if (abs(CursorDiff)>(WRITE_INIT_POS*2)) ! 376: DAudio_ResetBuffer(); ! 377: } ! 378: } ! 379: #endif ! 380: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.