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

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

unix.superglobalmegacorp.com

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