// Meteor - A Nintendo Gameboy Advance emulator1// Copyright (C) 2009-2011 Philippe Daouadi2//3// This program is free software: you can redistribute it and/or modify4// it under the terms of the GNU General Public License as published by5// the Free Software Foundation, either version 3 of the License, or6// (at your option) any later version.7//8// This program is distributed in the hope that it will be useful,9// but WITHOUT ANY WARRANTY; without even the implied warranty of10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11// GNU General Public License for more details.12//13// You should have received a copy of the GNU General Public License14// along with this program. If not, see <http://www.gnu.org/licenses/>.1516#include "ameteor/audio/sound1.hpp"17#include "../globals.hpp"18#include <cmath>1920namespace AMeteor21{22namespace Audio23{24Sound1::Sound1 (uint16_t& cntl, uint16_t& cnth, uint16_t& cntx,25uint16_t freq) :26m_cntl(cntl),27m_cnth(cnth),28m_cntx(cntx),29m_on(false),30m_posP(0),31m_posS(0),32m_posE(0),33m_sample(0),34m_speriod(16*1024*1024/freq),35m_envelope(0),36m_length(0),37m_timed(false)38{39}4041void Sound1::Reset ()42{43m_on = false;44m_timed = false;45m_length = 0;46m_envelope = 0;47m_posP = m_posE = m_posS = 0;48m_sample = 0;49}5051void Sound1::ResetSound ()52{53m_on = true;54m_timed = (m_cntx & (0x1 << 14));55m_length = (64 - (m_cnth & 0x3F)) * ((16*1024*1024)/256);56m_envelope = m_cnth >> 12;57m_posE = m_posS = 0;58}5960void Sound1::SoundTick ()61{62// remember here that the processors runs at 16MHz = 16,777,216 cycles/s63// and this function is called normally at 44,100 Hz6465m_posP += m_speriod;66m_posS += m_speriod;67m_posE += m_speriod;68if (m_length > m_speriod)69m_length -= m_speriod;70else71{72if (m_timed)73m_on = false;74m_length = 0;75}7677// sweep time in cycles78// maximum is 917,504, so we need a 32 bits int79uint32_t sweeptime = ((m_cntl >> 4) & 0x7) * ((16*1024*1024)/128);80// period in cycles81// period = 16M/freq82// freq = 128K/(2048 - (SOUND1CNT_X & 0x7FF))83// maximum is 262,144, so we need a 32 bits int84uint32_t period =85((16*1024*1024) / (128*1024)) * (2048 - (m_cntx & 0x7FF));86// frequency as contained in SOUND1CNT_X87uint16_t freq = m_cntx & 0x7FF;8889// we rewind posP90m_posP %= period;9192// the envelope now93// envelope step time in cycles94uint32_t steptime = ((m_cnth >> 8) & 0x7) * ((16*1024*1024)/64);95// the envelope can't do two steps between to calls of SoundTick96if (steptime && m_posE > steptime)97{98if (m_cnth & (0x1 << 11))99{100if (m_envelope < 15)101++m_envelope;102}103else104{105if (m_envelope > 0)106--m_envelope;107}108109m_posE -= steptime;110}111112// if the envelope is null or the sound is finished, no need to calculate113// anything114if (m_on && m_envelope)115{116// we set the sample according to the position in the current period117// and the wave duty cycle118switch ((m_cnth >> 6) & 0x3)119{120case 0: // 12.5%121m_sample = m_posP < period/8 ? 112 : -16;122break;123case 1: // 25%124m_sample = m_posP < period/4 ? 96 : -32;125break;126case 2: // 50%127m_sample = m_posP < period/2 ? 64 : -64;128break;129case 3: // 75%130m_sample = m_posP < (3*period)/4 ? 32 : -96;131break;132}133134m_sample = (((int16_t)m_sample) * m_envelope)/15;135}136else137m_sample = 0;138139// there can't have been more than one sweep between two call of140// SoundTick since SoundTick is called at least at a frequency of 4,000Hz141// (alsa can't output at a lower samplerate on my sound card) and sweeps142// happen at maximum at a frequency of 128Hz143144// if the channel is on and sweep is enabled and it's time to sweep145if (m_on && sweeptime && m_posS > sweeptime)146{147// n = sweep shifts (in SOUND1CNT_L)148if (m_cntl & (0x1 << 3))149// F(t+1) = F(t) - F(t) / 2^n150freq = freq - freq / (1 << (m_cntl & 0x7));151// freq won't go under 1 since when freq = 2, freq - freq / 2 (the152// minimum sweep shift) = 1 and then freq - freq / 2 = 1153// because 1/2 = 0154else155{156// F(t+1) = F(t) + F(t) / 2^n157freq = freq + freq / (1 << (m_cntl & 0x7));158if (freq > 2047)159{160m_on = false;161freq = 2047;162}163}164165// we update the frequency in the cntx register166m_cntx = (m_cntx & 0xF800) | freq;167168// now we rewind posS169m_posS -= sweeptime;170}171}172173bool Sound1::SaveState (std::ostream& stream)174{175SS_WRITE_VAR(m_on);176SS_WRITE_VAR(m_posP);177SS_WRITE_VAR(m_posS);178SS_WRITE_VAR(m_posE);179SS_WRITE_VAR(m_sample);180SS_WRITE_VAR(m_envelope);181SS_WRITE_VAR(m_length);182SS_WRITE_VAR(m_timed);183184return true;185}186187bool Sound1::LoadState (std::istream& stream)188{189SS_READ_VAR(m_on);190SS_READ_VAR(m_posP);191SS_READ_VAR(m_posS);192SS_READ_VAR(m_posE);193SS_READ_VAR(m_sample);194SS_READ_VAR(m_envelope);195SS_READ_VAR(m_length);196SS_READ_VAR(m_timed);197198return true;199}200}201}202203204