예제 #1
0
        private void envelope_generator_calc(_MultiPCM ptChip, _slot_t slot)
        {
            Int32 octave = ((slot.regs[3] >> 4) - 1) & 0xf;
            Int32 rate;

            if ((octave & 8) != 0)
            {
                octave = octave - 16;
            }

            if (slot.sample.key_rate_scale != 0xf)
            {
                rate = (octave + slot.sample.key_rate_scale) * 2 + ((slot.regs[3] >> 3) & 1);
            }
            else
            {
                rate = 0;
            }

            slot.envelope_gen.attack_rate  = (Int32)get_rate(ptChip.attack_step, (UInt32)rate, slot.sample.attack_reg);
            slot.envelope_gen.decay1_rate  = (Int32)get_rate(ptChip.decay_release_step, (UInt32)rate, slot.sample.decay1_reg);
            slot.envelope_gen.decay2_rate  = (Int32)get_rate(ptChip.decay_release_step, (UInt32)rate, slot.sample.decay2_reg);
            slot.envelope_gen.release_rate = (Int32)get_rate(ptChip.decay_release_step, (UInt32)rate, slot.sample.release_reg);
            slot.envelope_gen.decay_level  = 0xf - slot.sample.decay_level;
        }
예제 #2
0
        private Int32 envelope_generator_update(_slot_t slot)
        {
            switch (slot.envelope_gen.state)
            {
            case _STATE.ATTACK:
                slot.envelope_gen.volume += slot.envelope_gen.attack_rate;
                if (slot.envelope_gen.volume >= (0x3ff << EG_SHIFT))
                {
                    slot.envelope_gen.state = _STATE.DECAY1;
                    if (slot.envelope_gen.decay1_rate >= (0x400 << EG_SHIFT))     //Skip DECAY1, go directly to DECAY2
                    {
                        slot.envelope_gen.state = _STATE.DECAY2;
                    }
                    slot.envelope_gen.volume = 0x3ff << EG_SHIFT;
                }
                break;

            case _STATE.DECAY1:
                slot.envelope_gen.volume -= slot.envelope_gen.decay1_rate;
                if (slot.envelope_gen.volume <= 0)
                {
                    slot.envelope_gen.volume = 0;
                }
                if (slot.envelope_gen.volume >> EG_SHIFT <= (slot.envelope_gen.decay_level << (10 - 4)))
                {
                    slot.envelope_gen.state = _STATE.DECAY2;
                }
                break;

            case _STATE.DECAY2:
                slot.envelope_gen.volume -= slot.envelope_gen.decay2_rate;
                if (slot.envelope_gen.volume <= 0)
                {
                    slot.envelope_gen.volume = 0;
                }
                break;

            case _STATE.RELEASE:
                slot.envelope_gen.volume -= slot.envelope_gen.release_rate;
                if (slot.envelope_gen.volume <= 0)
                {
                    slot.envelope_gen.volume = 0;
                    slot.playing             = 0;
                }
                break;

            default:
                return(1 << TL_SHIFT);
            }
            return(linear_to_exp_volume[slot.envelope_gen.volume >> EG_SHIFT]);
        }
예제 #3
0
        //static STREAM_UPDATE( MultiPCM_update )
        public void MultiPCM_update(byte ChipID, Int32[][] outputs, Int32 samples)
        {
            //MultiPCM *ptChip = (MultiPCM *)param;
            _MultiPCM ptChip = MultiPCMData[ChipID];
            //Int32[][] datap = new Int32[2][];
            Int32 i, sl;

            //datap[0] = outputs[0];
            //datap[1] = outputs[1];

            for (int j = 0; j < samples; j++)
            {
                outputs[0][j] = 0;
                outputs[1][j] = 0;
            }
            //memset(datap[0], 0, sizeof(*datap[0]) * samples);
            //memset(datap[1], 0, sizeof(*datap[1]) * samples);


            for (i = 0; i < samples; ++i)
            {
                Int32 smpl = 0;
                Int32 smpr = 0;
                for (sl = 0; sl < 28; ++sl)
                {
                    _slot_t slot = ptChip.slots[sl];
                    if (slot.playing != 0 && slot.muted == 0)
                    {
                        UInt32 vol     = (slot.total_level >> TL_SHIFT) | (slot.pan << 7);
                        UInt32 spos    = slot.offset >> TL_SHIFT;
                        UInt32 step    = slot.step;
                        Int32  csample = 0;
                        Int32  fpart   = (Int32)(slot.offset & ((1 << TL_SHIFT) - 1));
                        Int32  sample;// = (csample * fpart + slot.prev_sample * ((1 << SHIFT) - fpart)) >> SHIFT;


                        if ((slot.format & 8) != 0)   // 12-bit linear
                        {
                            UInt32 adr = slot.Base + (spos >> 2) * 6;
                            switch (spos & 3)
                            {
                            case 0:
                            {         // ab.c .... ....
                                Int16 w0 = (short)(read_byte(ptChip, adr) << 8 | ((read_byte(ptChip, adr + 1) & 0xf) << 4));
                                csample = w0;
                                break;
                            }

                            case 1:
                            {         // ..C. AB.. ....
                                Int16 w0 = (short)((read_byte(ptChip, adr + 2) << 8) | (read_byte(ptChip, adr + 1) & 0xf0));
                                csample = w0;
                                break;
                            }

                            case 2:
                            {         // .... ..ab .c..
                                Int16 w0 = (short)(read_byte(ptChip, adr + 3) << 8 | ((read_byte(ptChip, adr + 4) & 0xf) << 4));
                                csample = w0;
                                break;
                            }

                            case 3:
                            {         // .... .... C.AB
                                Int16 w0 = (short)((read_byte(ptChip, adr + 5) << 8) | (read_byte(ptChip, adr + 4) & 0xf0));
                                csample = w0;
                                break;
                            }
                            }
                        }
                        else
                        {
                            csample = (Int16)(read_byte(ptChip, slot.Base + spos) << 8);
                        }

                        sample = (csample * fpart + slot.prev_sample * ((1 << TL_SHIFT) - fpart)) >> TL_SHIFT;

                        if ((slot.regs[6] & 7) != 0) // Vibrato enabled
                        {
                            step   = (uint)(step * pitch_lfo_step(slot.pitch_lfo));
                            step >>= TL_SHIFT;
                        }

                        slot.offset += step;
                        if (slot.offset >= (slot.sample.end << TL_SHIFT))
                        {
                            slot.offset = slot.sample.loop << TL_SHIFT;
                        }

                        if ((spos ^ (slot.offset >> TL_SHIFT)) != 0)
                        {
                            slot.prev_sample = csample;
                        }

                        if ((slot.total_level >> TL_SHIFT) != slot.dest_total_level)
                        {
                            slot.total_level += (uint)slot.total_level_step;
                        }

                        if ((slot.regs[7] & 7) != 0) // Tremolo enabled
                        {
                            sample   = sample * amplitude_lfo_step(slot.amplitude_lfo);
                            sample >>= TL_SHIFT;
                        }

                        sample = (sample * envelope_generator_update(slot)) >> 10;

                        smpl += (left_pan_table[vol] * sample) >> TL_SHIFT;
                        smpr += (right_pan_table[vol] * sample) >> TL_SHIFT;
                    }
                }

                outputs[0][i] = smpl;
                outputs[1][i] = smpr;
            }
        }
예제 #4
0
        private void write_slot(_MultiPCM ptChip, _slot_t slot, Int32 reg, byte data)
        {
            slot.regs[reg] = data;

            switch (reg)
            {
            case 0:     //PANPOT
                slot.pan = (UInt32)((data >> 4) & 0xf);
                break;

            case 1:     //Sample
                        //according to YMF278 sample write causes some base params written to the regs (envelope+lfos)
                        //the game should never change the sample while playing.
                        // patched to load all sample data here, so registers 6 and 7 aren't overridden by KeyOn -Valley Bell
                init_sample(ptChip, slot.sample, (ushort)(slot.regs[1] | ((slot.regs[2] & 1) << 8)));
                write_slot(ptChip, slot, 6, slot.sample.lfo_vibrato_reg);
                write_slot(ptChip, slot, 7, slot.sample.lfo_amplitude_reg);
                break;

            case 2:     //Pitch
            case 3:
            {
                UInt32 oct   = (UInt32)(((slot.regs[3] >> 4) - 1) & 0xf);
                UInt32 pitch = (UInt32)(((slot.regs[3] & 0xf) << 6) | (slot.regs[2] >> 2));
                pitch = ptChip.freq_step_table[pitch];
                if ((oct & 0x8) != 0)
                {
                    pitch >>= (Int32)(16 - oct);
                }
                else
                {
                    pitch <<= (Int32)oct;
                }
                slot.step = (UInt32)(pitch / ptChip.rate);
            }
            break;

            case 4:                     //KeyOn/Off (and more?)
            {
                if ((data & 0x80) != 0) //KeyOn
                {
                    slot.playing     = 1;
                    slot.Base        = slot.sample.start;
                    slot.offset      = 0;
                    slot.prev_sample = 0;
                    slot.total_level = slot.dest_total_level << TL_SHIFT;
                    slot.format      = slot.sample.format;

                    envelope_generator_calc(ptChip, slot);
                    slot.envelope_gen.state  = _STATE.ATTACK;
                    slot.envelope_gen.volume = 0;

                    if (ptChip.sega_banking != 0)
                    {
                        slot.Base &= 0x1fffff;
                        if (slot.Base >= 0x100000)
                        {
                            if ((slot.Base & 0x080000) != 0)
                            {
                                slot.Base = (slot.Base & 0x07ffff) | ptChip.bank1;
                            }

                            else
                            {
                                slot.Base = (slot.Base & 0x07ffff) | ptChip.bank0;
                            }
                        }
                    }
                }
                else
                {
                    if (slot.playing != 0)
                    {
                        if (slot.sample.release_reg != 0xf)
                        {
                            slot.envelope_gen.state = _STATE.RELEASE;
                        }
                        else
                        {
                            slot.playing = 0;
                        }
                    }
                }
            }
            break;

            case 5:     //TL+Interpolation
            {
                slot.dest_total_level = (UInt32)((data >> 1) & 0x7f);
                if ((data & 1) == 0)            //Interpolate TL
                {
                    if ((slot.total_level >> TL_SHIFT) > slot.dest_total_level)
                    {
                        slot.total_level_step = ptChip.total_level_steps[0];         // decrease
                    }
                    else
                    {
                        slot.total_level_step = ptChip.total_level_steps[1];         // increase
                    }
                }
                else
                {
                    slot.total_level = slot.dest_total_level << TL_SHIFT;
                }
            }
            break;

            case 6:     //LFO freq+PLFO
            {
                if (data != 0)
                {
                    lfo_compute_step(ptChip, slot.pitch_lfo, (UInt32)(slot.regs[6] >> 3) & 7, (UInt32)(slot.regs[6] & 7), 0);
                    lfo_compute_step(ptChip, slot.amplitude_lfo, (UInt32)(slot.regs[6] >> 3) & 7, (UInt32)(slot.regs[7] & 7), 1);
                }
            }
            break;

            case 7:     //ALFO
            {
                if (data != 0)
                {
                    lfo_compute_step(ptChip, slot.pitch_lfo, (UInt32)(slot.regs[6] >> 3) & 7, (UInt32)(slot.regs[6] & 7), 0);
                    lfo_compute_step(ptChip, slot.amplitude_lfo, (UInt32)(slot.regs[6] >> 3) & 7, (UInt32)(slot.regs[7] & 7), 1);
                }
            }
            break;
            }
        }