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

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(&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.