Annotation of hatari/src/sound.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.