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

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

unix.superglobalmegacorp.com

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