|
|
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: NOTE: If the emulator runs slower than 50fps it cannot update the buffers,
15: but the sound thread still needs some data to play to prevent a 'pop'. The
16: ONLY feasible solution is to play the same buffer again. I have tried all
17: kinds of methods to play the sound 'slower', but this produces un-even timing
18: in the sound and it simply doesn't work. If the emulator cannot keep the
19: speed, users will have to turn off the sound - that's it.
1.1.1.12! root 20:
! 21: The new version of the sound core uses some code/ideas from the following GPL projects :
! 22: - tone and noise steps computations are from StSound 1.2 by Arnaud Carr� (Leonard/Oxygene)
! 23: - 5 bits volume table and 16*16*16 combinations of all volume are from Sc68 by Benjamin Gerard
! 24: - 4 bits to 5 bits volume interpolation from 16*16*16 to 32*32*32 from YM blep synthesis by Antti Lankila
! 25:
1.1 root 26: */
1.1.1.12! root 27:
! 28: /* 2008/05/05 [NP] Fix case where period is 0 for noise, sound or envelope. */
! 29: /* In that case, a real ST sounds as if period was in fact 1. */
! 30: /* (fix buggy sound replay in ESwat that set volume<0 and trigger */
! 31: /* a badly initialised envelope with envper=0). */
! 32: /* 2008/07/27 [NP] Better separation between accesses to the YM hardware registers */
! 33: /* and the sound rendering routines. Use Sound_WriteReg() to pass */
! 34: /* all writes to the sound rendering functions. This allows to */
! 35: /* have sound.c independant of psg.c (to ease replacement of */
! 36: /* sound.c by another rendering method). */
! 37: /* 2008/08/02 [NP] Initial convert of Ym2149Ex.cpp from C++ to C. */
! 38: /* Remove unused part of the code (StSound specific). */
! 39: /* 2008/08/09 [NP] Complete integration of StSound routines into sound.c */
! 40: /* Set EnvPer=3 if EnvPer<3 (ESwat buggy replay). */
! 41: /* 2008/08/13 [NP] StSound was generating samples in the range 0-32767, instead */
! 42: /* of really signed samples between -32768 and 32767, which could */
! 43: /* give incorrect results in many case. */
! 44: /* 2008/09/06 [NP] Use sc68 volumes table for a more accurate mixing of the voices */
! 45: /* All volumes are converted to 5 bits and the table contains */
! 46: /* 32*32*32 values. Samples are signed and centered to get the */
! 47: /* biggest amplitude possible. */
! 48: /* Faster mixing routines for tone+volume+envelope (don't use */
! 49: /* StSound's version anymore, it gave problem with some GCC). */
! 50: /* 2008/09/17 [NP] Add ym_normalise_5bit_table to normalise the 32*32*32 table and */
! 51: /* to optionally center 16 bit signed sample. */
! 52: /* Possibility to mix volumes using a table measured on ST or a */
! 53: /* linear mean of the 3 channels' volume. */
! 54: /* Default mixing set to YM_LINEAR_MIXING. */
! 55: /* 2008/10/14 [NP] Full support for 5 bits volumes : envelopes are generated with */
! 56: /* 32 volumes per pattern as on a real YM-2149. Fixed volumes */
! 57: /* on 4 bits are converted to their 5 bits equivalent. This should */
! 58: /* give the maximum accuracy possible when computing volumes. */
! 59: /* New version of Ym2149_EnvStepCompute to handle 5 bits volumes. */
! 60: /* Function YM2149_EnvBuild to compute the 96 volumes that define */
! 61: /* a single envelope (32 initial volumes, then 64 repeated values).*/
! 62: /* 2008/10/26 [NP] Correctly save/restore all necessary variables in */
! 63: /* Sound_MemorySnapShot_Capture. */
! 64: /* 2008/11/23 [NP] Clean source, remove old sound core. */
! 65:
! 66:
! 67:
! 68: const char Sound_rcsid[] = "Hatari $Id: sound.c,v 1.53 2008/11/23 11:49:03 npomarede Exp $";
1.1.1.5 root 69:
70: #include <SDL_types.h>
1.1 root 71:
72: #include "main.h"
73: #include "audio.h"
1.1.1.10 root 74: #include "cycles.h"
1.1.1.9 root 75: #include "dmaSnd.h"
1.1 root 76: #include "file.h"
77: #include "int.h"
1.1.1.8 root 78: #include "log.h"
1.1 root 79: #include "memorySnapShot.h"
80: #include "psg.h"
81: #include "sound.h"
82: #include "video.h"
83: #include "wavFormat.h"
84: #include "ymFormat.h"
85:
86:
87:
1.1.1.12! root 88: /*--------------------------------------------------------------*/
! 89: /* Definition of the possible envelopes shapes (using 5 bits) */
! 90: /*--------------------------------------------------------------*/
! 91:
! 92: #define ENV_GODOWN 0 /* 31 -> 0 */
! 93: #define ENV_GOUP 1 /* 0 -> 31 */
! 94: #define ENV_DOWN 2 /* 0 -> 0 */
! 95: #define ENV_UP 3 /* 31 -> 31 */
! 96:
! 97: /* To generate an envelope, we first use block 0, then we repeat blocks 1 and 2 */
! 98: static const int YmEnvDef[ 16 ][ 3 ] = {
! 99: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 0 \___ */
! 100: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 1 \___ */
! 101: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 2 \___ */
! 102: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 3 \___ */
! 103: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 4 /___ */
! 104: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 5 /___ */
! 105: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 6 /___ */
! 106: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 7 /___ */
! 107: { ENV_GODOWN, ENV_GODOWN, ENV_GODOWN } , /* 8 \\\\ */
! 108: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 9 \___ */
! 109: { ENV_GODOWN, ENV_GOUP, ENV_GODOWN } , /* A \/\/ */
! 110: { ENV_GODOWN, ENV_UP, ENV_UP } , /* B \--- */
! 111: { ENV_GOUP, ENV_GOUP, ENV_GOUP } , /* C //// */
! 112: { ENV_GOUP, ENV_UP, ENV_UP } , /* D /--- */
! 113: { ENV_GOUP, ENV_GODOWN, ENV_GOUP } , /* E /\/\ */
! 114: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* F /___ */
! 115: };
! 116:
! 117:
! 118: /* Buffer to store the 16 envelopes built from YmEnvDef */
! 119: static ymu16 YmEnvWaves[ 16 ][ 32 * 3 ]; /* 16 envelopes with 3 blocks of 32 volumes */
1.1.1.3 root 120:
1.1 root 121:
1.1.1.12! root 122:
! 123: /*--------------------------------------------------------------*/
! 124: /* Definition of the volumes tables (using 5 bits) and of the */
! 125: /* mixing parameters for the 3 voices. */
! 126: /*--------------------------------------------------------------*/
! 127:
! 128: /* Table of unsigned 5 bit D/A output level for 1 channel as measured on a real ST (expanded from 4 bits to 5 bits) */
! 129: /* Vol 0 should be 310 when measuread as a voltage, but we set it to 0 in order to have a volume=0 matching */
! 130: /* the 0 level of a 16 bits unsigned sample (no sound output) */
! 131: static const ymu16 ymout1c5bit[ 32 ] =
! 132: {
! 133: 0 /*310*/, 369, 438, 521, 619, 735, 874, 1039,
! 134: 1234, 1467, 1744, 2072, 2463, 2927, 3479, 4135,
! 135: 4914, 5841, 6942, 8250, 9806,11654,13851,16462,
! 136: 19565,23253,27636,32845,39037,46395,55141,65535
1.1 root 137: };
138:
1.1.1.12! root 139: /* Convert a constant 4 bits volume to the internal 5 bits value : */
! 140: /* volume5=volume4*2+1, except for volumes 0 and 1 which become 0 and 2, */
! 141: /* in order to map [0,15] into [0,31] (O must remain 0, and 15 must give 31) */
! 142: static const ymu16 YmVolume4to5[ 16 ] = { 0,2,5,7,9,11,13,15,17,19,21,23,25,27,29,31 };
1.1 root 143:
1.1.1.12! root 144: /* Table of unsigned 4 bit D/A output level for 3 channels as measured on a real ST */
! 145: static ymu16 volumetable_original[ 16 * 16 * 16 ] =
! 146: #include "ym2149_fixed_vol.h"
1.1.1.5 root 147:
1.1.1.12! root 148: /* Corresponding table interpolated to 5 bit D/A output level (16 bits unsigned) */
! 149: static ymu16 ymout5_u16[ 32 * 32 * 32 ];
! 150:
! 151: /* Same table, after conversion to signed results (same pointer, with different type) */
! 152: static yms16 *ymout5 = (yms16 *)ymout5_u16;
! 153:
! 154:
! 155:
! 156: /*--------------------------------------------------------------*/
! 157: /* Other constants / macros */
! 158: /*--------------------------------------------------------------*/
! 159:
! 160: /* Number of generated samples per frame (eg. 44Khz=882) */
! 161: #define SAMPLES_PER_FRAME ((SoundPlayBackFrequencies[OutputAudioFreqIndex]+35)/nScreenRefreshRate)
! 162:
! 163: /* Current sound replay freq (usually 44100 Hz) */
! 164: #define YM_REPLAY_FREQ (SoundPlayBackFrequencies[OutputAudioFreqIndex])
! 165:
! 166: /* YM-2149 clock on Atari ST is 2 MHz */
! 167: #define YM_ATARI_CLOCK 2000000
! 168:
! 169:
! 170: /* Merge/read the 3 volumes in a single integer (5 bits per volume) */
! 171: #define YM_MERGE_VOICE(C,B,A) ( (C)<<10 | (B)<<5 | A )
! 172: #define YM_MASK_1VOICE 0x1f
! 173: #define YM_MASK_A 0x1f
! 174: #define YM_MASK_B (0x1f<<5)
! 175: #define YM_MASK_C (0x1f<<10)
! 176:
! 177:
! 178: /* Constants for YM2149_Normalise_5bit_Table */
! 179: #define YM_OUTPUT_LEVEL 0x7fff /* amplitude of the final signal (0..65535 if centered, 0..32767 if not) */
! 180: #define YM_OUTPUT_CENTERED FALSE
! 181:
! 182:
! 183:
! 184: /*--------------------------------------------------------------*/
! 185: /* Variables for the DC adjuster / Low Pass Filter */
! 186: /*--------------------------------------------------------------*/
! 187: #define DC_ADJUST_BUFFERLEN 512 /* must be a power of 2 */
! 188:
! 189: static ymsample dc_buffer[DC_ADJUST_BUFFERLEN];
! 190: static int dc_pos;
! 191: static int dc_sum;
! 192: static ymsample m_lowPassFilter[2];
! 193:
! 194:
! 195:
! 196: /*--------------------------------------------------------------*/
! 197: /* Variables for the YM2149 emulator (need to be saved and */
! 198: /* restored in memory snapshots) */
! 199: /*--------------------------------------------------------------*/
! 200:
! 201: static ymu32 stepA , stepB , stepC;
! 202: static ymu32 posA , posB , posC;
! 203: static ymu32 mixerTA , mixerTB , mixerTC;
! 204: static ymu32 mixerNA , mixerNB , mixerNC;
! 205:
! 206: static ymu32 noiseStep;
! 207: static ymu32 noisePos;
! 208: static ymu32 currentNoise;
! 209: static ymu32 RndRack; /* current random seed */
! 210:
! 211: static ymu32 envStep;
! 212: static ymu32 envPos;
! 213: static int envShape;
! 214:
! 215: static ymu16 EnvMask3Voices = 0; /* mask is 0x1f for voices having an active envelope */
! 216: static ymu16 Vol3Voices = 0; /* volume 0-0x1f for voices having a constant volume */
! 217: /* volume is set to 0 if voice has an envelope in EnvMask3Voices */
! 218:
! 219:
! 220: /* Global variables that can be changed/read from other parts of Hatari */
! 221: Uint8 SoundRegs[ 14 ];
! 222:
! 223: int YmVolumeMixing = YM_LINEAR_MIXING;
! 224: bool UseLowPassFilter = FALSE;
! 225:
! 226: bool bEnvelopeFreqFlag; /* Cleared each frame for YM saving */
! 227:
! 228: Sint16 MixBuffer[MIXBUFFER_SIZE][2];
! 229: int nGeneratedSamples; /* Generated samples since audio buffer update */
! 230: int nSamplesToGenerate; /* How many samples are needed for this time-frame */
! 231: static int ActiveSndBufIdx; /* Current working index into above mix buffer */
! 232:
! 233:
! 234:
! 235: /*--------------------------------------------------------------*/
! 236: /* Local functions prototypes */
! 237: /*--------------------------------------------------------------*/
! 238:
! 239: static void DcAdjuster_Reset (void);
! 240: static void DcAdjuster_AddSample (ymsample sample);
! 241: static ymsample DcAdjuster_GetDcLevel (void);
! 242: static void LowPassFilter_Reset (void);
! 243: static ymsample LowPassFilter (ymsample in);
! 244:
! 245: static int volumetable_get (int i, int j, int k);
! 246: static void volumetable_set (ymu16 *volumetable, int i, int j, int k, int val);
! 247: static int volumetable_interpolate (int y1, int y2);
! 248: static void interpolate_volumetable (ymu16 *out);
! 249:
! 250: static void YM2149_BuildLinearVolumeTable(ymu16 *out);
! 251: static void YM2149_Normalise_5bit_Table(ymu16 *in_5bit , yms16 *out_5bit, unsigned int Level, bool DoCenter);
! 252:
! 253: static void YM2149_EnvBuild (void);
! 254: static void Ym2149_Init (void);
! 255: static void Ym2149_Reset (void);
! 256:
! 257: static ymu32 YM2149_RndCompute (void);
! 258: static ymu32 Ym2149_ToneStepCompute (ymu8 rHigh , ymu8 rLow);
! 259: static ymu32 Ym2149_NoiseStepCompute (ymu8 rNoise);
! 260: static ymu32 Ym2149_EnvStepCompute (ymu8 rHigh , ymu8 rLow);
! 261: static ymsample YM2149_NextSample (void);
! 262:
! 263: static void Sound_SetSamplesPassed (void);
! 264: static void Sound_GenerateSamples (void);
! 265:
! 266:
! 267:
! 268: /*--------------------------------------------------------------*/
! 269: /* DC Adjuster / Low Pass Filter routines. */
! 270: /*--------------------------------------------------------------*/
! 271:
! 272: static void DcAdjuster_Reset(void)
! 273: {
! 274: int i;
! 275:
! 276: for (i=0 ; i<DC_ADJUST_BUFFERLEN ; i++)
! 277: dc_buffer[i] = 0;
! 278:
! 279: dc_pos = 0;
! 280: dc_sum = 0;
! 281: }
! 282:
! 283:
! 284: static void DcAdjuster_AddSample(ymsample sample)
1.1 root 285: {
1.1.1.12! root 286: dc_sum -= dc_buffer[dc_pos];
! 287: dc_sum += sample;
1.1 root 288:
1.1.1.12! root 289: dc_buffer[dc_pos] = sample;
! 290: dc_pos = (dc_pos+1)&(DC_ADJUST_BUFFERLEN-1);
! 291: }
! 292:
! 293:
! 294: static ymsample DcAdjuster_GetDcLevel(void)
! 295: {
! 296: return dc_sum / DC_ADJUST_BUFFERLEN;
! 297: }
! 298:
! 299:
! 300: static void LowPassFilter_Reset(void)
! 301: {
! 302: m_lowPassFilter[0] = 0;
! 303: m_lowPassFilter[1] = 0;
! 304: }
! 305:
! 306:
! 307: static ymsample LowPassFilter(ymsample in)
! 308: {
! 309: ymsample out;
! 310:
! 311: out = (m_lowPassFilter[0]>>2) + (m_lowPassFilter[1]>>1) + (in>>2);
! 312: m_lowPassFilter[0] = m_lowPassFilter[1];
! 313: m_lowPassFilter[1] = in;
! 314: return out;
! 315: }
! 316:
! 317:
! 318:
! 319: /*--------------------------------------------------------------*/
! 320: /* Build the volume conversion table used to simulate the */
! 321: /* behaviour of DAC used with the YM2149 in the atari ST. */
! 322: /* The final 32*32*32 table is built using a 16*16*16 table */
! 323: /* of all possible fixed volume combinations on a ST. */
! 324: /*--------------------------------------------------------------*/
! 325:
! 326: static int volumetable_get(int i, int j, int k)
! 327: {
! 328: /* access at boundary finds the last value instead of the first */
! 329: if (i == 16)
! 330: i = 15;
! 331: if (j == 16)
! 332: j = 15;
! 333: if (k == 16)
! 334: k = 15;
! 335:
! 336: return volumetable_original[i + 16 * j + 16 * 16 * k];
! 337: }
! 338:
! 339: static void volumetable_set(ymu16 *volumetable, int i, int j, int k, int val)
! 340: {
! 341: volumetable[i + 32 * j + 32 * 32 * k] = val;
! 342: }
! 343:
! 344: /* the table is exponential in nature. These weighing factors approximate
! 345: * that the value in-between needs to be closer to the lower value in y2 */
! 346: static int volumetable_interpolate(int y1, int y2)
! 347: {
! 348: int erpolate;
! 349: erpolate = (y1 * 4 + y2 * 6) / 10u;
! 350: if (erpolate > 65535)
1.1.1.11 root 351: {
1.1.1.12! root 352: // fprintf ( stderr , "sature>:%d %d %d\n",erpolate,y1,y2 );
! 353: erpolate = 65535;
1.1.1.11 root 354: }
1.1.1.12! root 355: if (erpolate < 0)
! 356: {
! 357: // fprintf ( stderr , "sature<:%d %d %d\n",erpolate,y1,y2 );
! 358: erpolate = 0;
! 359: }
! 360: return erpolate;
! 361: }
1.1.1.11 root 362:
1.1.1.12! root 363: static void interpolate_volumetable(ymu16 *out)
! 364: {
! 365: int i, j, k;
! 366: int i1, i2;
! 367:
! 368: /* we are doing 4-dimensional interpolation here. For each
! 369: * known measurement point, we must find 8 new values. These values occur
! 370: * as follows:
! 371: *
! 372: * - one at the exact same position
! 373: * - one half-way in i direction
! 374: * - one half-way in j direction
! 375: * - one half-way in k direction
! 376: * - one half-way in i+j direction
! 377: * - one half-way in i+k direction
! 378: * - one half-way in j+k direction
! 379: * - one half-way in i+j+k direction
! 380: *
! 381: * The algorithm currently is very simplistic. Probably more points should be
! 382: * weighted in the multicomponented directions, for instance i+j+k should be
! 383: * an average of all surrounding data points. This probably doesn't matter much,
! 384: * though. This is because the only way to reach those locations is to modulate
! 385: * more than one voice with the envelope, and this is rare.
! 386: */
! 387:
! 388: for (i = 0; i < 16; i++)
1.1.1.11 root 389: {
1.1.1.12! root 390: for (j = 0; j < 16; j++)
! 391: {
! 392: for (k = 0; k < 16; k++)
! 393: {
! 394: i1 = volumetable_get(i, j, k);
! 395: /* copy value unchanged to new position */
! 396: volumetable_set(out,i*2, j*2, k*2, i1);
! 397:
! 398: /* interpolate in i direction */
! 399: i2 = volumetable_get(i + 1, j, k);
! 400: volumetable_set(out,i*2 + 1, j*2, k*2, volumetable_interpolate(i1, i2));
! 401:
! 402: /* interpolate in j direction */
! 403: i2 = volumetable_get(i, j+1, k);
! 404: volumetable_set(out,i*2, j*2 + 1, k*2, volumetable_interpolate(i1, i2));
! 405:
! 406: /* interpolate in k direction */
! 407: i2 = volumetable_get(i, j, k+1);
! 408: volumetable_set(out,i*2, j*2, k*2+1, volumetable_interpolate(i1, i2));
! 409:
! 410: /* interpolate in i + j direction */
! 411: i2 = volumetable_get(i + 1, j + 1, k);
! 412: volumetable_set(out,i*2 + 1, j*2 + 1, k*2, volumetable_interpolate(i1, i2));
! 413:
! 414: /* interpolate in i + k direction */
! 415: i2 = volumetable_get(i + 1, j, k + 1);
! 416: volumetable_set(out,i*2 + 1, j*2, k*2 + 1, volumetable_interpolate(i1, i2));
! 417:
! 418: /* interpolate in j + k direction */
! 419: i2 = volumetable_get(i, j + 1, k + 1);
! 420: volumetable_set(out,i*2, j*2 + 1, k*2 + 1, volumetable_interpolate(i1, i2));
! 421:
! 422: /* interpolate in i + j + k direction */
! 423: i2 = volumetable_get(i + 1, j + 1, k + 1);
! 424: volumetable_set(out,i*2 + 1, j*2 + 1, k*2 + 1, volumetable_interpolate(i1, i2));
! 425: }
! 426: }
1.1.1.11 root 427: }
1.1 root 428: }
429:
1.1.1.5 root 430:
1.1.1.12! root 431:
! 432:
1.1.1.2 root 433: /*-----------------------------------------------------------------------*/
1.1.1.11 root 434: /**
1.1.1.12! root 435: * Build a linear version of the conversion table.
! 436: * We use the mean of the 3 volumes converted to 16 bit values
! 437: * (each value of ymout1c5bit is in [0,65535])
1.1.1.11 root 438: */
1.1.1.12! root 439:
! 440: static void YM2149_BuildLinearVolumeTable(ymu16 *out)
1.1 root 441: {
1.1.1.12! root 442: int i, j, k;
! 443: int res;
! 444:
! 445: for (i = 0; i < 32; i++)
! 446: for (j = 0; j < 32; j++)
! 447: for (k = 0; k < 32; k++)
! 448: {
! 449: res = ( ymout1c5bit[ i ] + ymout1c5bit[ j ] + ymout1c5bit[ k ] ) / 3;
! 450: volumetable_set ( out, i, j, k, res );
! 451: }
! 452: }
! 453:
! 454:
! 455:
1.1 root 456:
1.1.1.12! root 457: /*-----------------------------------------------------------------------*/
! 458: /**
! 459: * Normalise and optionally center the volume table used to
! 460: * convert the 3 volumes to a final signed 16 bit sample.
! 461: * This allows to adapt the amplitude/volume of the samples and
! 462: * to convert unsigned values to signed values.
! 463: * - in_5bit contains 32*32*32 unsigned values in the range
! 464: * [0,65535].
! 465: * - out_5bit will contain signed values
! 466: * Possible values are :
! 467: * Level=65535 and DoCenter=TRUE -> [-32768,32767]
! 468: * Level=32767 and DoCenter=FALSE -> [0,32767]
! 469: */
! 470:
! 471: static void YM2149_Normalise_5bit_Table(ymu16 *in_5bit , yms16 *out_5bit, unsigned int Level, bool DoCenter)
! 472: {
! 473: if ( Level )
1.1.1.11 root 474: {
1.1.1.12! root 475: int h;
! 476: int Max = in_5bit[0x7fff];
! 477: int Center = Level>>1;
! 478: //fprintf ( stderr , "level %d max %d center %d\n" , Level, Max, Center );
! 479:
! 480: /* Change the amplitude of the signal to 'level' : [0,max] -> [0,level] */
! 481: /* Then optionally center the signal around Level/2 */
! 482: /* This means we go from sthg like [0,65535] to [-32768, 32767] if Level=65535 and DoCenter=TRUE */
! 483: for (h=0; h<32*32*32; h++)
! 484: {
! 485: int tmp = in_5bit[h], res;
! 486: res = tmp * Level / Max;
! 487:
! 488: if ( DoCenter )
! 489: res -= Center;
! 490:
! 491: out_5bit[h] = res;
! 492: //fprintf ( stderr , "h %d in %d out %d\n" , h , tmp , res );
! 493: }
1.1.1.11 root 494: }
1.1 root 495: }
496:
1.1.1.5 root 497:
1.1.1.12! root 498:
! 499:
1.1.1.2 root 500: /*-----------------------------------------------------------------------*/
1.1.1.11 root 501: /**
1.1.1.12! root 502: * Precompute all 16 possible envelopes.
! 503: * Each envelope is made of 3 blocks of 32 volumes.
1.1.1.11 root 504: */
1.1.1.12! root 505:
! 506: static void YM2149_EnvBuild ( void )
1.1 root 507: {
1.1.1.12! root 508: int env;
! 509: int block;
! 510: int vol=0 , inc=0;
! 511: int i;
1.1 root 512:
1.1.1.12! root 513:
! 514: for ( env=0 ; env<16 ; env++ ) /* 16 possible envelopes */
! 515: for ( block=0 ; block<3 ; block++ ) /* 3 blocks to define an envelope */
! 516: {
! 517: switch ( YmEnvDef[ env ][ block ] ) {
! 518: case ENV_GODOWN : vol=31 ; inc=-1 ; break;
! 519: case ENV_GOUP : vol=0 ; inc=1 ; break;
! 520: case ENV_DOWN : vol=0 ; inc=0 ; break;
! 521: case ENV_UP : vol=31 ; inc=0 ; break;
! 522: }
! 523:
! 524: for ( i=0 ; i<32 ; i++ ) /* 32 volumes per block */
! 525: {
! 526: YmEnvWaves[ env ][ block*32 + i ] = YM_MERGE_VOICE ( vol , vol , vol );
! 527: vol += inc;
! 528: }
! 529: }
! 530: }
! 531:
! 532:
! 533:
! 534: /*-----------------------------------------------------------------------*/
! 535: /**
! 536: * Init some internal tables for faster results (env, volume)
! 537: * and reset the internal states.
! 538: */
! 539:
! 540: static void Ym2149_Init(void)
! 541: {
! 542: /* Build the 16 envelope shapes */
! 543: YM2149_EnvBuild();
! 544:
! 545: /* Depending on the volume mixing method, we use a table based on real measures */
! 546: /* or a table based on a linear volume mixing. */
! 547: if ( YmVolumeMixing == YM_TABLE_MIXING )
! 548: interpolate_volumetable(ymout5_u16); /* expand the 16*16*16 values in volumetable_original to 32*32*32 */
! 549: else
! 550: YM2149_BuildLinearVolumeTable(ymout5_u16); /* combine the 32 possible volumes */
! 551:
! 552: /* Normalise/center the values (convert from u16 to s16) */
! 553: YM2149_Normalise_5bit_Table ( ymout5_u16 , ymout5 , YM_OUTPUT_LEVEL , YM_OUTPUT_CENTERED );
! 554:
! 555: /* Reset YM2149 internal states */
! 556: Ym2149_Reset();
! 557: }
! 558:
! 559:
! 560:
! 561: /*-----------------------------------------------------------------------*/
! 562: /**
! 563: * Reset all ym registers as well as the internal varaibles
! 564: */
! 565:
! 566: static void Ym2149_Reset(void)
! 567: {
! 568: int i;
! 569:
! 570: for ( i=0 ; i<14 ; i++ )
! 571: Sound_WriteReg ( i , 0 );
! 572:
! 573: Sound_WriteReg ( 7 , 0xff );
! 574:
! 575: currentNoise = 0xffff;
! 576:
! 577: RndRack = 1;
! 578:
! 579: envShape = 0;
! 580: envPos = 0;
! 581:
! 582: DcAdjuster_Reset ();
! 583: LowPassFilter_Reset ();
! 584: }
! 585:
! 586:
! 587:
! 588: /*-----------------------------------------------------------------------*/
! 589: /**
! 590: * Returns a pseudo random value, used to generate white noise.
! 591: */
! 592:
! 593: static ymu32 YM2149_RndCompute(void)
! 594: {
! 595: ymu32 bit;
! 596:
! 597: bit = (RndRack&1) ^ ((RndRack>>2)&1);
! 598: RndRack = (RndRack>>1) | (bit<<16);
! 599: return (bit ? 0 : 0xffff);
! 600: }
! 601:
! 602:
! 603:
! 604: /*-----------------------------------------------------------------------*/
! 605: /**
! 606: * Compute steps for tone, noise and env, based on the input
! 607: * period.
! 608: */
! 609:
! 610: static ymu32 Ym2149_ToneStepCompute(ymu8 rHigh , ymu8 rLow)
! 611: {
! 612: int per;
! 613:
! 614: per = rHigh&15;
! 615: per = (per<<8)+rLow;
! 616: if (per<=5)
! 617: return 0;
! 618:
! 619: yms64 step = YM_ATARI_CLOCK;
! 620: step <<= (15+16-3);
! 621: step /= (per * YM_REPLAY_FREQ);
! 622:
! 623: return step;
! 624: }
! 625:
! 626:
! 627: static ymu32 Ym2149_NoiseStepCompute(ymu8 rNoise)
! 628: {
! 629: int per;
! 630:
! 631: per = (rNoise&0x1f);
! 632: if (per<3)
! 633: return 0;
! 634:
! 635: yms64 step = YM_ATARI_CLOCK;
! 636: step <<= (16-1-3);
! 637: step /= (per * YM_REPLAY_FREQ);
! 638:
! 639: return step;
1.1 root 640: }
641:
1.1.1.5 root 642:
1.1.1.2 root 643: /*-----------------------------------------------------------------------*/
1.1.1.11 root 644: /**
1.1.1.12! root 645: * Compute envelope's step. The envelope is made of different patterns
! 646: * of 32 volumes. In each pattern, the volume is changed at frequency
! 647: * Fe = MasterClock / ( 8 * EnvPer ).
! 648: * In our case, we use a lower replay freq ; between 2 consecutive calls
! 649: * to envelope's generation, the internal counter will advance 'step'
! 650: * units, where step = MasterClock / ( 8 * EnvPer * YM_REPLAY_FREQ )
! 651: * As 'step' requires floating point to be stored, we use left shifting
! 652: * to multiply 'step' by a fixed amount. All operations are made with
! 653: * shifted values ; to get the final value, we must right shift the
! 654: * result. We use '<<24', which gives 8 bits for the integer part, and
! 655: * the equivalent of 24 bits for the fractional part.
! 656: * Since we're using large numbers, we temporarily use 64 bits integer
! 657: * to avoid overflow and keep largest precision possible.
1.1.1.11 root 658: */
1.1.1.12! root 659:
! 660: static ymu32 Ym2149_EnvStepCompute(ymu8 rHigh , ymu8 rLow)
1.1 root 661: {
1.1.1.12! root 662: yms64 per;
1.1 root 663:
1.1.1.12! root 664: per = rHigh;
! 665: per = (per<<8)+rLow;
! 666:
! 667: yms64 step = YM_ATARI_CLOCK;
! 668: step <<= 24;
! 669: if ( per > 0 )
! 670: step /= (8 * per * YM_REPLAY_FREQ); /* 0x5ab < step < 0x5ab3f46 at 44.1 kHz */
! 671: else
! 672: step /= (8 * 1/2 * YM_REPLAY_FREQ); /* result for Per=0 is half the result for Per=1 */
! 673:
! 674: return step;
! 675: }
! 676:
! 677:
! 678:
! 679: /*-----------------------------------------------------------------------*/
! 680: /**
! 681: * Main function : compute the value of the next sample.
! 682: * Mixes all 3 voices with tone+noise+env and apply low pass
! 683: * filter if needed.
! 684: */
! 685:
! 686: static ymsample YM2149_NextSample(void)
! 687: {
! 688: ymsample sample;
! 689: int bt;
! 690: ymu32 bn;
! 691: ymu16 Env3Voices;
! 692: ymu16 Tone3Voices;
! 693:
! 694:
! 695: /* Noise value : 0 or 0xffff */
! 696: if ( noisePos&0xffff0000 )
! 697: {
! 698: currentNoise ^= YM2149_RndCompute();
! 699: noisePos &= 0xffff;
! 700: }
! 701: bn = currentNoise; /* 0 or 0xffff */
! 702:
! 703: /* Get the 5 bits volume corresponding to the current envelope's position */
! 704: Env3Voices = YmEnvWaves[ envShape ][ envPos>>24 ]; /* integer part of envPos is in bits 24-31 */
! 705: Env3Voices &= EnvMask3Voices; /* only keep volumes for voices using envelope */
! 706:
! 707: //fprintf ( stderr , "env %x %x %x\n" , Env3Voices , envStep , envPos );
! 708:
! 709: /* Tone3Voices will contain the output state of each voice : 0 or 0x1f */
! 710: bt = ((((yms32)posA)>>31) | mixerTA) & (bn | mixerNA); /* 0 or 0xffff */
! 711: Tone3Voices = bt & YM_MASK_1VOICE; /* 0 or 0x1f */
! 712: bt = ((((yms32)posB)>>31) | mixerTB) & (bn | mixerNB);
! 713: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 5;
! 714: bt = ((((yms32)posC)>>31) | mixerTC) & (bn | mixerNC);
! 715: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 10;
! 716:
! 717: /* Combine fixed volumes and envelope volumes and keep the resulting */
! 718: /* volumes depending on the output state of each voice (0 or 0x1f) */
! 719: Tone3Voices &= ( Env3Voices | Vol3Voices );
! 720:
! 721: /* D/A conversion of the 3 volumes into a sample using a precomputed conversion table */
! 722: sample = ymout5[ Tone3Voices ]; /* 16 bits signed value */
! 723:
! 724:
! 725: /* Increment positions */
! 726: posA += stepA;
! 727: posB += stepB;
! 728: posC += stepC;
! 729: noisePos += noiseStep;
! 730:
! 731: envPos += envStep;
! 732: if ( envPos >= (3*32) << 24 ) /* blocks 0, 1 and 2 were used (envPos 0 to 95) */
! 733: envPos -= (2*32) << 24; /* replay/loop blocks 1 and 2 (envPos 32 to 95) */
! 734:
! 735:
! 736: /* Apply low pass filter ? */
! 737: if ( UseLowPassFilter )
1.1.1.11 root 738: {
1.1.1.12! root 739: DcAdjuster_AddSample ( sample ); /* normalize sound level */
! 740: sample = LowPassFilter ( sample - DcAdjuster_GetDcLevel() );
1.1.1.11 root 741: }
1.1.1.12! root 742:
! 743: return sample;
1.1 root 744: }
745:
746:
1.1.1.12! root 747:
1.1.1.2 root 748: /*-----------------------------------------------------------------------*/
1.1.1.11 root 749: /**
1.1.1.12! root 750: * Update internal variables (steps, volume masks, ...) each
! 751: * time an YM register is changed.
1.1.1.11 root 752: */
753:
1.1.1.12! root 754: void Sound_WriteReg( int reg , Uint8 data )
1.1.1.7 root 755: {
1.1.1.12! root 756: switch (reg)
! 757: {
! 758: case 0:
! 759: SoundRegs[0] = data;
! 760: stepA = Ym2149_ToneStepCompute ( SoundRegs[1] , SoundRegs[0] );
! 761: if (!stepA) posA = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
! 762: break;
! 763:
! 764: case 1:
! 765: SoundRegs[1] = data & 0x0f;
! 766: stepA = Ym2149_ToneStepCompute ( SoundRegs[1] , SoundRegs[0] );
! 767: if (!stepA) posA = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
! 768: break;
! 769:
! 770: case 2:
! 771: SoundRegs[2] = data;
! 772: stepB = Ym2149_ToneStepCompute ( SoundRegs[3] , SoundRegs[2] );
! 773: if (!stepB) posB = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
! 774: break;
1.1.1.7 root 775:
1.1.1.12! root 776: case 3:
! 777: SoundRegs[3] = data & 0x0f;
! 778: stepB = Ym2149_ToneStepCompute ( SoundRegs[3] , SoundRegs[2] );
! 779: if (!stepB) posB = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
! 780: break;
! 781:
! 782: case 4:
! 783: SoundRegs[4] = data;
! 784: stepC = Ym2149_ToneStepCompute ( SoundRegs[5] , SoundRegs[4] );
! 785: if (!stepC) posC = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
! 786: break;
! 787:
! 788: case 5:
! 789: SoundRegs[5] = data & 0x0f;
! 790: stepC = Ym2149_ToneStepCompute ( SoundRegs[5] , SoundRegs[4] );
! 791: if (!stepC) posC = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
! 792: break;
! 793:
! 794: case 6:
! 795: SoundRegs[6] = data & 0x1f;
! 796: noiseStep = Ym2149_NoiseStepCompute ( SoundRegs[6] );
! 797: if (!noiseStep)
! 798: {
! 799: noisePos = 0;
! 800: currentNoise = 0xffff;
! 801: }
! 802: break;
! 803:
! 804: case 7:
! 805: SoundRegs[7] = data & 0x3f; /* ignore bits 6 and 7 */
! 806: mixerTA = (data&(1<<0)) ? 0xffff : 0;
! 807: mixerTB = (data&(1<<1)) ? 0xffff : 0;
! 808: mixerTC = (data&(1<<2)) ? 0xffff : 0;
! 809: mixerNA = (data&(1<<3)) ? 0xffff : 0;
! 810: mixerNB = (data&(1<<4)) ? 0xffff : 0;
! 811: mixerNC = (data&(1<<5)) ? 0xffff : 0;
! 812: break;
! 813:
! 814: case 8:
! 815: SoundRegs[8] = data & 0x1f;
! 816: if ( data & 0x10 )
! 817: {
! 818: EnvMask3Voices |= YM_MASK_A; /* env ON */
! 819: Vol3Voices &= ~YM_MASK_A; /* fixed vol OFF */
! 820: }
! 821: else
! 822: {
! 823: EnvMask3Voices &= ~YM_MASK_A; /* env OFF */
! 824: Vol3Voices &= ~YM_MASK_A; /* clear previous vol */
! 825: Vol3Voices |= YmVolume4to5[ SoundRegs[8] ]; /* fixed vol ON */
! 826: }
! 827: break;
! 828:
! 829: case 9:
! 830: SoundRegs[9] = data & 0x1f;
! 831: if ( data & 0x10 )
! 832: {
! 833: EnvMask3Voices |= YM_MASK_B; /* env ON */
! 834: Vol3Voices &= ~YM_MASK_B; /* fixed vol OFF */
! 835: }
! 836: else
! 837: {
! 838: EnvMask3Voices &= ~YM_MASK_B; /* env OFF */
! 839: Vol3Voices &= ~YM_MASK_B; /* clear previous vol */
! 840: Vol3Voices |= ( YmVolume4to5[ SoundRegs[9] ] ) << 5; /* fixed vol ON */
! 841: }
! 842: break;
! 843:
! 844: case 10:
! 845: SoundRegs[10] = data & 0x1f;
! 846: if ( data & 0x10 )
! 847: {
! 848: EnvMask3Voices |= YM_MASK_C; /* env ON */
! 849: Vol3Voices &= ~YM_MASK_C; /* fixed vol OFF */
! 850: }
! 851: else
! 852: {
! 853: EnvMask3Voices &= ~YM_MASK_C; /* env OFF */
! 854: Vol3Voices &= ~YM_MASK_C; /* clear previous vol */
! 855: Vol3Voices |= ( YmVolume4to5[ SoundRegs[10] ] ) << 10; /* fixed vol ON */
! 856: }
! 857: break;
! 858:
! 859: case 11:
! 860: SoundRegs[11] = data;
! 861: envStep = Ym2149_EnvStepCompute ( SoundRegs[12] , SoundRegs[11] );
! 862: break;
! 863:
! 864: case 12:
! 865: SoundRegs[12] = data;
! 866: envStep = Ym2149_EnvStepCompute ( SoundRegs[12] , SoundRegs[11] );
! 867: break;
! 868:
! 869: case 13:
! 870: SoundRegs[13] = data & 0xf;
! 871: envPos = 0; /* when writing to EnvShape, we must reset the EnvPos */
! 872: envShape = SoundRegs[13];
! 873: bEnvelopeFreqFlag = TRUE; /* used for YmFormat saving */
! 874: break;
! 875:
! 876: }
! 877: }
! 878:
! 879:
! 880:
! 881: /*-----------------------------------------------------------------------*/
! 882: /**
! 883: * Init random generator, sound tables and envelopes
! 884: * (called only once when Hatari starts)
! 885: */
! 886: void Sound_Init(void)
! 887: {
! 888: /* Build volume/env tables, ... */
! 889: Ym2149_Init();
! 890:
1.1.1.11 root 891: Sound_Reset();
1.1.1.7 root 892: }
893:
894:
895: /*-----------------------------------------------------------------------*/
1.1.1.11 root 896: /**
1.1.1.12! root 897: * Reset the sound emulation (called from Reset_ST() in reset.c)
1.1.1.11 root 898: */
1.1.1.7 root 899: void Sound_Reset(void)
900: {
1.1.1.11 root 901: /* Lock audio system before accessing variables which are used by the
902: * callback function, too! */
903: Audio_Lock();
1.1.1.9 root 904:
1.1.1.11 root 905: /* Clear sound mixing buffer: */
1.1.1.12! root 906: memset(MixBuffer, 0, sizeof(MixBuffer));
1.1.1.7 root 907:
1.1.1.11 root 908: /* Clear cycle counts, buffer index and register '13' flags */
909: Cycles_SetCounter(CYCLES_COUNTER_SOUND, 0);
910: bEnvelopeFreqFlag = FALSE;
1.1.1.12! root 911:
1.1.1.11 root 912: CompleteSndBufIdx = 0;
913: /* We do not start with 0 here to fake some initial samples: */
914: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
915: ActiveSndBufIdx = nGeneratedSamples % MIXBUFFER_SIZE;
1.1.1.7 root 916:
1.1.1.12! root 917: Ym2149_Reset();
1.1.1.9 root 918:
1.1.1.11 root 919: Audio_Unlock();
1.1.1.7 root 920: }
921:
922:
923: /*-----------------------------------------------------------------------*/
1.1.1.11 root 924: /**
925: * Reset the sound buffer index variables.
926: */
1.1.1.9 root 927: void Sound_ResetBufferIndex(void)
1.1.1.7 root 928: {
1.1.1.11 root 929: Audio_Lock();
930: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
931: ActiveSndBufIdx = (CompleteSndBufIdx + nGeneratedSamples) % MIXBUFFER_SIZE;
932: Audio_Unlock();
1.1.1.7 root 933: }
934:
935:
936: /*-----------------------------------------------------------------------*/
1.1.1.11 root 937: /**
938: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
939: */
1.1.1.12! root 940: void Sound_MemorySnapShot_Capture(bool bSave)
1.1.1.7 root 941: {
1.1.1.11 root 942: /* Save/Restore details */
1.1.1.12! root 943: MemorySnapShot_Store(&stepA, sizeof(stepA));
! 944: MemorySnapShot_Store(&stepB, sizeof(stepB));
! 945: MemorySnapShot_Store(&stepC, sizeof(stepC));
! 946: MemorySnapShot_Store(&posA, sizeof(posA));
! 947: MemorySnapShot_Store(&posB, sizeof(posB));
! 948: MemorySnapShot_Store(&posC, sizeof(posC));
! 949:
! 950: MemorySnapShot_Store(&mixerTA, sizeof(mixerTA));
! 951: MemorySnapShot_Store(&mixerTB, sizeof(mixerTB));
! 952: MemorySnapShot_Store(&mixerTC, sizeof(mixerTC));
! 953: MemorySnapShot_Store(&mixerNA, sizeof(mixerNA));
! 954: MemorySnapShot_Store(&mixerNB, sizeof(mixerNB));
! 955: MemorySnapShot_Store(&mixerNC, sizeof(mixerNC));
! 956:
! 957: MemorySnapShot_Store(&noiseStep, sizeof(noiseStep));
! 958: MemorySnapShot_Store(&noisePos, sizeof(noisePos));
! 959: MemorySnapShot_Store(¤tNoise, sizeof(currentNoise));
! 960: MemorySnapShot_Store(&RndRack, sizeof(RndRack));
! 961:
! 962: MemorySnapShot_Store(&envStep, sizeof(envStep));
! 963: MemorySnapShot_Store(&envPos, sizeof(envPos));
! 964: MemorySnapShot_Store(&envShape, sizeof(envShape));
! 965:
! 966: MemorySnapShot_Store(&EnvMask3Voices, sizeof(EnvMask3Voices));
! 967: MemorySnapShot_Store(&Vol3Voices, sizeof(Vol3Voices));
! 968:
! 969: MemorySnapShot_Store(SoundRegs, sizeof(SoundRegs));
! 970:
! 971: MemorySnapShot_Store(&YmVolumeMixing, sizeof(YmVolumeMixing));
! 972: MemorySnapShot_Store(&UseLowPassFilter, sizeof(UseLowPassFilter));
1.1.1.7 root 973: }
974:
975:
976: /*-----------------------------------------------------------------------*/
1.1.1.11 root 977: /**
978: * Find how many samples to generate and store in 'nSamplesToGenerate'
979: * Also update sound cycles counter to store how many we actually did
980: * so generates set amount each frame.
981: */
1.1.1.7 root 982: static void Sound_SetSamplesPassed(void)
1.1 root 983: {
1.1.1.11 root 984: int nSampleCycles;
985: int nSamplesPerFrame;
986: int nSoundCycles;
987:
988: nSoundCycles = Cycles_GetCounter(CYCLES_COUNTER_SOUND);
989:
990: /* 160256 cycles per VBL, 44Khz = 882 samples per VBL */
991: /* 882/160256 samples per clock cycle */
992: nSamplesPerFrame = SAMPLES_PER_FRAME;
993:
994: nSamplesToGenerate = nSoundCycles * nSamplesPerFrame / CYCLES_PER_FRAME;
995: if (nSamplesToGenerate > nSamplesPerFrame)
996: nSamplesToGenerate = nSamplesPerFrame;
997:
998: nSampleCycles = nSamplesToGenerate * CYCLES_PER_FRAME / nSamplesPerFrame;
999: nSoundCycles -= nSampleCycles;
1000: Cycles_SetCounter(CYCLES_COUNTER_SOUND, nSoundCycles);
1001:
1002: if (nSamplesToGenerate > MIXBUFFER_SIZE - nGeneratedSamples)
1003: {
1004: nSamplesToGenerate = MIXBUFFER_SIZE - nGeneratedSamples;
1005: if (nSamplesToGenerate < 0)
1006: nSamplesToGenerate = 0;
1007: }
1.1 root 1008: }
1009:
1.1.1.5 root 1010:
1.1.1.2 root 1011: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1012: /**
1013: * Generate samples for all channels during this time-frame
1014: */
1.1.1.5 root 1015: static void Sound_GenerateSamples(void)
1.1 root 1016: {
1.1.1.12! root 1017: int i;
! 1018: int idx;
! 1019:
! 1020: if (nSamplesToGenerate <= 0)
! 1021: return;
! 1022:
! 1023: for (i = 0; i < nSamplesToGenerate; i++)
1.1.1.11 root 1024: {
1.1.1.12! root 1025: idx = (ActiveSndBufIdx + i) % MIXBUFFER_SIZE;
! 1026: MixBuffer[idx][0] = MixBuffer[idx][1] = YM2149_NextSample();
1.1.1.11 root 1027: }
1.1.1.12! root 1028:
! 1029: DmaSnd_GenerateSamples(ActiveSndBufIdx, nSamplesToGenerate);
! 1030:
! 1031: ActiveSndBufIdx = (ActiveSndBufIdx + nSamplesToGenerate) % MIXBUFFER_SIZE;
! 1032: nGeneratedSamples += nSamplesToGenerate;
1.1 root 1033: }
1034:
1.1.1.5 root 1035:
1.1.1.2 root 1036: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1037: /**
1038: * This is called to built samples up until this clock cycle
1039: */
1.1.1.5 root 1040: void Sound_Update(void)
1.1 root 1041: {
1.1.1.11 root 1042: int OldSndBufIdx = ActiveSndBufIdx;
1.1.1.5 root 1043:
1.1.1.11 root 1044: /* Make sure that we don't interfere with the audio callback function */
1045: Audio_Lock();
1.1.1.6 root 1046:
1.1.1.11 root 1047: /* Find how many to generate */
1048: Sound_SetSamplesPassed();
1049: /* And generate */
1050: Sound_GenerateSamples();
1.1 root 1051:
1.1.1.11 root 1052: /* Allow audio callback function to occur again */
1053: Audio_Unlock();
1.1.1.6 root 1054:
1.1.1.11 root 1055: /* Save to WAV file, if open */
1056: if (bRecordingWav)
1057: WAVFormat_Update(MixBuffer, OldSndBufIdx, nSamplesToGenerate);
1.1 root 1058: }
1059:
1.1.1.5 root 1060:
1.1.1.2 root 1061: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1062: /**
1063: * On each VBL (50fps) complete samples.
1064: */
1.1.1.5 root 1065: void Sound_Update_VBL(void)
1.1 root 1066: {
1.1.1.11 root 1067: Sound_Update();
1.1.1.5 root 1068:
1.1.1.11 root 1069: /* Clear write to register '13', used for YM file saving */
1070: bEnvelopeFreqFlag = FALSE;
1.1 root 1071: }
1072:
1073:
1.1.1.2 root 1074: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1075: /**
1076: * Start recording sound, as .YM or .WAV output
1077: */
1.1.1.12! root 1078: bool Sound_BeginRecording(char *pszCaptureFileName)
1.1 root 1079: {
1.1.1.12! root 1080: bool bRet;
1.1.1.7 root 1081:
1.1.1.11 root 1082: if (!pszCaptureFileName || strlen(pszCaptureFileName) <= 3)
1083: {
1084: Log_Printf(LOG_ERROR, "Illegal sound recording file name!\n");
1085: return FALSE;
1086: }
1087:
1088: /* Did specify .YM or .WAV? If neither report error */
1089: if (File_DoesFileExtensionMatch(pszCaptureFileName,".ym"))
1090: bRet = YMFormat_BeginRecording(pszCaptureFileName);
1091: else if (File_DoesFileExtensionMatch(pszCaptureFileName,".wav"))
1092: bRet = WAVFormat_OpenFile(pszCaptureFileName);
1093: else
1094: {
1095: Log_AlertDlg(LOG_ERROR, "Unknown Sound Recording format.\n"
1096: "Please specify a .YM or .WAV output file.");
1097: bRet = FALSE;
1098: }
1099:
1100: return bRet;
1.1 root 1101: }
1102:
1.1.1.5 root 1103:
1.1.1.2 root 1104: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1105: /**
1106: * End sound recording
1107: */
1.1.1.7 root 1108: void Sound_EndRecording(void)
1.1 root 1109: {
1.1.1.11 root 1110: /* Stop sound recording and close files */
1111: if (bRecordingYM)
1112: YMFormat_EndRecording();
1113: if (bRecordingWav)
1114: WAVFormat_CloseFile();
1.1 root 1115: }
1116:
1.1.1.6 root 1117:
1.1.1.2 root 1118: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1119: /**
1120: * Are we recording sound data?
1121: */
1.1.1.12! root 1122: bool Sound_AreWeRecording(void)
1.1 root 1123: {
1.1.1.11 root 1124: return (bRecordingYM || bRecordingWav);
1.1 root 1125: }
1.1.1.12! root 1126:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.