|
|
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.10! root 22: const char Sound_rcsid[] = "Hatari $Id: sound.c,v 1.26 2006/08/01 09:23:05 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.10! root 28: #include "cycles.h"
1.1.1.9 root 29: #include "dmaSnd.h"
1.1 root 30: #include "file.h"
31: #include "int.h"
1.1.1.8 root 32: #include "log.h"
1.1 root 33: #include "memorySnapShot.h"
34: #include "misc.h"
35: #include "psg.h"
36: #include "sound.h"
37: #include "video.h"
38: #include "wavFormat.h"
39: #include "ymFormat.h"
40:
1.1.1.5 root 41: #define LONGLONG Uint64
1.1 root 42:
1.1.1.8 root 43: #define ENVELOPE_PERIOD(Fine,Coarse) ((((Uint32)Coarse)<<8) + (Uint32)Fine)
44: #define NOISE_PERIOD(Freq) (((((Uint32)Freq)&0x1f)<<11))
45: #define TONE_PERIOD(Fine,Coarse) (((((Uint32)Coarse)&0x0f)<<8) + (Uint32)Fine)
1.1.1.5 root 46: #define MIXTABLE_SIZE (256*8) /* Large table, so don't overflow */
47: #define TONEFREQ_SHIFT 28 /* 4.28 fixed point */
48: #define NOISEFREQ_SHIFT 28 /* 4.28 fixed point */
49: #define ENVFREQ_SHIFT 16 /* 16.16 fixed */
1.1 root 50:
1.1.1.6 root 51: #define SAMPLES_BUFFER_SIZE 1024
52: /* Number of generated samples per frame (eg. 44Khz=882) : */
53: #define SAMPLES_PER_FRAME ((SoundPlayBackFrequencies[OutputAudioFreqIndex]+35)/nScreenRefreshRate)
54: /* Frequency of generated samples: */
55: #define SAMPLES_FREQ (SoundPlayBackFrequencies[OutputAudioFreqIndex])
56: #define YM_FREQ (2000000/SAMPLES_FREQ) /* YM Frequency 2Mhz */
57:
58:
1.1 root 59: /* Original wave samples */
1.1.1.7 root 60: static int EnvelopeShapeValues[16*1024]; /* Shape x Length(repeat 3rd/4th entries) */
1.1 root 61: /* Frequency and time period samples */
1.1.1.8 root 62: static Uint32 ChannelFreq[3], EnvelopeFreq, NoiseFreq; /* Current frequency of each channel A,B,C,Envelope and Noise */
1.1.1.7 root 63: static int ChannelAmpDecayTime[3]; /* Store counter to show if amplitude is changed to generate 'samples' */
64: static int Envelope[SAMPLES_BUFFER_SIZE],Noise[SAMPLES_BUFFER_SIZE]; /* Current sample for this time period */
1.1 root 65: /* Output channel data */
1.1.1.7 root 66: 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 67: /* Use table to convert from (A+B+C) to clipped 8-bit for sound buffer */
68: static Sint8 MixTable[MIXTABLE_SIZE]; /* -ve and +ve range */
69: static Sint8 *pMixTable = &MixTable[MIXTABLE_SIZE/2]; /* Signed index into above */
1.1.1.7 root 70: static int ActiveSndBufIdx; /* Current working index into above mix buffer */
71: static int nSamplesToGenerate; /* How many samples are needed for this time-frame */
72:
73: /* global values */
1.1 root 74: BOOL bWriteEnvelopeFreq; /* Did write to register '13' - causes frequency reset */
1.1.1.5 root 75: BOOL bWriteChannelAAmp, bWriteChannelBAmp, bWriteChannelCAmp; /* Did write to amplitude registers? */
1.1 root 76: BOOL bEnvelopeFreqFlag; /* As above, but cleared each frame for YM saving */
1.1.1.2 root 77: /* Buffer to store circular samples */
1.1.1.9 root 78: Sint8 MixBuffer[MIXBUFFER_SIZE];
1.1.1.5 root 79: int nGeneratedSamples; /* Generated samples since audio buffer update */
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.10! root 90: static const 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.10! root 111: static const 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.10! root 154: static void Sound_CreateEnvelopeShape(const 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 */
1.1.1.10! root 233: Cycles_SetCounter(CYCLES_COUNTER_SOUND, 0);
1.1.1.7 root 234: bEnvelopeFreqFlag = FALSE;
235: bWriteEnvelopeFreq = FALSE;
236: bWriteChannelAAmp = bWriteChannelBAmp = bWriteChannelCAmp = FALSE;
237:
238: CompleteSndBufIdx = 0;
1.1.1.10! root 239: /* We do not start with 0 here to fake some initial samples: */
! 240: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
! 241: ActiveSndBufIdx = nGeneratedSamples % MIXBUFFER_SIZE;
1.1.1.7 root 242:
243: /* Clear frequency counter */
244: for(i=0; i<3; i++)
245: {
246: ChannelFreq[i] =
247: ChannelAmpDecayTime[i] = 0;
248: }
249: EnvelopeFreq = NoiseFreq = 0;
1.1.1.9 root 250:
251: Audio_Unlock();
1.1.1.7 root 252: }
253:
254:
255: /*-----------------------------------------------------------------------*/
256: /*
1.1.1.9 root 257: Reset the sound buffer index variables.
1.1.1.7 root 258: */
1.1.1.9 root 259: void Sound_ResetBufferIndex(void)
1.1.1.7 root 260: {
261: Audio_Lock();
1.1.1.10! root 262: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
! 263: ActiveSndBufIdx = (CompleteSndBufIdx + nGeneratedSamples) % MIXBUFFER_SIZE;
1.1.1.7 root 264: Audio_Unlock();
265: }
266:
267:
268: /*-----------------------------------------------------------------------*/
269: /*
270: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
271: */
272: void Sound_MemorySnapShot_Capture(BOOL bSave)
273: {
274: /* Save/Restore details */
275: MemorySnapShot_Store(ChannelFreq,sizeof(ChannelFreq));
276: MemorySnapShot_Store(&EnvelopeFreq,sizeof(EnvelopeFreq));
277: MemorySnapShot_Store(&NoiseFreq,sizeof(NoiseFreq));
278: }
279:
280:
281: /*-----------------------------------------------------------------------*/
282: /*
1.1 root 283: Find how many samples to generate and store in 'nSamplesToGenerate'
1.1.1.10! root 284: Also update sound cycles counter to store how many we actually did
! 285: so generates set amount each frame.
1.1 root 286: */
1.1.1.7 root 287: static void Sound_SetSamplesPassed(void)
1.1 root 288: {
289: int nSampleCycles;
1.1.1.7 root 290: int nSamplesPerFrame;
1.1 root 291: int Dec=1;
1.1.1.10! root 292: int nSoundCycles;
! 293:
! 294: nSoundCycles = Cycles_GetCounter(CYCLES_COUNTER_SOUND);
1.1 root 295:
1.1.1.2 root 296: /* Check how many cycles have passed, as we use this to help find out if we are playing sample data */
1.1 root 297:
1.1.1.2 root 298: /* First, add decay to channel amplitude variables */
1.1.1.10! root 299: if (nSoundCycles > (CYCLES_PER_FRAME/4))
1.1.1.2 root 300: Dec = 16; /* Been long time between sound writes, must be normal tone sound */
1.1 root 301:
1.1.1.5 root 302: if (!bWriteChannelAAmp) /* Not written to amplitude, decay value */
303: {
1.1 root 304: ChannelAmpDecayTime[0]-=Dec;
305: if (ChannelAmpDecayTime[0]<0) ChannelAmpDecayTime[0] = 0;
306: }
1.1.1.5 root 307: if (!bWriteChannelBAmp)
308: {
1.1 root 309: ChannelAmpDecayTime[1]-=Dec;
310: if (ChannelAmpDecayTime[1]<0) ChannelAmpDecayTime[1] = 0;
311: }
1.1.1.5 root 312: if (!bWriteChannelCAmp)
313: {
1.1 root 314: ChannelAmpDecayTime[2]-=Dec;
315: if (ChannelAmpDecayTime[2]<0) ChannelAmpDecayTime[2] = 0;
316: }
317:
1.1.1.2 root 318: /* 160256 cycles per VBL, 44Khz = 882 samples per VBL */
319: /* 882/160256 samples per clock cycle */
1.1.1.7 root 320: nSamplesPerFrame = SAMPLES_PER_FRAME;
1.1 root 321:
1.1.1.10! root 322: nSamplesToGenerate = nSoundCycles * nSamplesPerFrame / CYCLES_PER_FRAME;
1.1.1.7 root 323: if (nSamplesToGenerate > nSamplesPerFrame)
324: nSamplesToGenerate = nSamplesPerFrame;
325:
326: nSampleCycles = nSamplesToGenerate * CYCLES_PER_FRAME / nSamplesPerFrame;
1.1.1.10! root 327: nSoundCycles -= nSampleCycles;
! 328: Cycles_SetCounter(CYCLES_COUNTER_SOUND, nSoundCycles);
! 329:
! 330: if (nSamplesToGenerate > MIXBUFFER_SIZE - nGeneratedSamples)
! 331: {
! 332: nSamplesToGenerate = MIXBUFFER_SIZE - nGeneratedSamples;
! 333: if (nSamplesToGenerate < 0)
! 334: nSamplesToGenerate = 0;
! 335: }
1.1 root 336: }
337:
1.1.1.5 root 338:
1.1.1.2 root 339: /*-----------------------------------------------------------------------*/
1.1 root 340: /*
341: Generate envelope wave for this time-frame
342: */
1.1.1.7 root 343: static void Sound_GenerateEnvelope(unsigned char EnvShape, unsigned char Fine, unsigned char Coarse)
1.1 root 344: {
345: int *pEnvelopeValues;
1.1.1.8 root 346: Uint32 EnvelopePeriod, EnvelopeFreqDelta;
1.1 root 347: int i;
348:
1.1.1.2 root 349: /* Find envelope details */
1.1 root 350: if (bWriteEnvelopeFreq)
351: EnvelopeFreq = 0;
1.1.1.2 root 352: pEnvelopeValues = &EnvelopeShapeValues[ (EnvShape&0x0f)*1024 ]; /* Envelope shape values */
1.1.1.8 root 353: EnvelopePeriod = ENVELOPE_PERIOD((Uint32)Fine, (Uint32)Coarse);
1.1 root 354:
1.1.1.2 root 355: if (EnvelopePeriod==0) /* Handle div by zero */
1.1 root 356: EnvelopeFreqDelta = 0;
357: else
1.1.1.2 root 358: EnvelopeFreqDelta = ((LONGLONG)YM_FREQ<<ENVFREQ_SHIFT) / (EnvelopePeriod); /* 16.16 fixed point */
1.1 root 359:
1.1.1.2 root 360: /* Create envelope from current shape and frequency */
1.1.1.5 root 361: for(i=0; i<nSamplesToGenerate; i++)
362: {
1.1.1.2 root 363: Envelope[i] = pEnvelopeValues[EnvelopeFreq>>ENVFREQ_SHIFT]; /* Store envelope wave, already applied 'log' function */
1.1 root 364: EnvelopeFreq += EnvelopeFreqDelta;
365: if (EnvelopeFreq&0xfe000000)
1.1.1.2 root 366: EnvelopeFreq = 0x02000000 | (EnvelopeFreq&0x01ffffff); /* Keep in range 512-1024 once past 511! */
1.1 root 367: }
368: }
369:
1.1.1.5 root 370:
1.1.1.2 root 371: /*-----------------------------------------------------------------------*/
1.1 root 372: /*
373: Generate nosie for this time-frame
374: */
1.1.1.7 root 375: static void Sound_GenerateNoise(unsigned char MixerControl, unsigned char NoiseGen)
1.1 root 376: {
377: int NoiseValue;
1.1.1.8 root 378: Uint32 NoisePeriod, NoiseFreqDelta;
1.1 root 379: int i;
380:
1.1.1.8 root 381: NoisePeriod = NOISE_PERIOD((Uint32)NoiseGen);
1.1 root 382:
1.1.1.2 root 383: if (NoisePeriod==0) /* Handle div by zero */
1.1 root 384: NoiseFreqDelta = 0;
385: else
1.1.1.2 root 386: NoiseFreqDelta = (((LONGLONG)YM_FREQ)<<NOISEFREQ_SHIFT) / NoisePeriod; /* 4.28 fixed point */
1.1 root 387:
1.1.1.2 root 388: /* Generate noise samples */
1.1.1.5 root 389: for(i=0; i<nSamplesToGenerate; i++)
390: {
1.1.1.2 root 391: NoiseValue = (unsigned int)Misc_GetRandom()%96; /* Get random value */
392: if (SquareWave[NoiseFreq>>NOISEFREQ_SHIFT]<=0) /* Add to square wave at given frequency */
1.1 root 393: NoiseValue = -NoiseValue;
394:
395: Noise[i] = NoiseValue;
396: NoiseFreq += NoiseFreqDelta;
397: }
398: }
399:
1.1.1.5 root 400:
1.1.1.2 root 401: /*-----------------------------------------------------------------------*/
1.1 root 402: /*
403: Generate channel of samples for this time-frame
404: */
1.1.1.8 root 405: 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 406: {
407: int *pNoise = Noise, *pEnvelope = Envelope;
1.1.1.8 root 408: Uint32 ToneFreq = *pChannelFreq;
409: Uint32 TonePeriod;
410: Uint32 ToneFreqDelta;
1.1 root 411: int i,Amp,Mix;
412: int ToneOutput,NoiseOutput,MixerOutput,EnvelopeOutput,AmplitudeOutput;
413:
1.1.1.8 root 414: TonePeriod = TONE_PERIOD((Uint32)ToneFine, (Uint32)ToneCoarse);
1.1.1.2 root 415: /* Find frequency of channel */
1.1 root 416: if (TonePeriod==0)
1.1.1.2 root 417: ToneFreqDelta = 0; /* Handle div by zero */
1.1 root 418: else
1.1.1.2 root 419: ToneFreqDelta = (((LONGLONG)YM_FREQ)<<TONEFREQ_SHIFT) / TonePeriod; /* 4.28 fixed point */
1.1 root 420: Amp = LogTable16[(Amplitude&0x0f)];
1.1.1.2 root 421: Mix = (MixerControl>>MixMask)&9; /* Read I/O Mixer */
1.1 root 422:
1.1.1.2 root 423: /* 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 424: if ((Amplitude&0x10)==0) /* Fixed level amplitude? */
425: {
1.1.1.2 root 426: ChannelAmpDecayTime[MixMask]++; /* Increment counter to find out if we are playing samples... */
1.1 root 427: if (ChannelAmpDecayTime[MixMask]>16)
1.1.1.2 root 428: ChannelAmpDecayTime[MixMask] = 16; /* And limit */
1.1 root 429: }
430:
1.1.1.5 root 431: for(i=0; i<nSamplesToGenerate; i++)
432: {
1.1.1.2 root 433: /* Output from Tone Generator(0-255) */
1.1 root 434: ToneOutput = SquareWave[ToneFreq>>TONEFREQ_SHIFT];
435:
1.1.1.2 root 436: /* Output from Noise Generator(0-255) */
1.1 root 437: NoiseOutput = *pNoise++;
1.1.1.2 root 438: /* Output from Mixer(combines Tone+Noise) */
1.1 root 439: switch (Mix) {
1.1.1.2 root 440: case 0: /* Has Noise and Tone */
1.1 root 441: MixerOutput = NoiseOutput+ToneOutput;
442: break;
1.1.1.2 root 443: case 1: /* Has Noise */
1.1 root 444: MixerOutput = NoiseOutput;
445: break;
1.1.1.2 root 446: case 8: /* Has Tone */
1.1 root 447: MixerOutput = ToneOutput;
448: break;
449:
1.1.1.2 root 450: default: /* This is used to emulate samples - should give no output, but ST gives set tone!!?? */
451: /* MixerControl gets set to give a continuous tone and then then Amplitude */
452: /* of channels A,B and C get changed with all other registers in the PSG */
453: /* staying as zero's. This produces the sounds from Quartet, Speech, NoiseTracker etc...! */
1.1 root 454: MixerOutput = 127;
455: }
456:
457: EnvelopeOutput = pEnvelopeLogTable[*pEnvelope++];
458:
1.1.1.5 root 459: if ((Amplitude&0x10)==0)
460: {
1.1.1.2 root 461: AmplitudeOutput = Amp; /* Fixed level amplitude */
1.1 root 462:
1.1.1.2 root 463: /* As with most emulators, sample playback is always 'quiet'. We check to see if */
464: /* the amplitude of a channel is repeatedly changing and when this is detected we */
465: /* scale the volume accordingly */
1.1 root 466: if (ChannelAmpDecayTime[MixMask]>8)
1.1.1.2 root 467: AmplitudeOutput <<= 1; /* Scale up by a factor of 2 */
1.1 root 468: }
469: else
470: AmplitudeOutput = EnvelopeOutput;
471:
472: *pBuffer++ = (MixerOutput*AmplitudeOutput)>>8;
473:
474: ToneFreq+=ToneFreqDelta;
475: }
476:
1.1.1.2 root 477: /* Store back incremented frequency, for next call */
1.1 root 478: *pChannelFreq = ToneFreq;
479: }
480:
1.1.1.5 root 481:
1.1.1.2 root 482: /*-----------------------------------------------------------------------*/
1.1 root 483: /*
484: Generate samples for all channels during this time-frame
485: */
1.1.1.5 root 486: static void Sound_GenerateSamples(void)
1.1 root 487: {
488: int *pChannelA=Channel_A_Buffer, *pChannelB=Channel_B_Buffer, *pChannelC=Channel_C_Buffer;
489: int i;
490:
1.1.1.2 root 491: /* Anything to do? */
1.1.1.5 root 492: if (nSamplesToGenerate>0)
493: {
1.1.1.2 root 494: /* Generate envelope/noise samples for this time */
1.1 root 495: Sound_GenerateEnvelope(PSGRegisters[PSG_REG_ENV_SHAPE],PSGRegisters[PSG_REG_ENV_FINE],PSGRegisters[PSG_REG_ENV_COARSE]);
496: Sound_GenerateNoise(PSGRegisters[PSG_REG_MIXER_CONTROL],PSGRegisters[PSG_REG_NOISE_GENERATOR]);
497:
1.1.1.2 root 498: /* Generate 3 channels, store to separate buffer so can mix/clip */
1.1 root 499: 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);
500: 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);
501: 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);
502:
1.1.1.9 root 503: /* Mix channels together, using table to clip and convert to proper 8-bit type */
1.1 root 504: for(i=0; i<nSamplesToGenerate; i++)
1.1.1.5 root 505: MixBuffer[(i+ActiveSndBufIdx)%MIXBUFFER_SIZE] = pMixTable[(*pChannelA++) + (*pChannelB++) + (*pChannelC++)];
506:
1.1.1.9 root 507: DmaSnd_GenerateSamples(ActiveSndBufIdx, nSamplesToGenerate);
508:
1.1.1.5 root 509: ActiveSndBufIdx = (ActiveSndBufIdx + nSamplesToGenerate) % MIXBUFFER_SIZE;
510: nGeneratedSamples += nSamplesToGenerate;
511:
1.1.1.2 root 512: /* Reset the write to register '13' flag */
1.1 root 513: bWriteEnvelopeFreq = FALSE;
1.1.1.2 root 514: /* And amplitude write flags */
1.1 root 515: bWriteChannelAAmp = bWriteChannelBAmp = bWriteChannelCAmp = FALSE;
516: }
517: }
518:
1.1.1.5 root 519:
1.1.1.2 root 520: /*-----------------------------------------------------------------------*/
1.1 root 521: /*
1.1.1.5 root 522: This is called to built samples up until this clock cycle
1.1 root 523: */
1.1.1.5 root 524: void Sound_Update(void)
1.1 root 525: {
1.1.1.5 root 526: int OldSndBufIdx = ActiveSndBufIdx;
527:
1.1.1.6 root 528: /* Make sure that we don't interfere with the audio callback function */
529: Audio_Lock();
530:
1.1.1.5 root 531: /* Find how many to generate */
1.1 root 532: Sound_SetSamplesPassed();
1.1.1.2 root 533: /* And generate */
1.1 root 534: Sound_GenerateSamples();
535:
1.1.1.6 root 536: /* Allow audio callback function to occur again */
537: Audio_Unlock();
538:
1.1.1.2 root 539: /* Save to WAV file, if open */
1.1.1.5 root 540: WAVFormat_Update(MixBuffer, OldSndBufIdx, nSamplesToGenerate);
1.1 root 541: }
542:
1.1.1.5 root 543:
1.1.1.2 root 544: /*-----------------------------------------------------------------------*/
1.1 root 545: /*
1.1.1.5 root 546: On each VBL (50fps) complete samples.
1.1 root 547: */
1.1.1.5 root 548: void Sound_Update_VBL(void)
1.1 root 549: {
1.1.1.5 root 550: Sound_Update();
551:
552: /* Clear write to register '13', used for YM file saving */
553: bEnvelopeFreqFlag = FALSE;
1.1 root 554: }
555:
556:
1.1.1.2 root 557: /*-----------------------------------------------------------------------*/
1.1 root 558: /*
559: Start recording sound, as .YM or .WAV output
560: */
561: BOOL Sound_BeginRecording(char *pszCaptureFileName)
562: {
563: BOOL bRet;
564:
1.1.1.7 root 565: if (!pszCaptureFileName || strlen(pszCaptureFileName) <= 3)
566: {
1.1.1.8 root 567: Log_Printf(LOG_ERROR, "Illegal sound recording file name!\n");
1.1.1.7 root 568: return FALSE;
569: }
570:
1.1.1.2 root 571: /* Did specify .YM or .WAV? If neither report error */
1.1.1.7 root 572: if (File_DoesFileExtensionMatch(pszCaptureFileName,".ym"))
1.1.1.4 root 573: bRet = YMFormat_BeginRecording(pszCaptureFileName);
1.1 root 574: else if (File_DoesFileExtensionMatch(pszCaptureFileName,".wav"))
1.1.1.4 root 575: bRet = WAVFormat_OpenFile(pszCaptureFileName);
1.1.1.5 root 576: else
577: {
1.1.1.8 root 578: Log_AlertDlg(LOG_ERROR, "Unknown Sound Recording format.\n"
579: "Please specify a .YM or .WAV output file.");
1.1 root 580: bRet = FALSE;
581: }
582:
1.1.1.8 root 583: return bRet;
1.1 root 584: }
585:
1.1.1.5 root 586:
1.1.1.2 root 587: /*-----------------------------------------------------------------------*/
1.1 root 588: /*
589: End sound recording
590: */
1.1.1.7 root 591: void Sound_EndRecording(void)
1.1 root 592: {
1.1.1.2 root 593: /* Stop sound recording and close files */
1.1 root 594: if (bRecordingYM)
1.1.1.4 root 595: YMFormat_EndRecording();
1.1 root 596: if (bRecordingWav)
1.1.1.4 root 597: WAVFormat_CloseFile();
1.1 root 598: }
599:
1.1.1.6 root 600:
1.1.1.2 root 601: /*-----------------------------------------------------------------------*/
1.1 root 602: /*
603: Are we recording sound data?
604: */
605: BOOL Sound_AreWeRecording(void)
606: {
607: return(bRecordingYM || bRecordingWav);
608: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.