Пример #1
0
        public APU(ARM7TDMI cpu, Scheduler.Scheduler scheduler)
        {
            this.Channels = new Channel[] { sq1, sq2, wave, noise };

            this.FIFO[0] = this.FIFOA = new FIFOChannel(cpu, 0x0400_00a0);
            this.FIFO[1] = this.FIFOB = new FIFOChannel(cpu, 0x0400_00a4);

            // initial APU events
            scheduler.Push(new Event(FrameSequencerPeriod, this.TickFrameSequencer));
            foreach (Channel ch in this.Channels)
            {
                scheduler.Push(new Event(ch.Period, ch.Tick));
            }
            scheduler.Push(new Event(SamplePeriod, this.ProvideSample));
        }
Пример #2
0
        private void TickFrameSequencer(Event sender, Scheduler.Scheduler scheduler)
        {
            this.FrameSequencer++;
            switch (this.FrameSequencer & 7)
            {
            case 0:
            case 4:
                foreach (Channel ch in this.Channels)
                {
                    ch.TickLengthCounter();
                }
                break;

            case 2:
            case 6:
                foreach (Channel ch in this.Channels)
                {
                    ch.TickLengthCounter();
                }
                this.sq1.DoSweep();
                break;

            case 7:
                this.sq1.DoEnvelope();
                this.sq2.DoEnvelope();
                this.noise.DoEnvelope();
                break;
            }

            sender.Time += FrameSequencerPeriod;
            scheduler.Push(sender);
        }
Пример #3
0
        public void Tick(Event sender, Scheduler.Scheduler scheduler)
        {
            this.OnTick();
            if (!this.SoundOn())
            {
                this.CurrentSample = 0;
            }
            else
            {
                this.CurrentSample = this.GetSample();
            }

            sender.Time += this.Period;
            scheduler.Push(sender);
        }
Пример #4
0
        private void ProvideSample(Event sender, Scheduler.Scheduler scheduler)
        {
            int SampleLeft = 0, SampleRight = 0;

            for (int i = 0; i < 4; i++)
            {
                if (!ExternalChannelEnable[i])
                {
                    continue;
                }

                if (this.MasterEnableRight[i])
                {
                    SampleRight += this.Channels[i].CurrentSample;
                }
                if (this.MasterEnableLeft[i])
                {
                    SampleLeft += this.Channels[i].CurrentSample;
                }
            }

            // SOUNDCNT_L volume control does not affect FIFO channels
            SampleRight = (int)((SampleRight * this.MasterVolumeRight) / 8);
            SampleLeft  = (int)((SampleLeft * this.MasterVolumeLeft) / 8);

            switch (this.Sound1_4Volume)
            {
            case 0:
                // 25%
                SampleLeft  >>= 2;
                SampleRight >>= 2;
                break;

            case 1:
                // 50%
                SampleLeft  >>= 1;
                SampleRight >>= 1;
                break;

            default:
                // 100% / prohibited
                break;
            }

            /*
             * GBATek:
             * Each of the two FIFOs can span the FULL output range (+/-200h).
             * Each of the four PSGs can span one QUARTER of the output range (+/-80h).
             * So we multiply the output of the FIFO by 4
             */

            for (int i = 0; i < 2; i++)
            {
                if (!ExternalFIFOEnable[i])
                {
                    continue;
                }

                if (this.DMAEnableRight[i])
                {
                    SampleRight += this.FIFO[i].CurrentSample << (this.DMASoundVolume[i] ? 1 : 2);  // false = 50%, true = 100%
                }

                if (this.DMAEnableLeft[i])
                {
                    SampleLeft += this.FIFO[i].CurrentSample << (this.DMASoundVolume[i] ? 1 : 2);  // false = 50%, true = 100%
                }
            }

            SampleRight = (int)(SampleRight * Amplitude);
            SampleLeft  = (int)(SampleLeft * Amplitude);

            if (this.ExternalEnable)
            {
                SpinWait.SpinUntil(() => this.speaker.NeedMoreSamples);  // prevent buffer overflow
                this.speaker.AddSample((short)SampleLeft, (short)SampleRight);
            }

            sender.Time += SamplePeriod;
            scheduler.Push(sender);
        }