Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Channel 1, 2 dual-wave channels (Channel 1 supports "real-time" frequency conversion scanning) */
- /* In GBC/GB games, it is usually used as the main melody channel. */
- struct channel_squ {
- int32_t sweep_phase; /* Frequency scan basic timestamp (based on CPU clock cycle) */
- int32_t sweep_trigger; /* Frequency scan update clock point (based on CPU clock cycle) */
- int32_t signal_phase; /* Square wave signal updates the basic timestamp (based on CPU clock cycle).
- One f (x) of the waveform, that is, one hz,
- scans eight points of the current square wave duty cycle (based on CPU clock cycle). */
- int32_t signal_trigger; /* Square wave signal update clock point (based on CPU clock cycle) */
- int32_t length_phase; /* Basic time stamp of square wave signal sound length (based on CPU clock cycle) */
- int32_t length_trigger; /* Square wave signal length update clock point (based on CPU clock cycle) */
- int32_t envlope_phase; /* Square wave signal envelope basic timestamp (based on CPU clock cycle) */
- int32_t envlope_trigger; /* Square wave envelope update clock point (based on CPU clock cycle) */
- int32_t signal_output; /* Square wave signal output, note. As a level signal, only 0 or 1 will be output. */
- int32_t signal_volume; /* Signal amplification, also known as Volume. */
- int32_t duty_poll; /* Duty ratio look-up count, which essentially changes tone color, but also has a role in internal frequency division */
- int32_t length_count;/* Length counter */
- uint8_t *duty_vec; /* Square wave duty ratio vector table */
- uint16_t nrx0; /* Square-wave correlation registers used by GBA (sweep frequency) */
- uint16_t nrx1_x2; /* Square-wave correlation registers used by GBA (duty cycle/length/envelope [GBC NR register merge]) */
- uint16_t nrx3_x4; /* Square wave correlation registers used by GBA (restart/channel frequency write [high bit] [GBC NR register merge]) */
- uint8_t duty[4][8]; /* Duty ratio table, placed internally to facilitate Cache correlation */
- };
- /* Channel 3: 4-bit waveform
- /* In GBC/GB games, it is usually used as configurable waveforms,
- such as triangular/sinusoidal synthesis, and can also play some bad voices? */
- struct channel_wave {
- int32_t output_phase; /* Waveform update basic timestamp (based on CPU clock cycle) */
- int32_t output_trigger; /* Waveform update clock point, once f (x), that is, 1 Hz will scan 32/64 waveform scan points (based on CPU clock cycle) */
- int32_t length_phase; /* Waveform tone length basic timestamp (based on CPU clock cycle) */
- int32_t length_trigger; /* Waveform length update clock point (based on CPU clock cycle) */
- int32_t length_count;/* Length counter */
- int32_t counter; /* Waveform playback count */
- uint8_t qram[64]; /* 4-bit waveform correlation register used by GBA (PCM4-bit waveform writing) */
- uint16_t xram[16]; /* 4-bit waveform correlation register used by GBA (PCM4-bit waveform writing) */
- uint16_t nr30; /* 4-bit waveform-related registers used by GBA (channel switch/bank mode selection) */
- uint16_t nr31_32; /* 4-bit waveform-related registers used by GBA (length/volume) */
- uint16_t nr33_34; /* 4-bit waveform-related registers used by GBA (frequency/control) */
- };
- /* Channel 4: LFSR Random noise */
- /* Used as special effects and some simple drums in GBC/GB games. */
- struct channel_noise {
- int32_t signal_phase; /* Noise signal update basic timestamp (based on CPU clock cycle) */
- int32_t signal_trigger; /* Noise signal update clock point (based on CPU clock cycle) */
- int32_t length_phase; /* Noise length update basic timestamp (based on CPU clock cycle) */
- int32_t length_trigger; /* Noise length update clock point (based on CPU clock cycle) */
- int32_t envlope_phase; /* Noise envelope update basic timestamp (based on CPU clock cycle) */
- int32_t length_count;/* Length counter */
- int32_t envlope_trigger; /* Noise envelope update clock point (based on CPU clock cycle) */
- int32_t signal_output; /* Noise signal output, note. As a level signal, only 0 or 1 will be output. */
- int32_t signal_volume; /* Signal amplification, also known as Volume. */
- uint16_t nr41_42; /* Noise-related registers used by GBA (length/envelope) */
- uint16_t nr43_44; /* Noise-related registers used by GBA (frequency/control) */
- };
- /* Channel 5, 6 FIFO, 8-bit signed PCM, with the same name as DirectSound in Microsoft DirectX. */
- /* The strongest vocal channel, supporting 8Bit PCM,
- you can even use to play some clear voices, (Namco's Tales of Phantasia OP in GBA) */
- struct channel_fifo {
- int8_t buf [32]; /* PCM ring buffer */
- int8_t write; /* PCM write location */
- int8_t count; /* PCM effective count */
- int8_t read; /* PCM read location */
- };
- /* Channel master control/settings */
- struct channel_control {
- uint16_t nr50_51;
- uint16_t nr52;
- uint16_t snd_ctl;
- uint16_t pwm_ctl;
- };
- /* Synthesizer for GBA (based on GBC, adding two 8-bit PCM channels) */
- struct apu {
- struct channel_squ squ_ch[2];
- struct channel_wave wave_ch;
- struct channel_noise noise_ch;
- struct channel_fifo fifo_ch[2];
- struct channel_control settings;
- uint8_t pcm_buf[8 * APU_INTERNAL_BUFFER_N * APU_SAMPLE_FREQ_MAX / 59]; /* 8:max size (float) * channel 2 */
- uint32_t sam_bstop;
- uint32_t sam_bstart;
- uint32_t sam_pointer;
- struct gba *agb;
- };
- struct gba {
- struct arm7 arm7;
- struct controller joypad;
- struct timer timer;
- struct apu apu;
- struct dma dma;
- struct gpu gpu;
- struct cart cart;
- struct serial sio;
- struct dev_infos *dfs;
- uint32_t mctl;
- uint16_t mwait;
- uint8_t postf;
- uint32_t cache_ptr; /* I'm not really sure about the detailed caching information of the GBA machine. */
- uint8_t SRam[0x10000+32];
- uint8_t PRom[0x400*0x400*32+32];
- uint8_t WRam[0x400*256+32];
- uint8_t IRam[0x400*32+32];
- uint8_t bios[0x400*16+32];
- uint8_t IOMap[0x800+32];
- uint8_t wram_wait;
- uint8_t sram_wait;
- uint8_t noseq_wait0;
- uint8_t seq_wait0;
- uint8_t noseq_wait1;
- uint8_t seq_wait1;
- uint8_t noseq_wait2;
- uint8_t seq_wait2;
- uint8_t sram_wait_t[4];
- uint8_t noseq_wait0_t[4];
- uint8_t seq_wait0_t[2];
- uint8_t noseq_wait1_t[4];
- uint8_t seq_wait1_t[2];
- uint8_t noseq_wait2_t[4];
- uint8_t seq_wait2_t[2];
- int32_t clks_oft;
- int32_t clks_cpu_ct;
- };
- uint8_t callstd agb_mbus_rb_seq (struct gba *agb, uint32_t addr);
- uint8_t callstd agb_mbus_rb_noseq (struct gba *agb, uint32_t addr);
- uint16_t callstd agb_mbus_rhw_seq (struct gba *agb, uint32_t addr);
- uint16_t callstd agb_mbus_rhw_noseq (struct gba *agb, uint32_t addr);
- uint32_t callstd agb_mbus_rw_noseq (struct gba *agb, uint32_t addr);
- uint32_t callstd agb_mbus_rw_seq (struct gba *agb, uint32_t addr);
- void callstd agb_mbus_wb_noseq (struct gba *agb, uint32_t addr, uint8_t value);
- void callstd agb_mbus_wb_seq (struct gba *agb, uint32_t addr, uint8_t value);
- void callstd agb_mbus_whw_noseq (struct gba *agb, uint32_t addr, uint16_t value);
- void callstd agb_mbus_whw_seq (struct gba *agb, uint32_t addr, uint16_t value);
- void callstd agb_mbus_ww_noseq (struct gba *agb, uint32_t addr, uint32_t value);
- void callstd agb_mbus_ww_seq (struct gba *agb, uint32_t addr, uint32_t value);
- uint16_t callstd agb_code_rhw_seq (struct gba *agb, uint32_t addr) ;
- uint16_t callstd agb_code_rhw_noseq (struct gba *agb, uint32_t addr) ;
- uint32_t callstd agb_code_rw_seq (struct gba *agb, uint32_t addr);
- uint32_t callstd agb_code_rw_noseq (struct gba *agb, uint32_t addr);
- void callstd agb_gamepak_prefetch (struct gba *agb, uint32_t addr, uint32_t internal_clks);
- finline
- void check_halt (struct gba *agb, int int_mask) {
- if ((agb->arm7.halt & 0x80000001) == 0x80000001)
- if (agb->arm7.ime & int_mask)
- agb->arm7.halt &= ~1;
- else ;
- else ;
- }
- finline
- void check_stop (struct gba *agb, int int_mask) {
- if ((agb->arm7.halt & 0x80000001) == 0x00000001)
- if (agb->arm7.ime & int_mask)
- agb->arm7.halt &= ~1;
- else ;
- else ;
- }
- #include "gba.inl"
- #include "dma.inl"
- finline
- void squ_render (struct apu *apu, int ch, int32_t delta) {
- if ((apu->settings.nr52 & 0x80)) {
- if (!(apu->settings.nr52 & (1 << (ch & 1))))
- return ;
- else {
- struct channel_squ *squ = & apu->squ_ch[ch & 1];
- /* squ signal */
- squ->signal_phase += delta;
- if (squ->signal_phase >= squ->signal_trigger) {
- squ->duty_poll += squ->signal_phase / squ->signal_trigger;
- squ->signal_phase %= squ->signal_trigger;
- }
- /* squ envlope */
- if ((squ->nrx1_x2 >> 8) & 7) {
- squ->envlope_phase += delta;
- if (squ->envlope_phase >= squ->envlope_trigger) {
- squ->envlope_phase %= squ->envlope_trigger;
- if (squ->nrx1_x2 & 0x800) {
- squ->signal_volume += squ->envlope_phase / squ->envlope_trigger;
- if (squ->signal_volume > 15)
- squ->signal_volume = 15;
- } else {
- squ->signal_volume -= squ->envlope_phase / squ->envlope_trigger;
- if (squ->signal_volume < 0) {
- #ifdef NR_SQU_TEST1
- apu->settings.nr52 &= ~(1 << (ch & 1));
- #endif
- squ->signal_volume = 0;
- }
- }
- }
- }
- /* length count */
- squ->length_phase += delta;
- if (squ->length_phase > squ->length_trigger) {
- squ->length_count -= squ->length_phase/ squ->length_trigger;
- squ->length_phase %= squ->length_trigger;
- if (squ->length_count <= 0) {
- squ->length_count = 0;
- if (squ->nrx3_x4 & 0x4000)
- apu->settings.nr52 &= ~(1 << (ch & 1));
- }
- }
- /* freq sweep */
- if (!ch && (squ->nrx0 >> 4) & 7) {
- squ->sweep_phase += delta;
- if (squ->sweep_phase >= squ->sweep_trigger) {
- int _freq_n = squ->nrx3_x4 & 0x3FF;
- int _freq_s = _freq_n;
- int _block_n = squ->sweep_phase/ squ->sweep_trigger;
- squ->sweep_phase %= squ->sweep_trigger;
- if (squ->nrx0 & 8)
- while (_block_n-- > 0)
- _freq_n = (int) ((double) _freq_n - (double) _freq_n / (double)(1 << (squ->nrx0 & 7)));
- else
- while (_block_n-- > 0)
- _freq_n = (int) ((double) _freq_n + (double) _freq_n / (double)(1 << (squ->nrx0 & 7)));
- if (_freq_n <= 0)
- _freq_n = _freq_s;
- else if (_freq_n > 2047) {
- _freq_n = 2047; /* FIXME: right ??, i don't know */
- apu->settings.nr52 &= ~(1 << (ch & 1));
- }
- /* signal_trigger calc := cpu freq/ chan freq / duty 8 divider
- chan freq (hz):= 131072/(2048 - ch's freq data )
- */
- squ->signal_trigger = (int)((16780000.0/ 131072.0 / (double)(2048 - _freq_n)) / 8.0);
- if (squ->signal_phase >= squ->signal_trigger) {
- squ->duty_poll += squ->signal_phase / squ->signal_trigger;
- squ->signal_phase %= squ->signal_trigger;
- }
- }
- }
- }
- }
- }
- finline
- void wave_render (struct apu *apu, int32_t delta) {
- if ((apu->settings.nr52 & 0x84) == 0x84
- && (apu->wave_ch.nr30 & 0x80) == 0x80) {
- struct channel_wave *wav = & apu->wave_ch;
- /* wave out */
- wav->output_phase += delta;
- if (wav->output_phase >= wav->output_trigger) {
- wav->counter += wav->output_phase / wav->output_trigger;
- wav->output_phase %= wav->output_trigger;
- }
- /* length count */
- wav->length_phase += delta;
- if (wav->length_phase > wav->length_trigger) {
- wav->length_count -= wav->length_phase/ wav->length_trigger;
- wav->length_phase %= wav->length_trigger;
- if (wav->length_count <= 0) {
- wav->length_count = 0;
- if (wav->nr33_34 & 0x4000)
- apu->settings.nr52 &= ~4;
- }
- }
- }
- }
- finline
- intptr_t lfsr15 (intptr_t seed) {
- /* step15 lfsr: 15, 14 (14,13)*/
- intptr_t d2 = (seed & 0x4000) >> 14;
- intptr_t d3 = (seed & 0x2000) >> 13;
- intptr_t out = 1 & (d2 ^ d3);
- seed <<= 1;
- seed |= out;
- seed &= 0x7FFF;
- return seed;
- }
- finline
- intptr_t lfsr7 (intptr_t seed) {
- /* step7 lfsr: 7, 6 (6,5)*/
- intptr_t d2 = (seed & 0x40) >> 6;
- intptr_t d3 = (seed & 0x20) >> 5;
- intptr_t out = 1 & (d2 ^ d3);
- seed <<= 1;
- seed |= out;
- seed &= 0x7F;
- return seed;
- }
- finline
- void noi_render (struct apu *apu, int32_t delta) {
- if ((apu->settings.nr52 & 0x88) == 0x88) {
- struct channel_noise *noi = & apu->noise_ch;
- /* noi signal */
- noi->signal_phase += delta;
- if (noi->signal_phase >= noi->signal_trigger) {
- int n_block = noi->signal_phase / noi->signal_trigger;
- noi->signal_phase %= noi->signal_trigger;
- while (n_block-- > 0)
- noi->signal_output = (noi->nr43_44 & 8)
- ? lfsr7 (noi->signal_output & 0x7F)
- : lfsr15 (noi->signal_output & 0x7FFF);
- }
- /* noise envlope */
- if ((noi->nr41_42 >> 8) & 7) {
- noi->envlope_phase += delta;
- if (noi->envlope_phase >= noi->envlope_trigger) {
- noi->envlope_phase %= noi->envlope_trigger;
- if (noi->nr41_42 & 0x800) {
- noi->signal_volume += noi->envlope_phase / noi->envlope_trigger;
- if (noi->signal_volume > 15)
- noi->signal_volume = 15;
- } else {
- noi->signal_volume -= noi->envlope_phase / noi->envlope_trigger;
- if (noi->signal_volume < 0) {
- #ifdef NR_NOI_TEST1
- apu->settings.nr52 &= ~(1 << (ch & 1));
- #endif
- noi->signal_volume = 0;
- }
- }
- }
- }
- /* length count */
- noi->length_phase += delta;
- if (noi->length_phase > noi->length_trigger) {
- noi->length_count -= noi->length_phase/ noi->length_trigger;
- noi->length_phase %= noi->length_trigger;
- if (noi->length_count <= 0) {
- noi->length_count = 0;
- if (noi->nr43_44 & 0x4000)
- apu->settings.nr52 &= ~8;
- }
- }
- }
- }
- finline
- void apu_clks (struct apu *apu, int32_t delta) {
- }
- finline
- uint16_t apu_read (struct apu *apu, uint32_t addr) {
- /* TODO: NR MASK */
- switch (addr & 0x3FF) {
- case 0x060: return apu->squ_ch[0].nrx0;
- case 0x062: return apu->squ_ch[0].nrx1_x2;
- case 0x064: return apu->squ_ch[0].nrx3_x4;
- case 0x068: return apu->squ_ch[1].nrx1_x2;
- case 0x06C: return apu->squ_ch[1].nrx3_x4;
- case 0x070: return apu->wave_ch.nr30;
- case 0x072: return apu->wave_ch.nr31_32;
- case 0x074: return apu->wave_ch.nr33_34;
- case 0x078: return apu->noise_ch.nr41_42;
- case 0x07C: return apu->noise_ch.nr43_44;
- case 0x080: return apu->settings.nr50_51;
- case 0x082: return apu->settings.snd_ctl;
- case 0x084: return apu->settings.nr52;
- case 0x088: return apu->settings.pwm_ctl;
- case 0x090: case 0x0092: case 0x094: case 0x096:
- case 0x098: case 0x009A: case 0x09C:
- case 0x09E: return apu->wave_ch.xram[((addr - 0x090 & 0x3FF) >> 1) + (apu->wave_ch.nr30 & 0x40) ? 0 : 8];
- default:
- DEBUG_BREAK ();
- }
- return 0;
- }
- finline
- void apu_write (struct apu *apu, uint32_t addr, uint16_t value) {
- switch (addr & 0x3FF) {
- case 0x060:
- apu->squ_ch[0].nrx0 = value;
- break;
- case 0x062:
- apu->settings.nr52 |= 1;
- apu->squ_ch[0].nrx1_x2 = value;
- apu->squ_ch[0].duty_vec = & apu->squ_ch[0].duty[value >> 6 & 3][0];
- apu->squ_ch[0].signal_volume = value >> 12;
- apu->squ_ch[0].length_count = 64 - (value & 63);
- apu->squ_ch[0].length_trigger = 16780000/256;
- apu->squ_ch[0].envlope_trigger = 16780000/64 * (apu->squ_ch[0].nrx1_x2 >> 8 & 7);;
- break;
- case 0x068:
- apu->settings.nr52 |= 2;
- apu->squ_ch[1].nrx1_x2 = value;
- apu->squ_ch[1].duty_vec = & apu->squ_ch[1].duty[value >> 6 & 3][0];
- apu->squ_ch[1].signal_volume = value >> 12;
- apu->squ_ch[1].length_count = 64 - (value & 63);
- apu->squ_ch[1].length_trigger = 16780000/256;
- apu->squ_ch[1].envlope_trigger = 16780000/64* (apu->squ_ch[1].nrx1_x2 >> 8 & 7);;
- break;
- case 0x064:
- if (value & 0x8000) {
- apu->settings.nr52 |= 1;
- /* Trigger Event
- * Writing a value to NRx4 with bit 7 set causes the following things to occur:
- *
- * Channel is enabled (see length counter).
- * If length counter is zero, it is set to 64
- * Frequency timer is reloaded with period.
- * Volume envelope timer is reloaded with period.
- * Channel volume is reloaded from NRx2.
- * Square 1's sweep does several things
- * Note that if the channel's DAC is off, after the above actions occur the channel will be immediately disabled again.
- /* During a trigger event, several things occur:
- Square 1's frequency is copied to the shadow register.
- The sweep timer is reloaded.
- The internal enabled flag is set if either the sweep period or shift are non-zero, cleared otherwise.
- If the sweep shift is non-zero, frequency calculation and the overflow check are performed immediately.
- TODO: Some features
- */
- if (!apu->squ_ch[0].length_count) {
- apu->squ_ch[0].length_count = 64;
- if (apu->squ_ch[0].nrx3_x4 & 0x4000) {
- apu->squ_ch[0].signal_phase = 0;
- apu->squ_ch[0].envlope_phase = 0;
- }
- }
- apu->squ_ch[0].nrx3_x4 = value;
- apu->squ_ch[0].signal_volume = apu->squ_ch[0].nrx1_x2 >> 12;
- apu->squ_ch[0].envlope_trigger = 16780000/64 * (apu->squ_ch[0].nrx1_x2 >> 8 & 7);
- apu->squ_ch[0].length_trigger = 16780000/256;
- apu->squ_ch[0].sweep_phase = 0;
- }
- apu->squ_ch[0].signal_trigger = (int) ( 2097500.0 / (131072.0 / (double)(2048 - (value & 2047))) );
- break;
- case 0x06C:
- if (value & 0x8000) {
- apu->settings.nr52 |= 2;
- /* Trigger Event Same as square 1 */
- if (!apu->squ_ch[1].length_count) {
- apu->squ_ch[1].length_count = 64;
- if (apu->squ_ch[1].nrx3_x4 & 0x4000) {
- apu->squ_ch[1].signal_phase = 0;
- apu->squ_ch[1].envlope_phase = 0;
- }
- }
- apu->squ_ch[1].nrx3_x4 = value;
- apu->squ_ch[1].signal_volume = apu->squ_ch[1].nrx1_x2 >> 12;
- apu->squ_ch[1].envlope_trigger = 16780000/64 * (apu->squ_ch[1].nrx1_x2 >> 8 & 7);
- apu->squ_ch[1].length_trigger = 16780000/256;
- apu->squ_ch[1].sweep_phase = 0;
- }
- apu->squ_ch[1].signal_trigger = (int) ( 2097500.0 / (131072.0 / (double)(2048 - (value & 2047))) );
- break;
- case 0x070:
- apu->wave_ch.nr30 = value;
- break;
- case 0x072:
- apu->wave_ch.length_count = 256 - (value & 255);
- apu->wave_ch.length_trigger = 16780000/256;
- apu->wave_ch.nr31_32 = value;
- break;
- case 0x074:
- if (value & 0x80) {
- apu->settings.nr52 |= 4;
- /* Trigger Event
- * Writing a value to NR34 with bit 7 set causes the following things to occur:
- *
- * Channel is enabled (see length counter).
- * If length counter is zero, it is set to 256.
- * Frequency timer is reloaded with period.
- * Wave channel's position is set to 0 but sample buffer is NOT refilled.
- * Note that if the channel's DAC is off, after the above actions occur the channel will be immediately disabled again.
- *
- * TODO: Some features
- */
- if (!apu->wave_ch.length_count) {
- apu->wave_ch.length_count = 256;
- if (apu->wave_ch.nr33_34 & 0x4000) {
- apu->wave_ch.output_phase = 0;
- }
- }
- apu->wave_ch.nr33_34 = value;
- apu->wave_ch.length_trigger = 16780000/256;
- }
- apu->wave_ch.output_trigger = (int)((16780000.0/ (131072.0 / (double)(2048 - (value & 2047)))) /
- ((apu->wave_ch.nr30 & 0x20) ? 64.0 : 32.0));
- break;
- case 0x078:
- apu->settings.nr52 |= 8;
- apu->noise_ch.nr41_42 = value;
- apu->noise_ch.signal_volume = value >> 12;
- apu->noise_ch.length_count = 64 - (value & 63);
- apu->noise_ch.length_trigger = 16780000/256;
- apu->noise_ch.envlope_trigger = 16780000/64 * (value >> 8 & 7);
- break;
- case 0x07C:
- if (value & 0x80) {
- apu->settings.nr52 |= 8;
- /* Trigger Event
- * Writing a value to NR44 with bit 7 set causes the following things to occur:
- *
- * Channel is enabled (see length counter).
- * If length counter is zero, it is set to 64
- * Frequency timer is reloaded with period.
- * Volume envelope timer is reloaded with period.
- * Channel volume is reloaded from NR42.
- * Noise channel's LFSR bits are all set to 1.
- * Note that if the channel's DAC is off, after the above actions occur the channel will be immediately disabled again.
- */
- if (!apu->noise_ch.length_count) {
- apu->noise_ch.length_count = 64;
- if (apu->noise_ch.nr43_44 & 0x4000) {
- apu->noise_ch.signal_phase = 0;
- apu->noise_ch.envlope_phase = 0;
- }
- }
- apu->noise_ch.nr43_44 = value;
- apu->noise_ch.signal_volume = value >> 12;
- apu->noise_ch.length_trigger = 16780000/256;
- apu->noise_ch.envlope_trigger = 16780000/64 * (value >> 8 & 7);
- apu->noise_ch.signal_output = -1;
- } else if ((value ^ apu->noise_ch.nr43_44) & 8) {
- apu->noise_ch.signal_output = -1;
- }
- apu->noise_ch.signal_trigger = (int)(16780000.0/ (524288.0 / (double)(1 << 1 + (value >> 4 & 15))
- / ((value & 7) ? (double) (value & 7) : 0.5 )));
- break;
- case 0x080:
- apu->settings.nr50_51 = value;
- break;
- case 0x082:
- if (value & 0x800) {
- /* Reset FIFO-A */
- apu->fifo_ch[0].count = 0;
- apu->fifo_ch[0].write = 0;
- apu->fifo_ch[0].read = 0;
- memset (apu->fifo_ch[0].buf, 0, sizeof (apu->fifo_ch[0].buf));
- }
- if (value & 0x8000) {
- /* Reset FIFO-B */
- apu->fifo_ch[1].count = 0;
- apu->fifo_ch[1].write = 0;
- apu->fifo_ch[1].read = 0;
- memset (apu->fifo_ch[1].buf, 0, sizeof (apu->fifo_ch[1].buf));
- }
- apu->settings.snd_ctl = value;
- break;
- case 0x084:
- apu->settings.nr52 = (apu->settings.nr52 & 15) | ~(value & 15);
- break;
- case 0x088:
- apu->settings.pwm_ctl = value; /* TODO: pwm control */
- break;
- case 0x090: case 0x0092:
- /* FIFO- A Write */
- apu->fifo_ch[0].buf[apu->fifo_ch[0].write++] = (int8_t) value;
- apu->fifo_ch[0].buf[apu->fifo_ch[0].write++] = (int8_t)(value >> 8);
- apu->fifo_ch[0].count += 2;
- break;
- case 0x094: case 0x096:
- /* FIFO- B Write */
- apu->fifo_ch[1].buf[apu->fifo_ch[1].write++] = (int8_t) value;
- apu->fifo_ch[1].buf[apu->fifo_ch[1].write++] = (int8_t)(value >> 8);
- apu->fifo_ch[1].count += 2;
- break;
- case 0x098: case 0x009A: case 0x09C: case 0x0A0: case 0x0A2: case 0xA4: case 0xA6:
- case 0x09E:
- if (apu->wave_ch.nr30 & 0x40) {
- apu->wave_ch.qram[(addr - 0x098) * 2+0] = value >> 4 & 15;
- apu->wave_ch.qram[(addr - 0x098) * 2+1] = value & 15;
- apu->wave_ch.qram[(addr - 0x098) * 2+2] = value >> 12 & 15;
- apu->wave_ch.qram[(addr - 0x098) * 2+3] = value >> 8 & 15;
- } else {
- apu->wave_ch.qram[(addr - 0x098) * 2+ 32+0] = value >> 4 & 15;
- apu->wave_ch.qram[(addr - 0x098) * 2+ 32+1] = value & 15;
- apu->wave_ch.qram[(addr - 0x098) * 2+ 32+2] = value >> 12 & 15;
- apu->wave_ch.qram[(addr - 0x098) * 2+ 32+3] = value >> 8 & 15;
- }
- apu->wave_ch.xram[((addr - 0x090 & 0x3FF) >> 1) + (apu->wave_ch.nr30 & 0x40) ? 0 : 8] = value;
- break;
- default:
- DEBUG_BREAK ();
- }
- }
- finline int16_t
- adds16 (int16_t u, int16_t v) {
- uint32_t out = (unsigned)u+(unsigned)v;
- if (out > INT16_MAX)
- out = INT16_MAX;
- return (int16_t)out;
- }
- finline
- void apu_mixer_s16 (struct apu *apu, void *volume2) {
- /* Synthesizer- Signed 16bit PCM
- * Square1 Square2 Wave Noise FIFO-2
- * Amplifier
- */
- if (!(apu->settings.nr52 & 0x80)) {
- ((int16_t *)volume2)[0] = 0;
- ((int16_t *)volume2)[1] = 1;
- } else {
- int16_t left = 0;
- int16_t right = 0;
- int16_t id;
- int16_t squ_out[2] = { 0, 0};
- int16_t wave_out = 0;
- int16_t noi_out = 0;
- int16_t fifo_out[2];
- /* GBC Sound 4bit -> 16bit
- FIFO Sound 8Bit -> 16Bit */
- /* Square channel - 1, 2*/
- for (id = 0; id!= 2; id++) {
- if (apu->settings.nr52 & (1 << id)) {
- struct channel_squ *squ = & apu->squ_ch[id];
- if (squ->signal_volume != 0)
- squ_out[id] = (int16_t) (squ->duty_vec[squ->duty_poll & 7] ? squ->signal_volume : 0);
- else ;
- }
- }
- /* Wave channel - 3*/
- if (apu->settings.nr52 & 4) {
- struct channel_wave *wave = & apu->wave_ch;
- /* TODO:*/
- }
- /* Noise channel - 4*/
- if (apu->settings.nr52 & 8) {
- struct channel_noise *noi = & apu->noise_ch;
- if (noi->signal_volume != 0)
- noi_out =(int16_t)( (noi->signal_output & 1) ? noi->signal_volume : 0);
- else ;
- }
- /* FIFO channel - 5, 6*/
- for (id = 0; id!= 2; id++) {
- int8_t value = apu->fifo_ch[id].buf[apu->fifo_ch[id].read];
- if (value < 0)
- value = -value;
- fifo_out[id] = value;
- }
- /*Mixer channel */
- if (1) {
- int16_t rcmix_mask = apu->settings.nr50_51 >> 8 & 15;
- int16_t lcmix_mask = apu->settings.nr50_51 >> 12 & 15;
- int16_t auxi_step = ((apu->settings.snd_ctl & 3) == 2) ? 4 : ((apu->settings.snd_ctl & 1) + 1);
- int16_t lc_step = (((apu->settings.nr50_51 >> 4 & 7) + 1) * 2184 >> 8) *auxi_step;
- int16_t rc_step = (((apu->settings.nr50_51 & 7) + 1) * 2184 >> 8) *auxi_step;
- /*Mixer right channel */
- if (rcmix_mask & 1)
- right = squ_out[0] * rc_step >> 4;
- if (rcmix_mask & 2)
- right = adds16 (right, squ_out[1] * rc_step >> 4);
- if (rcmix_mask & 4)
- right = adds16 (right, wave_out * rc_step >> 4);
- if (rcmix_mask & 8)
- right = adds16 (right, noi_out * rc_step >> 4);
- if (apu->settings.snd_ctl & 0x100)
- right = adds16 (right, fifo_out[0] << 8 >> (apu->settings.snd_ctl >> 2 & 1 ^ 1));
- if (apu->settings.snd_ctl & 0x1000)
- right = adds16 (right, fifo_out[1] << 8 >> (apu->settings.snd_ctl >> 3 & 1 ^ 1));
- /*Mixer left channel */
- if (lcmix_mask & 1)
- left = squ_out[0] * lc_step >> 4;
- if (lcmix_mask & 2)
- left = adds16 (left, squ_out[1] * lc_step >> 4);
- if (lcmix_mask & 4)
- left = adds16 (left, wave_out * lc_step >> 4);
- if (lcmix_mask & 8)
- left = adds16 (left, noi_out * lc_step >> 4);
- if (apu->settings.snd_ctl & 0x200)
- left = adds16 (left, fifo_out[0] << 8 >> (apu->settings.snd_ctl >> 2 & 1 ^ 1));
- if (apu->settings.snd_ctl & 0x2000)
- left = adds16 (left, fifo_out[1] << 8 >> (apu->settings.snd_ctl >> 3 & 1 ^ 1));
- }
- if (1) {
- static int16_t swi_dir = 0;
- if (swi_dir) {
- ((int16_t *)volume2)[0] = -left;
- ((int16_t *)volume2)[1] = -right;
- } else {
- ((int16_t *)volume2)[0] = left;
- ((int16_t *)volume2)[1] = right;
- }
- // swi_dir ^= 1;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement