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

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

unix.superglobalmegacorp.com

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