sound.cpp
1 #include "dcastaway.h" 2 3 #ifndef NO_SOUND 4 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<string.h> 8 9 #include<Arduino.h> 10 11 #include "st.h" 12 #include "mem.h" 13 #include "m68k_intrf.h" 14 15 #include "sound.h" 16 17 #define LONGLONG unsigned long long 18 19 #define ENVELOPE_PERIOD(Fine,Coarse) (((unsigned long)Coarse)<<8) + (unsigned long)Fine 20 #define NOISE_PERIOD(Freq) ((((unsigned long)Freq)&0x1f)<<11) 21 #define TONE_PERIOD(Fine,Coarse) ((((unsigned long)Coarse)&0x0f)<<8) + (unsigned long)Fine 22 #define MIXTABLE_SIZE (256*8) /* Large table, so don't overflow */ 23 #define TONEFREQ_SHIFT 28 /* 4.28 fixed point */ 24 #define NOISEFREQ_SHIFT 28 /* 4.28 fixed point */ 25 #define ENVFREQ_SHIFT 16 /* 16.16 fixed */ 26 27 #define SAMPLES_BUFFER_SIZE 1024 28 /* Number of generated samples per frame (eg. 44Khz=882) : */ 29 #define SAMPLES_PER_FRAME ((SOUND_FREQ+35)/nScreenRefreshRate) 30 /* Frequency of generated samples: */ 31 #define SAMPLES_FREQ (SOUND_FREQ) 32 #define YM_FREQ (2000000/SAMPLES_FREQ) /* YM Frequency 2Mhz */ 33 34 /* Original wave samples */ 35 #include "tab_EnvelopeShapeValues.h" 36 //static int EnvelopeShapeValues[16*1024]; /* Shape x Length(repeat 3rd/4th entries) */ 37 /* Frequency and time period samples */ 38 static unsigned long ChannelFreq[3], EnvelopeFreq, NoiseFreq; /* Current frequency of each channel A,B,C,Envelope and Noise */ 39 static int ChannelAmpDecayTime[3]; /* Store counter to show if amplitude is changed to generate 'samples' */ 40 static int Envelope[SAMPLES_BUFFER_SIZE],Noise[SAMPLES_BUFFER_SIZE]; /* Current sample for this time period */ 41 /* Output channel data */ 42 static int Channel_A_Buffer[SAMPLES_BUFFER_SIZE],Channel_B_Buffer[SAMPLES_BUFFER_SIZE],Channel_C_Buffer[SAMPLES_BUFFER_SIZE]; 43 /* Use table to convert from (A+B+C) to clipped 'unsigned char' for sound buffer */ 44 #include "tab_MixTable.h" 45 //static char MixTable[MIXTABLE_SIZE]; /* -ve and +ve range */ 46 static char *pMixTable = &MixTable[MIXTABLE_SIZE/2]; /* Signed index into above */ 47 static int ActiveSndBufIdx; /* Current working index into above mix buffer */ 48 static int nSamplesToGenerate; /* How many samples are needed for this time-frame */ 49 50 /* global values */ 51 bool bWriteEnvelopeFreq; /* Did write to register '13' - causes frequency reset */ 52 bool bWriteChannelAAmp, bWriteChannelBAmp, bWriteChannelCAmp; /* Did write to amplitude registers? */ 53 bool bEnvelopeFreqFlag; /* As above, but cleared each frame for YM saving */ 54 /* Buffer to store circular samples */ 55 char MixBuffer[MIXBUFFER_SIZE]; 56 int nGeneratedSamples; /* Generated samples since audio buffer update */ 57 int SoundCycles; 58 59 static int nScreenRefreshRate=60; 60 61 /*-----------------------------------------------------------------------*/ 62 /* Envelope shape table */ 63 typedef struct 64 { 65 int WaveStart[4], WaveDelta[4]; 66 } ENVSHAPE; 67 68 /* Envelope shapes */ 69 static ENVSHAPE EnvShapes[16] = 70 { 71 { {127,-128,-128,-128}, {-1, 0, 0, 0} }, /* \_____ 00xx */ 72 { {127,-128,-128,-128}, {-1, 0, 0, 0} }, /* \_____ 00xx */ 73 { {127,-128,-128,-128}, {-1, 0, 0, 0} }, /* \_____ 00xx */ 74 { {127,-128,-128,-128}, {-1, 0, 0, 0} }, /* \_____ 00xx */ 75 { {-128,-128,-128,-128}, {1, 0, 0, 0} }, /* /_____ 01xx */ 76 { {-128,-128,-128,-128}, {1, 0, 0, 0} }, /* /_____ 01xx */ 77 { {-128,-128,-128,-128}, {1, 0, 0, 0} }, /* /_____ 01xx */ 78 { {-128,-128,-128,-128}, {1, 0, 0, 0} }, /* /_____ 01xx */ 79 { {127,127,127,127}, {-1,-1,-1,-1} }, /* \\\\\\ 1000 */ 80 { {127,-128,-128,-128}, {-1, 0, 0, 0} }, /* \_____ 1001 */ 81 { {127,-128,127,-128}, {-1, 1,-1, 1} }, /* \/\/\/ 1010 */ 82 { {127,127,127,127}, {-1, 0, 0, 0} }, /* \~~~~~ 1011 */ 83 { {-128,-128,-128,-128}, {1, 1, 1, 1} }, /* ////// 1100 */ 84 { {-128,127,127,127}, {1, 0, 0, 0} }, /* /~~~~~ 1101 */ 85 { {-128,127,-128,127}, {1,-1, 1,-1} }, /* /\/\/\ 1110 */ 86 { {-128,-128,-128,-128}, {1, 0, 0, 0} } /* /_____ 1111 */ 87 }; 88 89 /* Square wave look up table */ 90 static int SquareWave[16] = { 127,127,127,127,127,127,127,127, -128,-128,-128,-128,-128,-128,-128,-128 }; 91 /* LogTable */ 92 #include "tab_LogTable.h" 93 //static int LogTable[256]; 94 #include "tab_LogTable16.h" 95 //static int LogTable16[16]; 96 static int *pEnvelopeLogTable = &LogTable[128]; 97 98 99 /*-----------------------------------------------------------------------*/ 100 /* 101 Create Log tables 102 */ 103 //static void Sound_CreateLogTables(void) 104 //{ 105 // float a; 106 // int i; 107 // 108 // /* Generate 'log' table for envelope output. It isn't quite a 'log' but it mimicks the ST */ 109 // /* output very well */ 110 // a = 1.0f; 111 // for(i=0; i<256; i++) 112 // { 113 // LogTable[255-i] = (int)(255*a); 114 // a /= 1.02f; 115 // } 116 // LogTable[0] = 0; 117 // 118 // /* And a 16 entry version(thanks to Nick for the '/= 1.5' bit) */ 119 // /* This is VERY important for clear sample playback */ 120 // a = 1.0f; 121 // for(i=0; i<15; i++) 122 // { 123 // LogTable16[15-i] = (int)(255*a); 124 // a /= 1.5f; 125 // } 126 // LogTable16[0] = 0; 127 //} 128 129 static long RandomNum; 130 131 static __inline__ long Misc_NextLongRand(long Seed) 132 { 133 unsigned long Lo, Hi; 134 135 Lo = 16807 * (long)(Seed & 0xffff); 136 Hi = 16807 * (long)((unsigned long)Seed >> 16); 137 Lo += (Hi & 0x7fff) << 16; 138 if (Lo > 2147483647L) { 139 Lo &= 2147483647L; 140 ++Lo; 141 } 142 Lo += Hi >> 15; 143 if (Lo > 2147483647L) { 144 Lo &= 2147483647L; 145 ++Lo; 146 } 147 return((long)Lo); 148 } 149 150 static __inline__ long Misc_GetRandom(void) 151 { 152 RandomNum = Misc_NextLongRand(RandomNum); 153 if (!RandomNum) 154 { 155 RandomNum++; 156 return 0; 157 } 158 return(RandomNum); 159 } 160 161 162 /*-----------------------------------------------------------------------*/ 163 /* 164 Create envelope shape, store to table 165 ( Wave is stored as 4 cycles, where cycles 1,2 are start and 3,4 are looped ) 166 */ 167 static void Sound_CreateEnvelopeShape(ENVSHAPE *pEnvShape,int *pEnvelopeValues) 168 { 169 int i,j,Value; 170 171 /* Create shape */ 172 for(i=0; i<4; i++) 173 { 174 Value = pEnvShape->WaveStart[i]; /* Set starting value for gradient */ 175 for(j=0; j<256; j++,Value+=pEnvShape->WaveDelta[i]) 176 *pEnvelopeValues++ = Misc_LimitInt(Value,-128,127); 177 } 178 } 179 180 181 /*-----------------------------------------------------------------------*/ 182 /* 183 Create YM2149 envelope shapes(x16) 184 */ 185 //static void Sound_CreateEnvelopeShapes(void) 186 //{ 187 // int i; 188 // 189 // /* Create 'envelopes' for YM table */ 190 // for(i=0; i<16; i++) 191 // Sound_CreateEnvelopeShape(&EnvShapes[i],&EnvelopeShapeValues[i*1024]); 192 //} 193 194 195 /*-----------------------------------------------------------------------*/ 196 /* 197 Create table to clip samples top 8-bit range 198 This keeps then 'signed', although many sound cards want 'unsigned' values, 199 but we keep them signed so we can vary the volume easily. 200 */ 201 202 //static void Sound_CreateSoundMixClipTable(void) 203 //{ 204 // int i,v; 205 // 206 // /* Create table to 'clip' values to -128...127 */ 207 // for(i=0; i<MIXTABLE_SIZE; i++) 208 // { 209 // v = (int)(((float)(i-(MIXTABLE_SIZE/2))) * 0.3f); /* Scale, to prevent clipping */ 210 // if (v<-128) v = -128; /* Limit -128..128 */ 211 // if (v>127) v = 127; 212 // MixTable[i] = v; 213 // } 214 //} 215 216 static void Sound_InitNoise(void) 217 { 218 int i; 219 srand(6643680); 220 RandomNum=rand(); 221 if (!RandomNum) 222 RandomNum++; 223 for(i=0;i<SAMPLES_BUFFER_SIZE;i++) 224 Noise[i]=(unsigned int)Misc_GetRandom()%96; 225 } 226 227 228 /*-----------------------------------------------------------------------*/ 229 /* 230 Init sound tables and envelopes 231 */ 232 void Sound_Init(void) 233 { 234 //Sound_CreateLogTables(); 235 //Sound_CreateEnvelopeShapes(); 236 //Sound_CreateSoundMixClipTable(); 237 Sound_InitNoise(); 238 Sound_Reset(); 239 } 240 241 242 /*-----------------------------------------------------------------------*/ 243 /* 244 Reset the sound emulation 245 */ 246 void Sound_Reset(void) 247 { 248 int i; 249 250 Sound_ClearMixBuffer(); /* Clear buffer */ 251 252 /* Clear cycle counts, buffer index and register '13' flags */ 253 SoundCycles = 0; 254 bEnvelopeFreqFlag = FALSE; 255 bWriteEnvelopeFreq = FALSE; 256 bWriteChannelAAmp = bWriteChannelBAmp = bWriteChannelCAmp = FALSE; 257 258 /* Lock audio system before accessing variables that are also use by the callback function! */ 259 Audio_Lock(); 260 CompleteSndBufIdx = 0; 261 ActiveSndBufIdx = (SOUND_BUFFER_SIZE + SAMPLES_PER_FRAME) % MIXBUFFER_SIZE; 262 nGeneratedSamples = 0; 263 Audio_Unlock(); 264 265 /* Clear frequency counter */ 266 for(i=0; i<3; i++) 267 { 268 ChannelFreq[i] = 269 ChannelAmpDecayTime[i] = 0; 270 } 271 EnvelopeFreq = NoiseFreq = 0; 272 } 273 274 275 /*-----------------------------------------------------------------------*/ 276 /* 277 Clear mixer buffer, where samples are stored ready to pass to sound player 278 */ 279 void Sound_ClearMixBuffer(void) 280 { 281 Audio_Lock(); 282 283 Memory_Clear(MixBuffer, MIXBUFFER_SIZE); /* Clear buffer */ 284 285 Audio_Unlock(); 286 } 287 288 289 /*-----------------------------------------------------------------------*/ 290 /* 291 Find how many samples to generate and store in 'nSamplesToGenerate' 292 Also update 'SoundCycles' to store how many we actually did so generates set amount each frame 293 */ 294 static void Sound_SetSamplesPassed(void) 295 { 296 int nSampleCycles; 297 int nSamplesPerFrame; 298 int Dec=1; 299 300 /* Check how many cycles have passed, as we use this to help find out if we are playing sample data */ 301 302 /* First, add decay to channel amplitude variables */ 303 if (SoundCycles>(CYCLES_PER_FRAME/4)) 304 Dec = 16; /* Been long time between sound writes, must be normal tone sound */ 305 306 if (!bWriteChannelAAmp) /* Not written to amplitude, decay value */ 307 { 308 ChannelAmpDecayTime[0]-=Dec; 309 if (ChannelAmpDecayTime[0]<0) ChannelAmpDecayTime[0] = 0; 310 } 311 if (!bWriteChannelBAmp) 312 { 313 ChannelAmpDecayTime[1]-=Dec; 314 if (ChannelAmpDecayTime[1]<0) ChannelAmpDecayTime[1] = 0; 315 } 316 if (!bWriteChannelCAmp) 317 { 318 ChannelAmpDecayTime[2]-=Dec; 319 if (ChannelAmpDecayTime[2]<0) ChannelAmpDecayTime[2] = 0; 320 } 321 322 /* 160256 cycles per VBL, 44Khz = 882 samples per VBL */ 323 /* 882/160256 samples per clock cycle */ 324 nSamplesPerFrame = SAMPLES_PER_FRAME; 325 #if 0 /* Use floats for calculation */ 326 nSamplesToGenerate = (int)( (float)SoundCycles * ((float)nSamplesPerFrame/(float)CYCLES_PER_FRAME) ); 327 if (nSamplesToGenerate > nSamplesPerFrame) 328 nSamplesToGenerate = nSamplesPerFrame; 329 330 nSampleCycles = (int)( (float)nSamplesToGenerate / ((float)nSamplesPerFrame/(float)CYCLES_PER_FRAME) ); 331 SoundCycles -= nSampleCycles; 332 #else /* Use integers for calculation - both of these calculations should fit into 32-bit int */ 333 nSamplesToGenerate = SoundCycles * nSamplesPerFrame / CYCLES_PER_FRAME; 334 //printf("nSamplesToGenerate=%i , SoundCycles=%i\n",nSamplesToGenerate,SoundCycles); 335 if (nSamplesToGenerate > nSamplesPerFrame) 336 nSamplesToGenerate = nSamplesPerFrame; 337 338 nSampleCycles = nSamplesToGenerate * CYCLES_PER_FRAME / nSamplesPerFrame; 339 SoundCycles -= nSampleCycles; 340 #endif 341 } 342 343 344 /*-----------------------------------------------------------------------*/ 345 /* 346 Generate envelope wave for this time-frame 347 */ 348 static void Sound_GenerateEnvelope(unsigned char EnvShape, unsigned char Fine, unsigned char Coarse) 349 { 350 int *pEnvelopeValues; 351 unsigned long EnvelopePeriod,EnvelopeFreqDelta; 352 int i; 353 354 /* Find envelope details */ 355 if (bWriteEnvelopeFreq) 356 EnvelopeFreq = 0; 357 pEnvelopeValues = &EnvelopeShapeValues[ (EnvShape&0x0f)*1024 ]; /* Envelope shape values */ 358 EnvelopePeriod = ENVELOPE_PERIOD((unsigned long)Fine,(unsigned long)Coarse); 359 360 if (EnvelopePeriod==0) /* Handle div by zero */ 361 EnvelopeFreqDelta = 0; 362 else 363 EnvelopeFreqDelta = ((LONGLONG)YM_FREQ<<ENVFREQ_SHIFT) / (EnvelopePeriod); /* 16.16 fixed point */ 364 365 /* Create envelope from current shape and frequency */ 366 for(i=0; i<nSamplesToGenerate; i++) 367 { 368 Envelope[i] = pEnvelopeValues[EnvelopeFreq>>ENVFREQ_SHIFT]; /* Store envelope wave, already applied 'log' function */ 369 EnvelopeFreq += EnvelopeFreqDelta; 370 if (EnvelopeFreq&0xfe000000) 371 EnvelopeFreq = 0x02000000 | (EnvelopeFreq&0x01ffffff); /* Keep in range 512-1024 once past 511! */ 372 } 373 } 374 375 376 /*-----------------------------------------------------------------------*/ 377 /* 378 Generate nosie for this time-frame 379 */ 380 static void Sound_GenerateNoise(unsigned char MixerControl, unsigned char NoiseGen) 381 { 382 int NoiseValue; 383 unsigned long NoisePeriod,NoiseFreqDelta; 384 int i; 385 386 NoisePeriod = NOISE_PERIOD((unsigned long)NoiseGen); 387 388 if (NoisePeriod==0) /* Handle div by zero */ 389 NoiseFreqDelta = 0; 390 else 391 NoiseFreqDelta = (((LONGLONG)YM_FREQ)<<NOISEFREQ_SHIFT) / NoisePeriod; /* 4.28 fixed point */ 392 393 /* Generate noise samples */ 394 for(i=0; i<nSamplesToGenerate; i++) 395 { 396 NoiseValue = (unsigned int)Misc_GetRandom()%96; /* Get random value */ 397 if (SquareWave[NoiseFreq>>NOISEFREQ_SHIFT]<=0) /* Add to square wave at given frequency */ 398 NoiseValue = -NoiseValue; 399 400 Noise[i] = NoiseValue; 401 NoiseFreq += NoiseFreqDelta; 402 } 403 } 404 405 406 /*-----------------------------------------------------------------------*/ 407 /* 408 Generate channel of samples for this time-frame 409 */ 410 static void Sound_GenerateChannel(int *pBuffer, unsigned char ToneFine, unsigned char ToneCoarse,unsigned char Amplitude,unsigned char MixerControl,unsigned long *pChannelFreq,int MixMask) 411 { 412 int *pNoise = Noise, *pEnvelope = Envelope; 413 unsigned long ToneFreq=*pChannelFreq; 414 unsigned long TonePeriod; 415 unsigned long ToneFreqDelta; 416 int i,Amp,Mix; 417 int ToneOutput,NoiseOutput,MixerOutput,EnvelopeOutput,AmplitudeOutput; 418 419 TonePeriod = TONE_PERIOD((unsigned long)ToneFine,(unsigned long)ToneCoarse); 420 /* Find frequency of channel */ 421 if (TonePeriod==0) 422 ToneFreqDelta = 0; /* Handle div by zero */ 423 else 424 ToneFreqDelta = (((LONGLONG)YM_FREQ)<<TONEFREQ_SHIFT) / TonePeriod; /* 4.28 fixed point */ 425 Amp = LogTable16[(Amplitude&0x0f)]; 426 Mix = (MixerControl>>MixMask)&9; /* Read I/O Mixer */ 427 428 /* Check if we are trying to play a 'sample' - we need to up the volume on these as they tend to be rather quiet */ 429 if ((Amplitude&0x10)==0) /* Fixed level amplitude? */ 430 { 431 ChannelAmpDecayTime[MixMask]++; /* Increment counter to find out if we are playing samples... */ 432 if (ChannelAmpDecayTime[MixMask]>16) 433 ChannelAmpDecayTime[MixMask] = 16; /* And limit */ 434 } 435 436 for(i=0; i<nSamplesToGenerate; i++) 437 { 438 /* Output from Tone Generator(0-255) */ 439 ToneOutput = SquareWave[ToneFreq>>TONEFREQ_SHIFT]; 440 441 /* Output from Noise Generator(0-255) */ 442 NoiseOutput = *pNoise++; 443 /* Output from Mixer(combines Tone+Noise) */ 444 switch (Mix) { 445 case 0: /* Has Noise and Tone */ 446 MixerOutput = NoiseOutput+ToneOutput; 447 break; 448 case 1: /* Has Noise */ 449 MixerOutput = NoiseOutput; 450 break; 451 case 8: /* Has Tone */ 452 MixerOutput = ToneOutput; 453 break; 454 455 default: /* This is used to emulate samples - should give no output, but ST gives set tone!!?? */ 456 /* MixerControl gets set to give a continuous tone and then then Amplitude */ 457 /* of channels A,B and C get changed with all other registers in the PSG */ 458 /* staying as zero's. This produces the sounds from Quartet, Speech, NoiseTracker etc...! */ 459 MixerOutput = 127; 460 } 461 462 EnvelopeOutput = pEnvelopeLogTable[*pEnvelope++]; 463 464 if ((Amplitude&0x10)==0) 465 { 466 AmplitudeOutput = Amp; /* Fixed level amplitude */ 467 468 /* As with most emulators, sample playback is always 'quiet'. We check to see if */ 469 /* the amplitude of a channel is repeatedly changing and when this is detected we */ 470 /* scale the volume accordingly */ 471 if (ChannelAmpDecayTime[MixMask]>8) 472 AmplitudeOutput <<= 1; /* Scale up by a factor of 2 */ 473 } 474 else 475 AmplitudeOutput = EnvelopeOutput; 476 477 *pBuffer++ = (MixerOutput*AmplitudeOutput)>>8; 478 479 ToneFreq+=ToneFreqDelta; 480 } 481 482 /* Store back incremented frequency, for next call */ 483 *pChannelFreq = ToneFreq; 484 } 485 486 487 /*-----------------------------------------------------------------------*/ 488 /* 489 Generate samples for all channels during this time-frame 490 */ 491 static void Sound_GenerateSamples(void) 492 { 493 int *pChannelA=Channel_A_Buffer, *pChannelB=Channel_B_Buffer, *pChannelC=Channel_C_Buffer; 494 int i; 495 496 /* Anything to do? */ 497 if (nSamplesToGenerate>0) 498 { 499 /* Generate envelope/noise samples for this time */ 500 Sound_GenerateEnvelope(psg[PSG_REG_ENV_SHAPE],psg[PSG_REG_ENV_FINE],psg[PSG_REG_ENV_COARSE]); 501 Sound_GenerateNoise(psg[PSG_REG_MIXER_CONTROL],psg[PSG_REG_NOISE_GENERATOR]); 502 503 /* Generate 3 channels, store to separate buffer so can mix/clip */ 504 Sound_GenerateChannel(pChannelA,psg[PSG_REG_CHANNEL_A_FINE],psg[PSG_REG_CHANNEL_A_COARSE],psg[PSG_REG_CHANNEL_A_AMP],psg[PSG_REG_MIXER_CONTROL],&ChannelFreq[0],0); 505 Sound_GenerateChannel(pChannelB,psg[PSG_REG_CHANNEL_B_FINE],psg[PSG_REG_CHANNEL_B_COARSE],psg[PSG_REG_CHANNEL_B_AMP],psg[PSG_REG_MIXER_CONTROL],&ChannelFreq[1],1); 506 Sound_GenerateChannel(pChannelC,psg[PSG_REG_CHANNEL_C_FINE],psg[PSG_REG_CHANNEL_C_COARSE],psg[PSG_REG_CHANNEL_C_AMP],psg[PSG_REG_MIXER_CONTROL],&ChannelFreq[2],2); 507 508 /* Mix channels together, using table to clip and also convert to 'unsigned char' */ 509 for(i=0; i<nSamplesToGenerate; i++) 510 MixBuffer[(i+ActiveSndBufIdx)%MIXBUFFER_SIZE] = pMixTable[(*pChannelA++) + (*pChannelB++) + (*pChannelC++)]; 511 512 ActiveSndBufIdx = (ActiveSndBufIdx + nSamplesToGenerate) % MIXBUFFER_SIZE; 513 nGeneratedSamples += nSamplesToGenerate; 514 515 /* Reset the write to register '13' flag */ 516 bWriteEnvelopeFreq = FALSE; 517 /* And amplitude write flags */ 518 bWriteChannelAAmp = bWriteChannelBAmp = bWriteChannelCAmp = FALSE; 519 } 520 } 521 522 523 /*-----------------------------------------------------------------------*/ 524 /* 525 This is called to built samples up until this clock cycle 526 */ 527 void Sound_Update(void) 528 { 529 int OldSndBufIdx = ActiveSndBufIdx; 530 531 /* Make sure that we don't interfere with the audio callback function */ 532 #ifndef DREAMCAST 533 Audio_Lock(); 534 #endif 535 536 /* Find how many to generate */ 537 Sound_SetSamplesPassed(); 538 /* And generate */ 539 Sound_GenerateSamples(); 540 541 /* Allow audio callback function to occur again */ 542 #ifndef DREAMCAST 543 Audio_Unlock(); 544 #endif 545 } 546 547 548 /*-----------------------------------------------------------------------*/ 549 /* 550 On each VBL (50fps) complete samples. 551 */ 552 void Sound_Update_VBL(void) 553 { 554 Sound_Update(); 555 556 /* Clear write to register '13', used for YM file saving */ 557 bEnvelopeFreqFlag = FALSE; 558 } 559 560 561 /*-----------------------------------------------------------------------*/ 562 /* 563 This is called from the audio callback function to create enough samples 564 to fill the current sound buffer. 565 */ 566 void Sound_UpdateFromAudioCallBack(void) 567 { 568 /* If there are already enough samples or if we are recording, we should 569 * not generate more samples here! */ 570 if(nGeneratedSamples >= SOUND_BUFFER_SIZE) 571 return; 572 573 nSamplesToGenerate = SOUND_BUFFER_SIZE - nGeneratedSamples; 574 575 Sound_GenerateSamples(); 576 } 577 578 579 580 /*-----------------------------------------------------------------------*/ 581 582 static void Audio_CallBack(void *userdata, uint8 *stream, int len) 583 { 584 int i; 585 586 uint16 *pBuffer; 587 588 589 /* If there are only some samples missing to have a complete buffer, 590 * we generate them here (sounds much better then!). However, if a lot of 591 * samples are missing, then the system is probably too slow, so we don't 592 * generate more samples to not make things worse... */ 593 594 if(nGeneratedSamples < len) 595 Sound_UpdateFromAudioCallBack(); 596 597 /* Pass completed buffer to audio system: Write samples into sound buffer 598 * and convert them from 'signed' to 'unsigned' */ 599 600 pBuffer = (uint16 *)stream; 601 602 for(i = 0; i < len; i++) 603 { 604 *pBuffer++ = ((int)((char)MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE]))*256; 605 } 606 607 /* We should now have generated a complete frame of samples. 608 * However, for slow systems we have to check how many generated samples 609 * we may advance... */ 610 if(nGeneratedSamples >= len) 611 { 612 CompleteSndBufIdx += len; 613 nGeneratedSamples -= len; 614 } 615 else 616 { 617 CompleteSndBufIdx += nGeneratedSamples; 618 nGeneratedSamples = 0; 619 } 620 CompleteSndBufIdx = CompleteSndBufIdx % MIXBUFFER_SIZE; 621 } 622 623 void Sound_UpdateFromCallBack16(short *pBuffer, int len) 624 { 625 Audio_CallBack(nullptr, (uint8 *)pBuffer, len); 626 } 627 628 629 630 #else 631 #warning NO_SOUND 632 #warning NO_SOUND 633 #warning NO_SOUND 634 #warning NO_SOUND 635 #warning NO_SOUND 636 #warning NO_SOUND 637 #endif