1166 lines
37 KiB
C
1166 lines
37 KiB
C
/*
|
|
|
|
This file is part of Emu-Pizza
|
|
|
|
Emu-Pizza is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Emu-Pizza is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Emu-Pizza. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include "cycles.h"
|
|
#include "global.h"
|
|
#include "gpu.h"
|
|
#include "mmu.h"
|
|
#include "sound.h"
|
|
#include "utils.h"
|
|
#include "sound_output.h"
|
|
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/time.h>
|
|
|
|
/* super variable for audio controller */
|
|
sound_t sound;
|
|
|
|
// functions to connect to blip buf
|
|
static int16_t last_sample[8];
|
|
|
|
#define BLIP_LEFT(v,i) if(1){int32_t d = (v)-last_sample[(i)*2];blip_left(d);last_sample[(i)*2] = (v);}
|
|
#define BLIP_RIGHT(v,i) if(1){int32_t d = (v)-last_sample[(i)*2+1];blip_right(d);last_sample[(i)*2+1] = (v);}
|
|
|
|
static void blip_ch1()
|
|
{
|
|
if (sound.channel_one.active)
|
|
{
|
|
if (sound.nr51->ch1_to_so1)
|
|
BLIP_RIGHT(sound.channel_one.sample, 0);
|
|
if (sound.nr51->ch1_to_so2)
|
|
BLIP_LEFT(sound.channel_one.sample, 0);
|
|
}
|
|
}
|
|
static void blip_ch2()
|
|
{
|
|
if (sound.channel_two.active)
|
|
{
|
|
if (sound.nr51->ch2_to_so1)
|
|
BLIP_RIGHT(sound.channel_two.sample, 1);
|
|
if (sound.nr51->ch2_to_so2)
|
|
BLIP_LEFT(sound.channel_two.sample, 1);
|
|
}
|
|
}
|
|
static void blip_ch3()
|
|
{
|
|
if (sound.channel_three.active)
|
|
{
|
|
uint16_t sample;
|
|
uint8_t shift = (sound.nr32->volume_code == 0 ?
|
|
4 : sound.nr32->volume_code - 1);
|
|
|
|
/* volume is zero in any case */
|
|
if (shift == 4)
|
|
sample = 0;
|
|
else
|
|
{
|
|
/* apply volume change */
|
|
uint8_t idx = sound.channel_three.index;
|
|
uint16_t s;
|
|
|
|
/* extract current sample */
|
|
if ((idx & 0x01) == 0)
|
|
s = (sound.wave_table[idx >> 1] & 0xf0) >> 4;
|
|
else
|
|
s = sound.wave_table[idx >> 1] & 0x0f;
|
|
|
|
/* transform it into signed 16 bit sample */
|
|
sample = ((s * 0x222) >> shift);
|
|
}
|
|
|
|
|
|
/* not silence? */
|
|
if (sample != 0)
|
|
{
|
|
if (sound.nr51->ch3_to_so1)
|
|
BLIP_RIGHT(sample, 2);
|
|
if (sound.nr51->ch3_to_so2)
|
|
BLIP_LEFT(sample, 2);
|
|
}
|
|
}
|
|
}
|
|
static void blip_ch4()
|
|
{
|
|
if (sound.channel_four.active)
|
|
{
|
|
if (sound.nr51->ch4_to_so1)
|
|
BLIP_RIGHT(sound.channel_four.sample, 3);
|
|
if (sound.nr51->ch4_to_so2)
|
|
BLIP_LEFT(sound.channel_four.sample, 3);
|
|
}
|
|
}
|
|
|
|
/* internal prototypes */
|
|
void sound_envelope_step();
|
|
void sound_length_ctrl_step();
|
|
void sound_sweep_step();
|
|
void sound_write_wave(uint16_t a, uint8_t v);
|
|
|
|
void sound_init_pointers()
|
|
{
|
|
/* point sound structures to their memory areas */
|
|
sound.nr10 = (nr10_t *) mmu_addr(0xFF10);
|
|
sound.nr11 = (nr11_t *) mmu_addr(0xFF11);
|
|
sound.nr12 = (nr12_t *) mmu_addr(0xFF12);
|
|
sound.nr13 = (nr13_t *) mmu_addr(0xFF13);
|
|
sound.nr14 = (nr14_t *) mmu_addr(0xFF14);
|
|
|
|
sound.nr21 = (nr21_t *) mmu_addr(0xFF16);
|
|
sound.nr22 = (nr22_t *) mmu_addr(0xFF17);
|
|
sound.nr23 = (nr23_t *) mmu_addr(0xFF18);
|
|
sound.nr24 = (nr24_t *) mmu_addr(0xFF19);
|
|
|
|
sound.nr30 = (nr30_t *) mmu_addr(0xFF1A);
|
|
sound.nr31 = (nr31_t *) mmu_addr(0xFF1B);
|
|
sound.nr32 = (nr32_t *) mmu_addr(0xFF1C);
|
|
sound.nr33 = (nr33_t *) mmu_addr(0xFF1D);
|
|
sound.nr34 = (nr34_t *) mmu_addr(0xFF1E);
|
|
|
|
sound.nr41 = (nr41_t *) mmu_addr(0xFF20);
|
|
sound.nr42 = (nr42_t *) mmu_addr(0xFF21);
|
|
sound.nr43 = (nr43_t *) mmu_addr(0xFF22);
|
|
sound.nr44 = (nr44_t *) mmu_addr(0xFF23);
|
|
|
|
sound.nr50 = mmu_addr(0xFF24);
|
|
sound.nr51 = mmu_addr(0xFF25);
|
|
sound.nr52 = mmu_addr(0xFF26);
|
|
|
|
sound.wave_table = mmu_addr(0xFF30);
|
|
}
|
|
|
|
/* init sound states */
|
|
void sound_init()
|
|
{
|
|
/* reset structure */
|
|
bzero(&sound, sizeof(sound_t));
|
|
|
|
/* point sound structures to their memory areas */
|
|
sound_init_pointers();
|
|
|
|
/* how many cpu cycles we need to emit a 512hz clock (frame sequencer) */
|
|
sound.fs_cycles = 4194304 / 512;
|
|
|
|
/* how many cpu cycles to generate a single frame seq clock? */
|
|
sound.fs_cycles_next = sound.fs_cycles;
|
|
}
|
|
|
|
void sound_set_speed(char dbl)
|
|
{
|
|
}
|
|
|
|
/* update sound internal state given CPU T-states */
|
|
void sound_step_fs()
|
|
{
|
|
/* rotate from 0 to 7 */
|
|
sound.fs_cycles_idx = (sound.fs_cycles_idx + 1) & 0x07;
|
|
|
|
/* reset fs cycles counter */
|
|
sound.fs_cycles_next = cycles.cnt +
|
|
(sound.fs_cycles << global_cpu_double_speed);
|
|
|
|
/* length controller works at 256hz */
|
|
if ((sound.fs_cycles_idx & 0x01) == 0)
|
|
sound_length_ctrl_step();
|
|
|
|
/* sweep works at 128hz */
|
|
if (sound.fs_cycles_idx == 2 || sound.fs_cycles_idx == 6)
|
|
sound_sweep_step();
|
|
|
|
/* envelope works at 64hz */
|
|
if (sound.fs_cycles_idx == 7)
|
|
sound_envelope_step();
|
|
blip_ch1();
|
|
blip_ch2();
|
|
blip_ch3();
|
|
blip_ch4();
|
|
}
|
|
|
|
/* update all channels */
|
|
void sound_step_ch1()
|
|
{
|
|
/* recalc current samples */
|
|
if ((sound.channel_one.duty >> sound.channel_one.duty_idx) & 0x01)
|
|
sound.channel_one.sample = sound.channel_one.volume;
|
|
else
|
|
sound.channel_one.sample = -sound.channel_one.volume;
|
|
|
|
/* step to the next duty value */
|
|
sound.channel_one.duty_idx =
|
|
(sound.channel_one.duty_idx + 1) & 0x07;
|
|
|
|
/* go back */
|
|
sound.channel_one.duty_cycles_next += sound.channel_one.duty_cycles;
|
|
blip_ch1();
|
|
}
|
|
|
|
void sound_step_ch2()
|
|
{
|
|
/* recalc current samples */
|
|
if ((sound.channel_two.duty >> sound.channel_two.duty_idx) & 0x01)
|
|
sound.channel_two.sample = sound.channel_two.volume;
|
|
else
|
|
sound.channel_two.sample = -sound.channel_two.volume;
|
|
|
|
/* step to the next duty value */
|
|
sound.channel_two.duty_idx =
|
|
(sound.channel_two.duty_idx + 1) & 0x07;
|
|
|
|
/* go back */
|
|
sound.channel_two.duty_cycles_next += sound.channel_two.duty_cycles;
|
|
blip_ch2();
|
|
}
|
|
|
|
void sound_step_ch3()
|
|
{
|
|
/* switch to the next wave sample */
|
|
sound.channel_three.index = (sound.channel_three.index + 1) & 0x1F;
|
|
|
|
/* set the new current sample */
|
|
sound.channel_three.sample =
|
|
sound.channel_three.wave[sound.channel_three.index];
|
|
|
|
/* reload new period */
|
|
uint_fast16_t freq = sound.nr33->frequency_lsb |
|
|
(sound.nr34->frequency_msb << 8);
|
|
|
|
/* qty of cpu ticks needed for a wave sample change */
|
|
sound.channel_three.cycles = ((2048 - freq) * 2) << global_cpu_double_speed;
|
|
sound.channel_three.cycles_next += sound.channel_three.cycles;
|
|
blip_ch3();
|
|
}
|
|
|
|
void sound_step_ch4()
|
|
{
|
|
/* update LSFR */
|
|
if (sound.nr43->shift < 14)
|
|
{
|
|
/* shift register one bit right */
|
|
uint16_t s = sound.channel_four.reg >> 1;
|
|
|
|
/* xor current register and the shifted version */
|
|
/* and extract bit zero */
|
|
uint16_t x = (sound.channel_four.reg ^ s) & 1;
|
|
|
|
/* update register */
|
|
sound.channel_four.reg = s | x << 14;
|
|
|
|
/* if width is set... */
|
|
if (sound.nr43->width)
|
|
sound.channel_four.reg =
|
|
(sound.channel_four.reg & 0xBF) | x << 6;
|
|
}
|
|
|
|
/* update sample */
|
|
if (sound.channel_four.reg & 0x01)
|
|
sound.channel_four.sample = -sound.channel_four.volume;
|
|
else
|
|
sound.channel_four.sample = sound.channel_four.volume;
|
|
|
|
/* qty of cpu ticks needed for a wave sample change */
|
|
sound.channel_four.cycles_next += sound.channel_four.period_lfsr;
|
|
blip_ch4();
|
|
}
|
|
|
|
/* update length of channel1 */
|
|
void static inline sound_length_ctrl_step_ch(char length_enable,
|
|
uint_fast32_t *length,
|
|
uint8_t *active)
|
|
{
|
|
if (length_enable && *length != 0)
|
|
{
|
|
(*length)--;
|
|
|
|
/* if ZERO is reached, turn off the channel */
|
|
if (*length == 0)
|
|
*active = 0;
|
|
}
|
|
}
|
|
|
|
/* length controller step */
|
|
void sound_length_ctrl_step()
|
|
{
|
|
/* step every channel */
|
|
sound_length_ctrl_step_ch(sound.nr14->length_enable,
|
|
&sound.channel_one.length,
|
|
&sound.channel_one.active);
|
|
|
|
sound_length_ctrl_step_ch(sound.nr24->length_enable,
|
|
&sound.channel_two.length,
|
|
&sound.channel_two.active);
|
|
|
|
sound_length_ctrl_step_ch(sound.nr34->length_enable,
|
|
&sound.channel_three.length,
|
|
&sound.channel_three.active);
|
|
|
|
sound_length_ctrl_step_ch(sound.nr44->length_enable,
|
|
&sound.channel_four.length,
|
|
&sound.channel_four.active);
|
|
}
|
|
|
|
/* calc the new frequency by sweep module */
|
|
uint_fast32_t sound_sweep_calc()
|
|
{
|
|
uint_fast32_t new_freq;
|
|
|
|
/* time to update frequency */
|
|
uint_fast32_t diff =
|
|
sound.channel_one.sweep_shadow_frequency >>
|
|
sound.nr10->shift;
|
|
|
|
/* the calculated diff must be summed or subtracted to frequency */
|
|
if (sound.nr10->negate)
|
|
{
|
|
new_freq = sound.channel_one.sweep_shadow_frequency - diff;
|
|
sound.channel_one.sweep_neg = 1;
|
|
}
|
|
else
|
|
new_freq = sound.channel_one.sweep_shadow_frequency + diff;
|
|
|
|
/* if freq > 2047, turn off the channel */
|
|
if (new_freq > 2047)
|
|
sound.channel_one.active = 0;
|
|
|
|
return new_freq;
|
|
}
|
|
|
|
/* set channel one new frequency */
|
|
void sound_set_frequency(uint_fast32_t new_freq)
|
|
{
|
|
/* too high? */
|
|
if (new_freq > 2047)
|
|
{
|
|
sound.channel_one.active = 0;
|
|
return;
|
|
}
|
|
|
|
/* update with the new frequency */
|
|
sound.channel_one.frequency = new_freq;
|
|
|
|
/* update them also into memory */
|
|
sound.nr13->frequency_lsb = (uint8_t) (new_freq & 0x000000ff);
|
|
sound.nr14->frequency_msb = (uint8_t) ((new_freq >> 8) & 0x00000007);
|
|
|
|
/* update the duty cycles */
|
|
sound.channel_one.duty_cycles =
|
|
((2048 - new_freq) * 4) << global_cpu_double_speed;
|
|
|
|
/* and reset them */
|
|
sound.channel_one.duty_cycles_next =
|
|
cycles.cnt + sound.channel_one.duty_cycles;
|
|
}
|
|
|
|
/* step of frequency sweep at 128hz */
|
|
void sound_sweep_step()
|
|
{
|
|
uint_fast32_t new_freq;
|
|
|
|
if (sound.channel_one.active &&
|
|
sound.channel_one.sweep_active)
|
|
{
|
|
/* make it rotate from 0 to 8 */
|
|
sound.channel_one.sweep_cnt++;
|
|
|
|
/* enough cycles? */
|
|
if (sound.channel_one.sweep_cnt == sound.channel_one.sweep_next)
|
|
{
|
|
/* reload the next step - 0 is treated as 8 */
|
|
sound.channel_one.sweep_next =
|
|
sound.nr10->sweep_period ?
|
|
sound.nr10->sweep_period : 8;
|
|
|
|
/* reset sweep counter */
|
|
sound.channel_one.sweep_cnt = 0;
|
|
|
|
/* period must be > 0 if new freq gotta be updated */
|
|
if (sound.nr10->sweep_period == 0)
|
|
return;
|
|
|
|
/* calc new frequency */
|
|
new_freq = sound_sweep_calc();
|
|
|
|
/* set it only if < 2048 and shift != 0 */
|
|
if (sound.nr10->shift &&
|
|
new_freq < 2048)
|
|
{
|
|
/* copy new_freq into shadow register */
|
|
sound.channel_one.sweep_shadow_frequency = new_freq;
|
|
|
|
/* update all the stuff related to new frequency */
|
|
sound_set_frequency(new_freq);
|
|
|
|
/* update freq again (but only in shadow register) */
|
|
sound_sweep_calc();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* step of envelope at 64hz */
|
|
void sound_envelope_step()
|
|
{
|
|
if (sound.channel_one.active && sound.nr12->period)
|
|
{
|
|
/* update counter */
|
|
sound.channel_one.envelope_cnt++;
|
|
|
|
/* if counter reaches period, update volume */
|
|
if (sound.channel_one.envelope_cnt == sound.nr12->period)
|
|
{
|
|
if (sound.nr12->add)
|
|
{
|
|
if (sound.channel_one.volume < (14 * 0x111))
|
|
sound.channel_one.volume += 0x111;
|
|
}
|
|
else
|
|
{
|
|
if (sound.channel_one.volume >= 0x111)
|
|
sound.channel_one.volume -= 0x111;
|
|
}
|
|
|
|
/* reset counter */
|
|
sound.channel_one.envelope_cnt = 0;
|
|
}
|
|
}
|
|
|
|
if (sound.channel_two.active && sound.nr22->period)
|
|
{
|
|
/* update counter */
|
|
sound.channel_two.envelope_cnt++;
|
|
|
|
/* if counter reaches period, update volume */
|
|
if (sound.channel_two.envelope_cnt == sound.nr22->period)
|
|
{
|
|
if (sound.nr22->add)
|
|
{
|
|
if (sound.channel_two.volume < (14 * 0x111))
|
|
sound.channel_two.volume += 0x111;
|
|
}
|
|
else
|
|
{
|
|
if (sound.channel_two.volume >= 0x111)
|
|
sound.channel_two.volume -= 0x111;
|
|
}
|
|
|
|
/* reset counter */
|
|
sound.channel_two.envelope_cnt = 0;
|
|
}
|
|
}
|
|
|
|
if (sound.channel_four.active && sound.nr42->period)
|
|
{
|
|
/* update counter */
|
|
sound.channel_four.envelope_cnt++;
|
|
|
|
/* if counter reaches period, update volume */
|
|
if (sound.channel_four.envelope_cnt == sound.nr42->period)
|
|
{
|
|
if (sound.nr42->add)
|
|
{
|
|
if (sound.channel_four.volume < (14 * 0x111))
|
|
sound.channel_four.volume += 0x111;
|
|
}
|
|
else
|
|
{
|
|
if (sound.channel_four.volume > 0x111)
|
|
sound.channel_four.volume -= 0x111;
|
|
}
|
|
|
|
/* reset counter */
|
|
sound.channel_four.envelope_cnt = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t sound_read_reg(uint16_t a, uint8_t v)
|
|
{
|
|
switch (a)
|
|
{
|
|
/* NR1X */
|
|
case 0xFF10: return v | 0x80;
|
|
case 0xFF11: return v | 0x3F;
|
|
case 0xFF12: return v;
|
|
case 0xFF13: return v | 0xFF;
|
|
case 0xFF14: return v | 0xBF;
|
|
/* NR2X */
|
|
case 0xFF15: return v | 0xFF;
|
|
case 0xFF16: return v | 0x3F;
|
|
case 0xFF17: return v;
|
|
case 0xFF18: return v | 0xFF;
|
|
case 0xFF19: return v | 0xBF;
|
|
/* NR3X */
|
|
case 0xFF1A: return v | 0x7F;
|
|
case 0xFF1B: return v | 0xFF;
|
|
case 0xFF1C: return v | 0x9F;
|
|
case 0xFF1D: return v | 0xFF;
|
|
case 0xFF1E: return v | 0xBF;
|
|
/* NR4X */
|
|
case 0xFF1F: return v | 0xFF;
|
|
case 0xFF20: return v | 0xFF;
|
|
case 0xFF21: return v;
|
|
case 0xFF22: return v;
|
|
case 0xFF23: return v | 0xBF;
|
|
/* NR5X */
|
|
case 0xFF24: return v;
|
|
case 0xFF25: return v;
|
|
case 0xFF26:
|
|
if (sound.nr52->power)
|
|
return 0xf0 |
|
|
sound.channel_one.active |
|
|
(sound.channel_two.active << 1) |
|
|
(sound.channel_three.active << 2) |
|
|
(sound.channel_four.active << 3);
|
|
else
|
|
return 0x70;
|
|
case 0xFF27:
|
|
case 0xFF28:
|
|
case 0xFF29:
|
|
case 0xFF2A:
|
|
case 0xFF2B:
|
|
case 0xFF2C:
|
|
case 0xFF2D:
|
|
case 0xFF2E:
|
|
case 0xFF2F: return 0xFF;
|
|
case 0xFF30:
|
|
case 0xFF31:
|
|
case 0xFF32:
|
|
case 0xFF33:
|
|
case 0xFF34:
|
|
case 0xFF35:
|
|
case 0xFF36:
|
|
case 0xFF37:
|
|
case 0xFF38:
|
|
case 0xFF39:
|
|
case 0xFF3A:
|
|
case 0xFF3B:
|
|
case 0xFF3C:
|
|
case 0xFF3D:
|
|
case 0xFF3E:
|
|
case 0xFF3F:
|
|
if (sound.channel_three.active)
|
|
{
|
|
/* if (!global_cgb && sound.channel_three.ram_access != 0)
|
|
{
|
|
printf("RAM ACCESSO NON ZERO %u - CNT %d NEXT %d\n",
|
|
sound.channel_three.ram_access, cycles.cnt, sound.channel_three.ram_access_next);
|
|
return 0xFF;
|
|
}*/
|
|
if (!global_cgb &&
|
|
cycles.cnt < sound.channel_three.ram_access_next)
|
|
return 0xFF;
|
|
|
|
return sound.wave_table[sound.channel_three.index >> 1];
|
|
}
|
|
|
|
default: return v;
|
|
}
|
|
}
|
|
|
|
void sound_write_reg(uint16_t a, uint8_t v)
|
|
{
|
|
/* when turned off, only write to NR52 (0xFF26) is legit */
|
|
if (!sound.nr52->power && a != 0xFF26)
|
|
{
|
|
/* CGB mode doesnt allow any write on register during power off */
|
|
if (global_cgb)
|
|
return;
|
|
|
|
/* in DMG mode, update length is legit while no power */
|
|
switch (a)
|
|
{
|
|
case 0xFF11: sound.channel_one.length = 64 - (v & 0x3f); return;
|
|
case 0xFF16: sound.channel_two.length = 64 - (v & 0x3f); return;
|
|
case 0xFF1B: sound.channel_three.length = 256 - v; return;
|
|
case 0xFF20: sound.channel_four.length = 64 - (v & 0x3f); return;
|
|
default: return;
|
|
}
|
|
}
|
|
|
|
/* wave write */
|
|
if (a >= 0xFF30 && a <= 0xFF3F)
|
|
return sound_write_wave(a, v);
|
|
|
|
/* save old value */
|
|
uint8_t old = *((uint8_t *) mmu_addr(a));
|
|
|
|
/* confirm write on memory */
|
|
*((uint8_t *) mmu_addr(a)) = v;
|
|
|
|
switch (a)
|
|
{
|
|
case 0xFF10:
|
|
|
|
if (!sound.nr10->negate && sound.channel_one.sweep_neg)
|
|
sound.channel_one.active = 0;
|
|
|
|
break;
|
|
|
|
case 0xFF11:
|
|
|
|
/* set length as 64 - length_load */
|
|
sound.channel_one.length = 64 - sound.nr11->length_load;
|
|
|
|
/* update duty type */
|
|
switch (sound.nr11->duty)
|
|
{
|
|
/* 12.5 % */
|
|
case 0x00: sound.channel_one.duty = 0x80;
|
|
break;
|
|
|
|
/* 25% */
|
|
case 0x01: sound.channel_one.duty = 0x81;
|
|
break;
|
|
|
|
/* 50% */
|
|
case 0x02: sound.channel_one.duty = 0xE1;
|
|
break;
|
|
|
|
/* 75% */
|
|
case 0x03: sound.channel_one.duty = 0x7E;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xFF12:
|
|
|
|
/* volume 0 = turn off the DAC = turn off channeru */
|
|
if (sound.nr12->volume == 0 &&
|
|
sound.nr12->add == 0)
|
|
sound.channel_one.active = 0;
|
|
|
|
break;
|
|
|
|
case 0xFF13:
|
|
|
|
/* update frequncy */
|
|
sound.channel_one.frequency = sound.nr13->frequency_lsb |
|
|
(sound.nr14->frequency_msb << 8);
|
|
|
|
/* update duty cycles */
|
|
sound.channel_one.duty_cycles =
|
|
((2048 - sound.channel_one.frequency) * 4)
|
|
<< global_cpu_double_speed;
|
|
|
|
break;
|
|
|
|
case 0xFF14:
|
|
|
|
/* length counter turned on */
|
|
if (sound.nr14->length_enable)
|
|
{
|
|
nr14_t *old_nr14 = (nr14_t *) &old;
|
|
|
|
/* give an extra length clock if */
|
|
/* 1) we switched from off to on the len counter */
|
|
/* 2) we are in the first half of len clock */
|
|
/* 3) actual length is not zero */
|
|
if ((old_nr14->length_enable == 0) &&
|
|
((sound.fs_cycles_idx & 0x01) == 0x00) &&
|
|
(sound.channel_one.length != 0))
|
|
sound_length_ctrl_step_ch(sound.nr14->length_enable,
|
|
&sound.channel_one.length,
|
|
&sound.channel_one.active);
|
|
}
|
|
|
|
/* always update frequency, even if it's not a trigger */
|
|
sound.channel_one.frequency = sound.nr13->frequency_lsb |
|
|
(sound.nr14->frequency_msb << 8);
|
|
|
|
/* qty of cpu ticks needed for a duty change */
|
|
/* (1/8 of wave cycle) */
|
|
sound.channel_one.duty_cycles =
|
|
((2048 - sound.channel_one.frequency) * 4)
|
|
<< global_cpu_double_speed;
|
|
|
|
if (v & 0x80)
|
|
{
|
|
/* if we switch from OFF to ON, reset duty idx */
|
|
if (sound.channel_two.active == 0)
|
|
sound.channel_two.duty_idx = 0;
|
|
|
|
/* setting internal modules data with stuff taken from memory */
|
|
sound.channel_one.active = 1;
|
|
sound.channel_one.duty_cycles_next =
|
|
cycles.cnt + sound.channel_one.duty_cycles;
|
|
|
|
/* set the 8 phase of a duty cycle by setting 8 bits */
|
|
switch (sound.nr11->duty)
|
|
{
|
|
/* 12.5 % */
|
|
case 0x00: sound.channel_one.duty = 0x80;
|
|
break;
|
|
|
|
/* 25% */
|
|
case 0x01: sound.channel_one.duty = 0x81;
|
|
break;
|
|
|
|
/* 50% */
|
|
case 0x02: sound.channel_one.duty = 0xE1;
|
|
break;
|
|
|
|
/* 75% */
|
|
case 0x03: sound.channel_one.duty = 0x7E;
|
|
break;
|
|
}
|
|
|
|
/* calc length */
|
|
if (sound.channel_one.length == 0)
|
|
sound.channel_one.length = 64;
|
|
|
|
/* base volume */
|
|
sound.channel_one.volume =
|
|
sound.nr12->volume * 0x111;
|
|
|
|
/* reset envelope counter */
|
|
sound.channel_one.envelope_cnt = 0;
|
|
|
|
/* save current freq into sweep shadow register */
|
|
sound.channel_one.sweep_shadow_frequency =
|
|
sound.channel_one.frequency;
|
|
|
|
/* reset sweep timer */
|
|
sound.channel_one.sweep_cnt = 0;
|
|
|
|
/* reset sweep neg bool */
|
|
sound.channel_one.sweep_neg = 0;
|
|
|
|
/* reload the next step */
|
|
sound.channel_one.sweep_next = sound.nr10->sweep_period ?
|
|
sound.nr10->sweep_period : 8;
|
|
|
|
/* set sweep as active if period != 0 or shift != 0 */
|
|
if (sound.nr10->sweep_period != 0 ||
|
|
sound.nr10->shift != 0)
|
|
sound.channel_one.sweep_active = 1;
|
|
else
|
|
sound.channel_one.sweep_active = 0;
|
|
|
|
/* if shift is != 0, calc the new frequency */
|
|
if (sound.nr10->shift != 0)
|
|
{
|
|
uint32_t new_freq = sound_sweep_calc();
|
|
|
|
/* update all the stuff related to new frequency */
|
|
sound_set_frequency(new_freq);
|
|
}
|
|
|
|
/* if DAC is off, turn off the channel */
|
|
if (sound.nr12->add == 0 &&
|
|
sound.nr12->volume == 0)
|
|
sound.channel_one.active = 0;
|
|
|
|
/* extra length clock if length == 64 */
|
|
/* and FS is in the fist half */
|
|
if ((sound.fs_cycles_idx & 0x01) == 0x00 &&
|
|
sound.channel_one.length == 64)
|
|
sound_length_ctrl_step_ch(sound.nr14->length_enable,
|
|
&sound.channel_one.length,
|
|
&sound.channel_one.active);
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
case 0xFF16:
|
|
|
|
sound.channel_two.length = 64 - sound.nr21->length_load;
|
|
|
|
/* update duty type */
|
|
switch (sound.nr21->duty)
|
|
{
|
|
/* 12.5 % */
|
|
case 0x00: sound.channel_two.duty = 0x80;
|
|
break;
|
|
|
|
/* 25% */
|
|
case 0x01: sound.channel_two.duty = 0x81;
|
|
break;
|
|
|
|
/* 50% */
|
|
case 0x02: sound.channel_two.duty = 0xE1;
|
|
break;
|
|
|
|
/* 75% */
|
|
case 0x03: sound.channel_two.duty = 0x7E;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xFF17:
|
|
|
|
/* volume 0 = turn off the DAC = turn off channeru */
|
|
if (sound.nr22->volume == 0 &&
|
|
sound.nr22->add == 0)
|
|
sound.channel_two.active = 0;
|
|
|
|
break;
|
|
|
|
case 0xFF18:
|
|
|
|
/* update frequncy */
|
|
sound.channel_two.frequency = (sound.nr23->frequency_lsb |
|
|
(sound.nr24->frequency_msb << 8));
|
|
|
|
/* update duty cycles */
|
|
sound.channel_two.duty_cycles =
|
|
((2048 - sound.channel_two.frequency) * 4)
|
|
<< global_cpu_double_speed;
|
|
|
|
break;
|
|
|
|
case 0xFF19:
|
|
|
|
/* length counter turned on */
|
|
if (sound.nr24->length_enable)
|
|
{
|
|
nr24_t *old_nr24 = (nr24_t *) &old;
|
|
|
|
/* give an extra length clock if */
|
|
/* 1) we switched from off to on the len counter */
|
|
/* 2) we are in the first half of len clock */
|
|
/* 3) actual length is not zero */
|
|
if ((old_nr24->length_enable == 0) &&
|
|
((sound.fs_cycles_idx & 0x01) == 0x00) &&
|
|
(sound.channel_two.length != 0))
|
|
sound_length_ctrl_step_ch(sound.nr24->length_enable,
|
|
&sound.channel_two.length,
|
|
&sound.channel_two.active);
|
|
}
|
|
|
|
/* always update frequency, even if it's not a trigger */
|
|
sound.channel_two.frequency = sound.nr23->frequency_lsb |
|
|
(sound.nr24->frequency_msb << 8);
|
|
|
|
/* qty of cpu ticks needed for a duty change */
|
|
/* (1/8 of wave cycle) */
|
|
sound.channel_two.duty_cycles =
|
|
((2048 - sound.channel_two.frequency) * 4)
|
|
<< global_cpu_double_speed;
|
|
|
|
if (v & 0x80)
|
|
{
|
|
/* if we switch from OFF to ON, reset duty idx */
|
|
if (sound.channel_two.active == 0)
|
|
sound.channel_two.duty_idx = 0;
|
|
|
|
/* setting internal modules data with stuff taken from memory */
|
|
sound.channel_two.active = 1;
|
|
sound.channel_two.duty_cycles_next =
|
|
cycles.cnt + sound.channel_two.duty_cycles;
|
|
|
|
/* set the 8 phase of a duty cycle by setting 8 bits */
|
|
switch (sound.nr21->duty)
|
|
{
|
|
/* 12.5 % */
|
|
case 0x00: sound.channel_two.duty = 0x80;
|
|
break;
|
|
|
|
/* 25% */
|
|
case 0x01: sound.channel_two.duty = 0x81;
|
|
break;
|
|
|
|
/* 50% */
|
|
case 0x02: sound.channel_two.duty = 0xE1;
|
|
break;
|
|
|
|
/* 75% */
|
|
case 0x03: sound.channel_two.duty = 0x7E;
|
|
break;
|
|
}
|
|
|
|
/* calc length */
|
|
if (sound.channel_two.length == 0)
|
|
sound.channel_two.length = 64;
|
|
|
|
/* base volume */
|
|
sound.channel_two.volume =
|
|
sound.nr22->volume * 0x111;
|
|
|
|
/* reset envelope counter */
|
|
sound.channel_two.envelope_cnt = 0;
|
|
|
|
/* if DAC is off, turn off the channel */
|
|
if (sound.nr22->add == 0 &&
|
|
sound.nr22->volume == 0)
|
|
sound.channel_two.active = 0;
|
|
|
|
/* extra length clock if length == 64 */
|
|
/* and FS is in the fist half */
|
|
if ((sound.fs_cycles_idx & 0x01) == 0x00 &&
|
|
sound.channel_two.length == 64)
|
|
sound_length_ctrl_step_ch(sound.nr24->length_enable,
|
|
&sound.channel_two.length,
|
|
&sound.channel_two.active);
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xFF1A:
|
|
|
|
/* if DAC is off, disable the channel */
|
|
if (sound.nr30->dac == 0)
|
|
sound.channel_three.active = 0;
|
|
|
|
break;
|
|
|
|
case 0xFF1B:
|
|
|
|
sound.channel_three.length =
|
|
256 - sound.nr31->length_load;
|
|
|
|
break;
|
|
|
|
case 0xFF1C:
|
|
|
|
break;
|
|
|
|
case 0xFF1E:
|
|
|
|
/* length counter turned on */
|
|
if (sound.nr34->length_enable)
|
|
{
|
|
nr34_t *old_nr34 = (nr34_t *) &old;
|
|
|
|
/* give an extra length clock if */
|
|
/* 1) we switched from off to on the len counter */
|
|
/* 2) we are in the first half of len clock */
|
|
/* 3) actual length is not zero */
|
|
if ((old_nr34->length_enable == 0) &&
|
|
((sound.fs_cycles_idx & 0x01) == 0x00) &&
|
|
(sound.channel_three.length != 0))
|
|
sound_length_ctrl_step_ch(sound.nr34->length_enable,
|
|
&sound.channel_three.length,
|
|
&sound.channel_three.active);
|
|
}
|
|
|
|
if (v & 0x80)
|
|
{
|
|
uint16_t freq = sound.nr33->frequency_lsb |
|
|
(sound.nr34->frequency_msb << 8);
|
|
|
|
/* setting internal modules data with stuff taken from memory */
|
|
sound.channel_three.active = 1;
|
|
|
|
uint_fast32_t old_cycles = sound.channel_three.cycles;
|
|
|
|
/* qty of cpu ticks needed for a wave sample change */
|
|
sound.channel_three.cycles =
|
|
(((2048 - freq) * 2) + 6) << global_cpu_double_speed;
|
|
|
|
|
|
/* treat obscure behaviours.... */
|
|
if (!global_cgb &&
|
|
cycles.cnt + 8 == sound.channel_three.cycles_next +
|
|
sound.channel_three.cycles -
|
|
old_cycles)
|
|
{
|
|
uint8_t next =
|
|
((sound.channel_three.index + 1) & 0x1F) >> 1;
|
|
|
|
if (next < 4)
|
|
sound.wave_table[0] = sound.wave_table[next];
|
|
else
|
|
memcpy(sound.wave_table,
|
|
&sound.wave_table[next & 0xfc], 4);
|
|
}
|
|
|
|
/* init wave table index */
|
|
sound.channel_three.index = 0;
|
|
sound.channel_three.cycles_next =
|
|
cycles.cnt + sound.channel_three.cycles;
|
|
|
|
/* calc length */
|
|
if (sound.channel_three.length == 0)
|
|
sound.channel_three.length = 256;
|
|
|
|
/* if DAC is off, disable the channel */
|
|
if (sound.nr30->dac == 0)
|
|
sound.channel_three.active = 0;
|
|
|
|
/* extra length clock if length == 256 */
|
|
/* and FS is in the fist half */
|
|
if ((sound.fs_cycles_idx & 0x01) == 0x00 &&
|
|
sound.channel_three.length == 256)
|
|
sound_length_ctrl_step_ch(sound.nr34->length_enable,
|
|
&sound.channel_three.length,
|
|
&sound.channel_three.active);
|
|
|
|
/* i accessed to the wave RAM... */
|
|
sound.channel_three.ram_access = sound.channel_three.cycles;
|
|
|
|
if (sound.channel_three.cycles % 4 == 0)
|
|
sound.channel_three.ram_access_next =
|
|
cycles.cnt + sound.channel_three.cycles;
|
|
else
|
|
sound.channel_three.ram_access_next = -1;
|
|
|
|
/* printf("RAM ACCESS RICARICATO %u - CNT %d CYCLES %d \n",
|
|
sound.channel_three.ram_access,
|
|
cycles.cnt, sound.channel_three.cycles);*/
|
|
}
|
|
break;
|
|
|
|
case 0xFF20:
|
|
|
|
sound.channel_four.length = 64 - sound.nr41->length_load;
|
|
|
|
break;
|
|
|
|
case 0xFF21:
|
|
|
|
/* highest 5 bits cleared = turn off the DAC = turn off channeru */
|
|
if (sound.nr42->volume == 0 &&
|
|
sound.nr42->add == 0)
|
|
sound.channel_four.active = 0;
|
|
|
|
break;
|
|
|
|
case 0xFF23:
|
|
|
|
/* length counter turned on */
|
|
if (sound.nr44->length_enable)
|
|
{
|
|
nr44_t *old_nr44 = (nr44_t *) &old;
|
|
|
|
/* give an extra length clock if */
|
|
/* 1) we switched from off to on the len counter */
|
|
/* 2) we are in the first half of len clock */
|
|
/* 3) actual length is not zero */
|
|
if ((old_nr44->length_enable == 0) &&
|
|
((sound.fs_cycles_idx & 0x01) == 0x00) &&
|
|
(sound.channel_four.length != 0))
|
|
sound_length_ctrl_step_ch(sound.nr44->length_enable,
|
|
&sound.channel_four.length,
|
|
&sound.channel_four.active);
|
|
}
|
|
|
|
if (v & 0x80)
|
|
{
|
|
/* setting internal modules data with stuff taken from memory */
|
|
sound.channel_four.active = 1;
|
|
|
|
/* calc length */
|
|
if (sound.channel_four.length == 0)
|
|
sound.channel_four.length = 64;
|
|
|
|
uint16_t divisor;
|
|
|
|
/* calc LFSR period */
|
|
switch (sound.nr43->divisor)
|
|
{
|
|
case 0: divisor = 8; break;
|
|
case 1: divisor = 16; break;
|
|
case 2: divisor = 32; break;
|
|
case 3: divisor = 48; break;
|
|
case 4: divisor = 64; break;
|
|
case 5: divisor = 80; break;
|
|
case 6: divisor = 96; break;
|
|
case 7: divisor = 112; break;
|
|
}
|
|
|
|
/* calc LFSR period */
|
|
sound.channel_four.period_lfsr = divisor << sound.nr43->shift;
|
|
sound.channel_four.cycles_next =
|
|
cycles.cnt + sound.channel_four.period_lfsr;
|
|
|
|
/* init reg to all bits to 1 */
|
|
sound.channel_four.reg = 0x7FFF;
|
|
|
|
/* base volume */
|
|
sound.channel_four.volume =
|
|
sound.nr42->volume * 0x111;
|
|
|
|
/* reset envelope counter */
|
|
sound.channel_four.envelope_cnt = 0;
|
|
|
|
/* if DAC is off, turn off the channel */
|
|
if (sound.nr42->add == 0 &&
|
|
sound.nr42->volume == 0)
|
|
sound.channel_four.active = 0;
|
|
|
|
/* extra length clock if length == 64 */
|
|
/* and FS is in the fist half */
|
|
if ((sound.fs_cycles_idx & 0x01) == 0x00 &&
|
|
sound.channel_four.length == 64)
|
|
sound_length_ctrl_step_ch(sound.nr44->length_enable,
|
|
&sound.channel_four.length,
|
|
&sound.channel_four.active);
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xFF26:
|
|
|
|
if (v & 0x80)
|
|
{
|
|
/* power from off to on! */
|
|
if (!(old & 0x80))
|
|
{
|
|
/* reset frame sequencer so the next step will be zero */
|
|
sound.fs_cycles_idx = 7;
|
|
|
|
/* reset wave index */
|
|
sound.channel_three.index = 0;
|
|
|
|
/* wave samples are resetted */
|
|
bzero(sound.wave_table, 16);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* power off */
|
|
|
|
/* clear all the sound memory */
|
|
bzero(mmu_addr(0xFF10), 22);
|
|
|
|
if (global_cgb)
|
|
{
|
|
sound.nr41->length_load = 0;
|
|
sound.channel_four.length = 0;
|
|
}
|
|
|
|
/* turn off every channeru */
|
|
sound.channel_one.active = 0;
|
|
sound.channel_two.active = 0;
|
|
sound.channel_three.active = 0;
|
|
sound.channel_four.active = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void sound_write_wave(uint16_t a, uint8_t v)
|
|
{
|
|
if (sound.channel_three.active)
|
|
{
|
|
// if (!global_cgb && sound.channel_three.ram_access != 0)
|
|
// return;
|
|
if (!global_cgb && cycles.cnt < sound.channel_three.ram_access_next)
|
|
return;
|
|
|
|
sound.wave_table[sound.channel_three.index >> 1] = v;
|
|
|
|
return;
|
|
}
|
|
|
|
sound.wave_table[a - 0xFF30] = v;
|
|
}
|