|
|
1.1 ! root 1: /* ! 2: Hatari ! 3: ! 4: This is where we emulate the YM2149. To obtain cycle-accurate timing we store the current cycle ! 5: time and this is incremented during each instruction. When a write occurs in the PSG registers ! 6: we take the difference in time and generate this many samples using the previous register data. ! 7: Now we begin again from this point. To make sure we always have 1/50th of samples we update ! 8: the buffer generation every 1/50th second, just in case no write took place on the PSG. ! 9: As with most 'sample' emulation it appears very quiet. We detect for any sample playback on a channel ! 10: by a decay timer on the channel amplitude - this will remain high if the PSG register is constantly ! 11: written to. We use this decay timer to boost the output of a sampled channel so the final sound is more ! 12: even through-out. ! 13: NOTE: If the emulator runs slower than 50fps it cannot update the buffers, but the DirectSound thread still ! 14: needs some data to play to prevent a 'pop'. The ONLY feasible solution is to play the same buffer again. ! 15: I have tried all kinds of methods to play the sound 'slower', but this produces un-even timing in the ! 16: sound and it simply doesn't work. If the emulator cannot keep the speed, users will have to turn off ! 17: the sound - that's it. ! 18: */ ! 19: ! 20: #include "main.h" ! 21: #include "decode.h" ! 22: #include "audio.h" ! 23: #include "debug.h" ! 24: #include "dialog.h" ! 25: #include "file.h" ! 26: #include "int.h" ! 27: #include "memAlloc.h" ! 28: #include "memorySnapShot.h" ! 29: #include "misc.h" ! 30: #include "psg.h" ! 31: #include "sound.h" ! 32: #include "video.h" ! 33: #include "wavFormat.h" ! 34: #include "ymFormat.h" ! 35: ! 36: #define LONGLONG long long /* ??? */ ! 37: ! 38: #define ENVELOPE_PERIOD(Fine,Coarse) (((unsigned long)Coarse)<<8) + (unsigned long)Fine ! 39: #define NOISE_PERIOD(Freq) ((((unsigned long)Freq)&0x1f)<<11) ! 40: #define TONE_PERIOD(Fine,Coarse) ((((unsigned long)Coarse)&0x0f)<<8) + (unsigned long)Fine ! 41: #define MIXTABLE_SIZE (256*8) /* Large table, so don't overflow */ ! 42: #define TONEFREQ_SHIFT 28 /* 4.28 fixed point */ ! 43: #define NOISEFREQ_SHIFT 28 /* 4.28 fixed point */ ! 44: #define ENVFREQ_SHIFT 16 /* 16.16 fixed */ ! 45: ! 46: /* Original wave samples */ ! 47: int EnvelopeShapeValues[16*1024]; /* Shape x Length(repeat 3rd/4th entries) */ ! 48: /* Frequency and time period samples */ ! 49: unsigned long ChannelFreq[3], EnvelopeFreq, NoiseFreq; /* Current frequency of each channel A,B,C,Envelope and Noise */ ! 50: int ChannelAmpDecayTime[3]; /* Store counter to show if amplitude is changed to generate 'samples' */ ! 51: int Envelope[SAMPLES_BUFFER_SIZE],Noise[SAMPLES_BUFFER_SIZE]; /* Current sample for this time period */ ! 52: /* Output channel data */ ! 53: int Channel_A_Buffer[SAMPLES_BUFFER_SIZE],Channel_B_Buffer[SAMPLES_BUFFER_SIZE],Channel_C_Buffer[SAMPLES_BUFFER_SIZE]; ! 54: /* Use table to convert from (A+B+C) to clipped 'unsigned char' for DirectSound buffer */ ! 55: char MixTable[MIXTABLE_SIZE]; /* -ve and +ve range */ ! 56: char *pMixTable = &MixTable[MIXTABLE_SIZE/2]; /* Signed index into above */ ! 57: BOOL bWriteEnvelopeFreq; /* Did write to register '13' - causes frequency reset */ ! 58: BOOL bWriteChannelAAmp,bWriteChannelBAmp,bWriteChannelCAmp; /* Did write to amplitude registers? */ ! 59: BOOL bEnvelopeFreqFlag; /* As above, but cleared each frame for YM saving */ ! 60: int OddEvenSoundFrame = 0; /* 11Khz does no divide nicely(remainder 0.5), so use this */ ! 61: int nSamplesToGenerate; /* How many samples are needed for this time-frame */ ! 62: // Buffer to store circular samples ! 63: char MixBuffer[MIXBUFFER_SIZE]; ! 64: int CompleteSoundBuffer,ActiveSoundBuffer; /* Index of complete and current into above mix buffer */ ! 65: ! 66: //----------------------------------------------------------------------- ! 67: // Envelope shapes ! 68: ENVSHAPE EnvShapes[16] = { ! 69: { 127,-128,-128,-128, -1, 0, 0, 0 }, /* \_____ 00xx */ ! 70: { 127,-128,-128,-128, -1, 0, 0, 0 }, /* \_____ 00xx */ ! 71: { 127,-128,-128,-128, -1, 0, 0, 0 }, /* \_____ 00xx */ ! 72: { 127,-128,-128,-128, -1, 0, 0, 0 }, /* \_____ 00xx */ ! 73: { -128,-128,-128,-128, 1, 0, 0, 0 }, /* /_____ 01xx */ ! 74: { -128,-128,-128,-128, 1, 0, 0, 0 }, /* /_____ 01xx */ ! 75: { -128,-128,-128,-128, 1, 0, 0, 0 }, /* /_____ 01xx */ ! 76: { -128,-128,-128,-128, 1, 0, 0, 0 }, /* /_____ 01xx */ ! 77: { 127,127,127,127, -1,-1,-1,-1 }, /* \\\\\\ 1000 */ ! 78: { 127,-128,-128,-128, -1, 0, 0, 0 }, /* \_____ 1001 */ ! 79: { 127,-128,127,-128, -1, 1,-1, 1 }, /* \/\/\/ 1010 */ ! 80: { 127,127,127,127, -1, 0, 0, 0 }, /* \~~~~~ 1011 */ ! 81: { -128,-128,-128,-128, 1, 1, 1, 1 }, /* ////// 1100 */ ! 82: { -128,127,127,127, 1, 0, 0, 0 }, /* /~~~~~ 1101 */ ! 83: { -128,127,-128,127, 1,-1, 1,-1 }, /* /\/\/\ 1110 */ ! 84: { -128,-128,-128,-128, 1, 0, 0, 0 } /* /_____ 1111 */ ! 85: }; ! 86: ! 87: /* Square wave look up table */ ! 88: int SquareWave[16] = { 127,127,127,127,127,127,127,127, -128,-128,-128,-128,-128,-128,-128,-128 }; ! 89: /* LogTable */ ! 90: int LogTable[256]; ! 91: int LogTable16[16]; ! 92: int *pEnvelopeLogTable = &LogTable[128]; ! 93: ! 94: //----------------------------------------------------------------------- ! 95: /* ! 96: Init sound tables and envelopes ! 97: */ ! 98: void Sound_Init(void) ! 99: { ! 100: Sound_CreateLogTables(); ! 101: Sound_CreateEnvelopeShapes(); ! 102: Sound_CreateSoundMixClipTable(); ! 103: ! 104: Sound_Reset(); ! 105: } ! 106: ! 107: //----------------------------------------------------------------------- ! 108: /* ! 109: Reset the sound emulation ! 110: */ ! 111: void Sound_Reset(void) ! 112: { ! 113: int i; ! 114: ! 115: // Clear buffer, passed to DirectSound ! 116: Sound_ClearMixBuffer(); ! 117: ! 118: /* Clear cycle counts, buffer index and register '13' flags */ ! 119: SoundCycles = 0; ! 120: CompleteSoundBuffer = ActiveSoundBuffer = 0; ! 121: bEnvelopeFreqFlag = FALSE; ! 122: bWriteEnvelopeFreq = FALSE; ! 123: bWriteChannelAAmp = bWriteChannelBAmp = bWriteChannelCAmp = FALSE; ! 124: ! 125: // Clear frequency counter ! 126: for(i=0; i<3; i++) { ! 127: ChannelFreq[i] = ! 128: ChannelAmpDecayTime[i] = 0; ! 129: } ! 130: EnvelopeFreq = NoiseFreq = 0; ! 131: } ! 132: ! 133: //----------------------------------------------------------------------- ! 134: /* ! 135: Clear mixer buffer, where samples are stored ready to pass to sound player ! 136: */ ! 137: void Sound_ClearMixBuffer(void) ! 138: { ! 139: // Clear buffer, passed to DirectSound ! 140: Memory_Clear(MixBuffer,MIXBUFFER_SIZE); ! 141: } ! 142: ! 143: //----------------------------------------------------------------------- ! 144: /* ! 145: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) ! 146: */ ! 147: void Sound_MemorySnapShot_Capture(BOOL bSave) ! 148: { ! 149: // Save/Restore details ! 150: MemorySnapShot_Store(ChannelFreq,sizeof(ChannelFreq)); ! 151: MemorySnapShot_Store(&EnvelopeFreq,sizeof(EnvelopeFreq)); ! 152: MemorySnapShot_Store(&NoiseFreq,sizeof(NoiseFreq)); ! 153: } ! 154: ! 155: //----------------------------------------------------------------------- ! 156: /* ! 157: Create Log tables ! 158: */ ! 159: void Sound_CreateLogTables(void) ! 160: { ! 161: float a; ! 162: int i; ! 163: ! 164: /* Generate 'log' table for envelope output. It isn't quite a 'log' but it mimicks the ST */ ! 165: // output very well ! 166: a = 1.0f; ! 167: for(i=0; i<256; i++) { ! 168: LogTable[255-i] = (int)(255*a); ! 169: a /= 1.02f; ! 170: } ! 171: LogTable[0] = 0; ! 172: ! 173: /* And a 16 entry version(thanks to Nick for the '/= 1.5' bit) */ ! 174: /* This is VERY important for clear sample playback */ ! 175: a = 1.0f; ! 176: for(i=0; i<15; i++) { ! 177: LogTable16[15-i] = (int)(255*a); ! 178: a /= 1.5f; ! 179: } ! 180: LogTable16[0] = 0; ! 181: } ! 182: ! 183: //----------------------------------------------------------------------- ! 184: /* ! 185: Create envelope shape, store to table ! 186: ( Wave is stored as 4 cycles, where cycles 1,2 are start and 3,4 are looped ) ! 187: */ ! 188: void Sound_CreateEnvelopeShape(ENVSHAPE *pEnvShape,int *pEnvelopeValues) ! 189: { ! 190: int i,j,Value; ! 191: ! 192: // Create shape ! 193: for(i=0; i<4; i++) { ! 194: Value = pEnvShape->WaveStart[i]; // Set starting value for gradient ! 195: for(j=0; j<256; j++,Value+=pEnvShape->WaveDelta[i]) ! 196: *pEnvelopeValues++ = Misc_LimitInt(Value,-128,127); ! 197: } ! 198: } ! 199: ! 200: //----------------------------------------------------------------------- ! 201: /* ! 202: Create YM2149 envelope shapes(x16) ! 203: */ ! 204: void Sound_CreateEnvelopeShapes(void) ! 205: { ! 206: int i; ! 207: ! 208: // Create 'envelopes' for YM table ! 209: for(i=0; i<16; i++) ! 210: Sound_CreateEnvelopeShape(&EnvShapes[i],&EnvelopeShapeValues[i*1024]); ! 211: } ! 212: ! 213: //----------------------------------------------------------------------- ! 214: /* ! 215: Create table to clip samples top 8-bit range ! 216: This keeps then 'signed', although DirectSound wants 'unsigned' values but ! 217: we keep them signed so we can vary the volume easily ! 218: */ ! 219: void Sound_CreateSoundMixClipTable(void) ! 220: { ! 221: int i,v; ! 222: ! 223: // Create table to 'clip' values to -128...127 ! 224: for(i=0; i<MIXTABLE_SIZE; i++) { ! 225: v = (float)(i-(MIXTABLE_SIZE/2)) * 0.3f; // Scale, to prevent clipping ! 226: if (v<-128) v = -128; // Limit -128..128 ! 227: if (v>127) v = 127; ! 228: MixTable[i] = v; ! 229: } ! 230: } ! 231: ! 232: //----------------------------------------------------------------------- ! 233: /* ! 234: Copy emulation sound buffer to DirectSound ! 235: This routine is called from Windows thread every 1/50th of a second ! 236: */ ! 237: void Sound_PassYMSamplesToDirectSound(void) ! 238: { ! 239: // Copy data to DirectSound ! 240: if (bDirectSoundWorking) { ! 241: // Is emulator running? ! 242: if (bEmulationActive!=EMULATION_ACTIVE) { ! 243: // Now pass completed buffer to DirectSound, toggle odd/even frame(for 11Khz timing) ! 244: DAudio_WriteSamplesIntoBuffer(MixBuffer,CompleteSoundBuffer,SoundPlayBackFreqFrameLengths[OutputAudioFreqIndex][OddEvenSoundFrame],RAMP_DOWN); ! 245: OddEvenSoundFrame ^= TRUE; ! 246: } ! 247: else { ! 248: // Now pass completed buffer to DirectSound, toggle odd/even frame(for 11Khz timing) ! 249: DAudio_WriteSamplesIntoBuffer(MixBuffer,CompleteSoundBuffer,SoundPlayBackFreqFrameLengths[OutputAudioFreqIndex][OddEvenSoundFrame],RAMP_UP); ! 250: OddEvenSoundFrame ^= TRUE; ! 251: } ! 252: } ! 253: } ! 254: ! 255: //----------------------------------------------------------------------- ! 256: /* ! 257: Find how many samples to generate and store in 'nSamplesToGenerate' ! 258: Also update 'SoundCycles' to store how many we actually did so generates set amount each frame ! 259: */ ! 260: void Sound_SetSamplesPassed(void) ! 261: { ! 262: int nSampleCycles; ! 263: int Dec=1; ! 264: ! 265: // Check how many cycles have passed, as we use this to help find out if we are playing sample data ! 266: ! 267: // First, add decay to channel amplitude variables ! 268: if (SoundCycles>(CYCLES_PER_FRAME/4)) ! 269: Dec = 16; // Been long time between sound writes, must be normal tone sound ! 270: ! 271: if (!bWriteChannelAAmp) { // Not written to amplitude, decay value ! 272: ChannelAmpDecayTime[0]-=Dec; ! 273: if (ChannelAmpDecayTime[0]<0) ChannelAmpDecayTime[0] = 0; ! 274: } ! 275: if (!bWriteChannelBAmp) { ! 276: ChannelAmpDecayTime[1]-=Dec; ! 277: if (ChannelAmpDecayTime[1]<0) ChannelAmpDecayTime[1] = 0; ! 278: } ! 279: if (!bWriteChannelCAmp) { ! 280: ChannelAmpDecayTime[2]-=Dec; ! 281: if (ChannelAmpDecayTime[2]<0) ChannelAmpDecayTime[2] = 0; ! 282: } ! 283: ! 284: // 160256 cycles per VBL, 44Khz = 882 samples per VBL ! 285: // 882/160256 samples per clock cycle ! 286: nSamplesToGenerate = (int)( (float)SoundCycles * ((float)SAMPLES_PER_FRAME/(float)CYCLES_PER_FRAME) ); ! 287: if (nSamplesToGenerate>SAMPLES_PER_FRAME) ! 288: nSamplesToGenerate = SAMPLES_PER_FRAME; ! 289: ! 290: nSampleCycles = (int)( (float)nSamplesToGenerate / ((float)SAMPLES_PER_FRAME/(float)CYCLES_PER_FRAME) ); ! 291: SoundCycles -= nSampleCycles; ! 292: } ! 293: ! 294: //----------------------------------------------------------------------- ! 295: /* ! 296: Generate envelope wave for this time-frame ! 297: */ ! 298: void Sound_GenerateEnvelope(unsigned char EnvShape, unsigned char Fine, unsigned char Coarse) ! 299: { ! 300: int *pEnvelopeValues; ! 301: unsigned long EnvelopePeriod,EnvelopeFreqDelta; ! 302: int i; ! 303: ! 304: // Find envelope details ! 305: if (bWriteEnvelopeFreq) ! 306: EnvelopeFreq = 0; ! 307: pEnvelopeValues = &EnvelopeShapeValues[ (EnvShape&0x0f)*1024 ]; // Envelope shape values ! 308: EnvelopePeriod = ENVELOPE_PERIOD((unsigned long)Fine,(unsigned long)Coarse); ! 309: ! 310: if (EnvelopePeriod==0) // Handle div by zero ! 311: EnvelopeFreqDelta = 0; ! 312: else ! 313: EnvelopeFreqDelta = ((LONGLONG)YM_FREQ<<ENVFREQ_SHIFT) / (EnvelopePeriod); // 16.16 fixed point ! 314: ! 315: // Create envelope from current shape and frequency ! 316: for(i=0; i<nSamplesToGenerate; i++) { ! 317: Envelope[i] = pEnvelopeValues[EnvelopeFreq>>ENVFREQ_SHIFT]; // Store envelope wave, already applied 'log' function ! 318: EnvelopeFreq += EnvelopeFreqDelta; ! 319: if (EnvelopeFreq&0xfe000000) ! 320: EnvelopeFreq = 0x02000000 | (EnvelopeFreq&0x01ffffff); // Keep in range 512-1024 once past 511! ! 321: } ! 322: } ! 323: ! 324: //----------------------------------------------------------------------- ! 325: /* ! 326: Generate nosie for this time-frame ! 327: */ ! 328: void Sound_GenerateNoise(unsigned char MixerControl, unsigned char NoiseGen) ! 329: { ! 330: int NoiseValue; ! 331: unsigned long NoisePeriod,NoiseFreqDelta; ! 332: int i; ! 333: ! 334: NoisePeriod = NOISE_PERIOD((unsigned long)NoiseGen); ! 335: ! 336: if (NoisePeriod==0) // Handle div by zero ! 337: NoiseFreqDelta = 0; ! 338: else ! 339: NoiseFreqDelta = (((LONGLONG)YM_FREQ)<<NOISEFREQ_SHIFT) / NoisePeriod; // 4.28 fixed point ! 340: ! 341: // Generate noise samples ! 342: for(i=0; i<nSamplesToGenerate; i++) { ! 343: NoiseValue = (unsigned int)Misc_GetRandom()%96; // Get random value ! 344: if (SquareWave[NoiseFreq>>NOISEFREQ_SHIFT]<=0) // Add to square wave at given frequency ! 345: NoiseValue = -NoiseValue; ! 346: ! 347: Noise[i] = NoiseValue; ! 348: NoiseFreq += NoiseFreqDelta; ! 349: } ! 350: } ! 351: ! 352: //----------------------------------------------------------------------- ! 353: /* ! 354: Generate channel of samples for this time-frame ! 355: */ ! 356: void Sound_GenerateChannel(int *pBuffer, unsigned char ToneFine, unsigned char ToneCoarse,unsigned char Amplitude,unsigned char MixerControl,unsigned long *pChannelFreq,int MixMask) ! 357: { ! 358: int *pNoise = Noise, *pEnvelope = Envelope; ! 359: unsigned long ToneFreq=*pChannelFreq; ! 360: unsigned long TonePeriod; ! 361: unsigned long ToneFreqDelta; ! 362: int i,Amp,Mix; ! 363: int ToneOutput,NoiseOutput,MixerOutput,EnvelopeOutput,AmplitudeOutput; ! 364: ! 365: TonePeriod = TONE_PERIOD((unsigned long)ToneFine,(unsigned long)ToneCoarse); ! 366: // Find frequency of channel ! 367: if (TonePeriod==0) ! 368: ToneFreqDelta = 0; // Handle div by zero ! 369: else ! 370: ToneFreqDelta = (((LONGLONG)YM_FREQ)<<TONEFREQ_SHIFT) / TonePeriod; // 4.28 fixed point ! 371: Amp = LogTable16[(Amplitude&0x0f)]; ! 372: Mix = (MixerControl>>MixMask)&9; // Read I/O Mixer ! 373: ! 374: // Check if we are trying to play a 'sample' - we need to up the volume on these as they tend to be rather quiet ! 375: if ((Amplitude&0x10)==0) { // Fixed level amplitude? ! 376: ChannelAmpDecayTime[MixMask]++; // Increment counter to find out if we are playing samples... ! 377: if (ChannelAmpDecayTime[MixMask]>16) ! 378: ChannelAmpDecayTime[MixMask] = 16; // And limit ! 379: } ! 380: ! 381: for(i=0; i<nSamplesToGenerate; i++) { ! 382: // Output from Tone Generator(0-255) ! 383: ToneOutput = SquareWave[ToneFreq>>TONEFREQ_SHIFT]; ! 384: ! 385: // Output from Noise Generator(0-255) ! 386: NoiseOutput = *pNoise++; ! 387: // Output from Mixer(combines Tone+Noise) ! 388: switch (Mix) { ! 389: case 0: // Has Noise and Tone ! 390: MixerOutput = NoiseOutput+ToneOutput; ! 391: break; ! 392: case 1: // Has Noise ! 393: MixerOutput = NoiseOutput; ! 394: break; ! 395: case 8: // Has Tone ! 396: MixerOutput = ToneOutput; ! 397: break; ! 398: ! 399: default: // This is used to emulate samples - should give no output, but ST gives set tone!!?? ! 400: // MixerControl gets set to give a continuous tone and then then Amplitude ! 401: // of channels A,B and C get changed with all other registers in the PSG ! 402: // staying as zero's. This produces the sounds from Quartet, Speech, NoiseTracker etc...! ! 403: MixerOutput = 127; ! 404: } ! 405: ! 406: EnvelopeOutput = pEnvelopeLogTable[*pEnvelope++]; ! 407: ! 408: if ((Amplitude&0x10)==0) { ! 409: AmplitudeOutput = Amp; // Fixed level amplitude ! 410: ! 411: // As with most emulators, sample playback is always 'quiet'. We check to see if ! 412: // the amplitude of a channel is repeatedly changing and when this is detected we ! 413: // scale the volume accordingly ! 414: if (ChannelAmpDecayTime[MixMask]>8) ! 415: AmplitudeOutput <<= 1; // Scale up by a factor of 2 ! 416: } ! 417: else ! 418: AmplitudeOutput = EnvelopeOutput; ! 419: ! 420: *pBuffer++ = (MixerOutput*AmplitudeOutput)>>8; ! 421: ! 422: ToneFreq+=ToneFreqDelta; ! 423: } ! 424: ! 425: // Store back incremented frequency, for next call ! 426: *pChannelFreq = ToneFreq; ! 427: } ! 428: ! 429: //----------------------------------------------------------------------- ! 430: /* ! 431: Generate samples for all channels during this time-frame ! 432: */ ! 433: void Sound_GenerateSamples(void) ! 434: { ! 435: int *pChannelA=Channel_A_Buffer, *pChannelB=Channel_B_Buffer, *pChannelC=Channel_C_Buffer; ! 436: int i; ! 437: ! 438: // Anything to do? ! 439: if (nSamplesToGenerate>0) { ! 440: // Generate envelope/noise samples for this time ! 441: Sound_GenerateEnvelope(PSGRegisters[PSG_REG_ENV_SHAPE],PSGRegisters[PSG_REG_ENV_FINE],PSGRegisters[PSG_REG_ENV_COARSE]); ! 442: Sound_GenerateNoise(PSGRegisters[PSG_REG_MIXER_CONTROL],PSGRegisters[PSG_REG_NOISE_GENERATOR]); ! 443: ! 444: // Generate 3 channels, store to separate buffer so can mix/clip ! 445: Sound_GenerateChannel(pChannelA,PSGRegisters[PSG_REG_CHANNEL_A_FINE],PSGRegisters[PSG_REG_CHANNEL_A_COARSE],PSGRegisters[PSG_REG_CHANNEL_A_AMP],PSGRegisters[PSG_REG_MIXER_CONTROL],&ChannelFreq[0],0); ! 446: Sound_GenerateChannel(pChannelB,PSGRegisters[PSG_REG_CHANNEL_B_FINE],PSGRegisters[PSG_REG_CHANNEL_B_COARSE],PSGRegisters[PSG_REG_CHANNEL_B_AMP],PSGRegisters[PSG_REG_MIXER_CONTROL],&ChannelFreq[1],1); ! 447: Sound_GenerateChannel(pChannelC,PSGRegisters[PSG_REG_CHANNEL_C_FINE],PSGRegisters[PSG_REG_CHANNEL_C_COARSE],PSGRegisters[PSG_REG_CHANNEL_C_AMP],PSGRegisters[PSG_REG_MIXER_CONTROL],&ChannelFreq[2],2); ! 448: ! 449: // Mix channels together, using table to clip and also convert to 'unsigned char' ! 450: for(i=0; i<nSamplesToGenerate; i++) ! 451: MixBuffer[(i+ActiveSoundBuffer)&MIXBUFFER_LENGTH] = pMixTable[(*pChannelA++) + (*pChannelB++) + (*pChannelC++)]; ! 452: ActiveSoundBuffer = (ActiveSoundBuffer+nSamplesToGenerate)&MIXBUFFER_LENGTH; ! 453: ! 454: // Reset the write to register '13' flag ! 455: bWriteEnvelopeFreq = FALSE; ! 456: // And amplitude write flags ! 457: bWriteChannelAAmp = bWriteChannelBAmp = bWriteChannelCAmp = FALSE; ! 458: } ! 459: } ! 460: ! 461: //----------------------------------------------------------------------- ! 462: /* ! 463: On each VBL(50fps) complete samples so DirectSound has something to copy ! 464: */ ! 465: void Sound_Update_VBL(void) ! 466: { ! 467: // Find how many to generate(enough to fill VBL) ! 468: Sound_SetSamplesPassed(); ! 469: // And generate ! 470: Sound_GenerateSamples(); ! 471: ! 472: // We should now have generated a frame of samples, give or take a few ! 473: // So, reset pointers(to keep exact time) and ready for next completed buffer ! 474: ActiveSoundBuffer = CompleteSoundBuffer; ! 475: CompleteSoundBuffer = (CompleteSoundBuffer+SAMPLES_PER_FRAME)&MIXBUFFER_LENGTH; ! 476: // Save to WAV file, if open ! 477: WAVFormat_Update(MixBuffer,CompleteSoundBuffer); ! 478: ! 479: // Clear write to register '13', used for YM file saving ! 480: bEnvelopeFreqFlag = FALSE; ! 481: } ! 482: ! 483: //----------------------------------------------------------------------- ! 484: /* ! 485: This is called to built samples up until this clock cycle ! 486: */ ! 487: void Sound_Update(void) ! 488: { ! 489: // Find how many to generate ! 490: Sound_SetSamplesPassed(); ! 491: // And generate ! 492: Sound_GenerateSamples(); ! 493: } ! 494: ! 495: ! 496: //----------------------------------------------------------------------- ! 497: /* ! 498: Start recording sound, as .YM or .WAV output ! 499: */ ! 500: BOOL Sound_BeginRecording(char *pszCaptureFileName) ! 501: { ! 502: BOOL bRet; ! 503: ! 504: // Did specify .YM or .WAV? If neither report error ! 505: if (File_DoesFileExtensionMatch(pszCaptureFileName,".ym") || (strlen(pszCaptureFileName)<=0) ) ! 506: bRet = YMFormat_BeginRecording(/*hWnd,*/pszCaptureFileName); ! 507: else if (File_DoesFileExtensionMatch(pszCaptureFileName,".wav")) ! 508: bRet = WAVFormat_OpenFile(/*hWnd,*/pszCaptureFileName); ! 509: else { ! 510: Main_Message("Unknown Sound Recording format\n\n.Please specify a .YM or .WAV output file.",PROG_NAME /*,MB_OK|MB_ICONSTOP*/); ! 511: bRet = FALSE; ! 512: } ! 513: ! 514: return(bRet); ! 515: } ! 516: ! 517: //----------------------------------------------------------------------- ! 518: /* ! 519: End sound recording ! 520: */ ! 521: void Sound_EndRecording(/*HWND hWnd*/) ! 522: { ! 523: // Stop sound recording and close files ! 524: if (bRecordingYM) ! 525: YMFormat_EndRecording(/*hWnd*/); ! 526: if (bRecordingWav) ! 527: WAVFormat_CloseFile(/*hWnd*/); ! 528: } ! 529: ! 530: //----------------------------------------------------------------------- ! 531: /* ! 532: Are we recording sound data? ! 533: */ ! 534: BOOL Sound_AreWeRecording(void) ! 535: { ! 536: return(bRecordingYM || bRecordingWav); ! 537: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.