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