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

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: 
1.1.1.13! root       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(&currentNoise, 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: 

unix.superglobalmegacorp.com

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