/// <summary> /// Processes an incoming pulse value and adds it to the blipbuffer /// </summary> /// <param name="pulse"></param> public void ProcessPulseValue(bool pulse) { if (!_machine._renderSound) { return; } if (LastPulse == pulse) { // no change blip.AddDelta((uint)_machine.CurrentFrameCycle, 0); } else { if (pulse) { blip.AddDelta((uint)_machine.CurrentFrameCycle, (short)(_volume)); } else { blip.AddDelta((uint)_machine.CurrentFrameCycle, -(short)(_volume)); } lastVolume = _volume; } LastPulse = pulse; }
private void ProcessSound(int nsamp) { for (uint i = 0; i < nsamp; i++) { int curr = _soundbuff[i * 2]; if (curr != _latchL) { int diff = _latchL - curr; _latchL = curr; _blipL.AddDelta(_blipAccumulate, diff >> 2); } curr = _soundbuff[(i * 2) + 1]; if (curr != _latchR) { int diff = _latchR - curr; _latchR = curr; _blipR.AddDelta(_blipAccumulate, diff >> 2); } _blipAccumulate++; } }
/// <summary> /// Processes an incoming pulse value /// </summary> public void ProcessPulseValue(bool pulse, bool renderSound = true) { if (!renderSound) { return; } if (lastPulse == pulse) { // no change _blip.AddDelta((uint)clockCounter, 0); } else { if (pulse) { _blip.AddDelta((uint)clockCounter, (short)(_volume)); } else { _blip.AddDelta((uint)clockCounter, -(short)(_volume)); } lastVolume = _volume; } lastPulse = pulse; }
public void GetSamples(short[] samples) { //Console.WriteLine("Sync: {0}", nes.apu.dlist.Count); int nsamp = samples.Length / 2; if (nsamp > blipbuffsize) // oh well. { nsamp = blipbuffsize; } uint targetclock = (uint)blip.ClocksNeeded(nsamp); uint actualclock = nes.apu.sampleclock; foreach (var d in nes.apu.dlist) { blip.AddDelta(d.time * targetclock / actualclock, d.value); } nes.apu.dlist.Clear(); blip.EndFrame(targetclock); nes.apu.sampleclock = 0; blip.ReadSamples(samples, nsamp, true); // duplicate to stereo for (int i = 0; i < nsamp * 2; i += 2) { samples[i + 1] = samples[i]; } //mix in the cart's extra sound circuit nes.board.ApplyCustomAudio(samples); }
private void ProcessSound(int nsamp) { for (uint i = 0; i < nsamp; i++) { int curr = soundbuff[i * 2]; if (curr != latchL) { int diff = latchL - curr; latchL = curr; blipL.AddDelta(blipAccumulate, diff); } curr = soundbuff[i * 2 + 1]; if (curr != latchR) { int diff = latchR - curr; latchR = curr; blipR.AddDelta(blipAccumulate, diff); } blipAccumulate++; } }
public void tick() { // add up components to each channel int L_final = 0; int R_final = 0; if (AUD_CTRL_sq1_L_en) { L_final += 0; } if (AUD_CTRL_sq1_R_en) { R_final += 0; } L_final *= (AUD_CTRL_vol_L + 1) * 40; R_final *= (AUD_CTRL_vol_R + 1) * 40; if (L_final != latched_sample_L) { _blip_L.AddDelta(master_audio_clock, L_final - latched_sample_L); latched_sample_L = L_final; } if (R_final != latched_sample_R) { _blip_R.AddDelta(master_audio_clock, R_final - latched_sample_R); latched_sample_R = R_final; } master_audio_clock++; }
unsafe void PrepSound() { fixed(short *sl = LeftBuffer, sr = RightBuffer) { for (uint i = 0; i < SampPerFrame * 2; i += 2) { int s = (sl[i] + sl[i + 1]) / 2; if (s != LatchL) { blip_left.AddDelta(i, s - LatchL); LatchL = s; } s = (sr[i] + sr[i + 1]) / 2; if (s != LatchR) { blip_right.AddDelta(i, s - LatchR); LatchR = s; } } } blip_left.EndFrame(SampPerFrame * 2); blip_right.EndFrame(SampPerFrame * 2); int count = blip_left.SamplesAvailable(); if (count != blip_right.SamplesAvailable()) { throw new Exception("Sound problem?"); } // calling blip.Clear() causes rounding fractions to be reset, // and if only one channel is muted, in subsequent frames we can be off by a sample or two // not a big deal, but we didn't account for it. so we actually complete the entire // audio read and then stamp it out if muted. blip_left.ReadSamplesLeft(SampleBuffer, count); if (L.Muted) { fixed(short *p = SampleBuffer) { for (int i = 0; i < SampleBuffer.Length; i += 2) { p[i] = 0; } } } blip_right.ReadSamplesRight(SampleBuffer, count); if (R.Muted) { fixed(short *p = SampleBuffer) { for (int i = 1; i < SampleBuffer.Length; i += 2) { p[i] = 0; } } } SampleBufferContains = count; }
public void Audio_tick() { int C_final = 0; if (aud_ctrl.Bit(7)) { tick_cnt++; if (tick_cnt > (aud_ctrl.Bit(5) ? 455 : 1820)) { tick_cnt = 0; output_bit = shift_2 & 1; shift_2 = (byte)((shift_2 >> 1) | ((shift_1 & 1) << 7)); shift_1 = (byte)((shift_1 >> 1) | ((shift_0 & 1) << 7)); if (aud_ctrl.Bit(6)) { shift_0 = (byte)((shift_0 >> 1) | (output_bit << 7)); } else { shift_0 = (byte)(shift_0 >> 1); } if (aud_ctrl.Bit(4)) { if (shift_2.Bit(7) == output_bit.Bit(0)) { shift_2 &= 0x7F; } else { shift_2 = (byte)(shift_2 | 0x80); } } } C_final = output_bit; C_final *= ((aud_ctrl & 0xF) + 1) * 3200; } if (C_final != latched_sample_C) { _blip_C.AddDelta(master_audio_clock, C_final - latched_sample_C); latched_sample_C = C_final; } master_audio_clock++; }
public void GetSamplesSync(out short[] samples, out int nsamp) { uint f_clock = LibMSX.MSX_get_audio(MSX_Pntr, Aud, ref num_samp); for (int i = 0; i < num_samp; i++) { blip.AddDelta((uint)Aud[i * 2], Aud[i * 2 + 1]); } blip.EndFrame(f_clock); nsamp = blip.SamplesAvailable(); samples = new short[nsamp * 2]; blip.ReadSamples(samples, nsamp, true); }
private void ProcessSound() { var len = bridge.LibretroBridge_GetAudioSize(cbHandler); if (len == 0) // no audio? { return; } if (len > _inSampBuf.Length) { _inSampBuf = new short[len]; } var ns = 0; bridge.LibretroBridge_GetAudio(cbHandler, ref ns, _inSampBuf); for (uint i = 0; i < ns; i++) { int curr = _inSampBuf[i * 2]; if (curr != _latchL) { int diff = _latchL - curr; _latchL = curr; _blipL.AddDelta(i, diff); } curr = _inSampBuf[(i * 2) + 1]; if (curr != _latchR) { int diff = _latchR - curr; _latchR = curr; _blipR.AddDelta(i, diff); } } _blipL.EndFrame((uint)ns); _blipR.EndFrame((uint)ns); _outSamps = _blipL.SamplesAvailable(); _blipL.ReadSamplesLeft(_outSampBuf, _outSamps); _blipR.ReadSamplesRight(_outSampBuf, _outSamps); }
public void GetSamplesSync(out short[] samples, out int nsamp) { //Console.WriteLine("ASync: {0}", nes.apu.dlist.Count); foreach (var d in nes.apu.dlist) { blip.AddDelta(d.time, d.value); } nes.apu.dlist.Clear(); blip.EndFrame(nes.apu.sampleclock); nes.apu.sampleclock = 0; nsamp = blip.SamplesAvailable(); samples = new short[nsamp * 2]; blip.ReadSamples(samples, nsamp, true); // duplicate to stereo for (int i = 0; i < nsamp * 2; i += 2) { samples[i + 1] = samples[i]; } nes.Board.ApplyCustomAudio(samples); }
public void GetSamplesSync(out short[] samples, out int nsamp) { uint f_clock = LibMSX.MSX_get_audio(MSX_Pntr, Aud_L, Aud_R, ref num_samp_L, ref num_samp_R); for (int i = 0; i < num_samp_L; i++) { blip_L.AddDelta(Aud_L[i * 2], (int)Aud_L[i * 2 + 1]); } for (int i = 0; i < num_samp_R; i++) { blip_R.AddDelta(Aud_R[i * 2], (int)Aud_R[i * 2 + 1]); } blip_L.EndFrame(f_clock); blip_R.EndFrame(f_clock); nsamp = Math.Max(Math.Max(blip_L.SamplesAvailable(), blip_R.SamplesAvailable()), 1); samples = new short[nsamp * 2]; blip_L.ReadSamplesLeft(samples, nsamp); blip_R.ReadSamplesRight(samples, nsamp); }
private void AudioChange() { if (tone == 0) { // silence } else { int SamplesPerWave = (int)(SampleRate / tone_freqs[tone]); double RadPerSample = (Math.PI * 2) / (double)SamplesPerWave; double SinVal = 0; int NumSamples = (int)(((double)FrameClock - (double)lastCycle) / CyclesPerSample); int startPos = lastCycle; for (int i = 0; i < NumSamples; i++) { SinVal = Math.Sin(RadPerSample * (double)(i * SamplesPerWave)); _blip.AddDelta((uint)startPos, (int)(Math.Floor(SinVal * 127) + 128) * 1024); startPos += (int)CyclesPerSample; } } }
public byte DB; //old data bus values from previous reads internal void RunCpuOne() { /////////////////////////// // OAM DMA start /////////////////////////// if (oam_dma_exec && apu.dmc_dma_countdown != 1 && !dmc_realign) { if (cpu_deadcounter == 0) { if (oam_dma_index % 2 == 0) { oam_dma_byte = ReadMemory(oam_dma_addr); oam_dma_addr++; } else { WriteMemory(0x2004, oam_dma_byte); } oam_dma_index++; if (oam_dma_index == 512) { oam_dma_exec = false; } } else { cpu_deadcounter--; } } dmc_realign = false; ///////////////////////////// // OAM DMA end ///////////////////////////// ///////////////////////////// // dmc dma start ///////////////////////////// if (apu.dmc_dma_countdown > 0) { if (apu.dmc_dma_countdown == 1) { dmc_realign = true; } // By this point the cpu should be frozen, if it is not, then we are in a multi-write opcode, add another cycle delay if (!cpu.RDY && !cpu.rdy_freeze && (apu.dmc_dma_countdown == apu.DMC_RDY_check)) { //Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + apu.call_from_write + " " + cpu.opcode + " " + oam_dma_exec); apu.dmc_dma_countdown += 2; apu.DMC_RDY_check = -1; } cpu.RDY = false; dmc_dma_exec = true; apu.dmc_dma_countdown--; if (apu.dmc_dma_countdown == 0) { apu.RunDMCFetch(); dmc_dma_exec = false; apu.dmc_dma_countdown = -1; do_the_reread = true; } //Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + apu.call_from_write + " " + cpu.opcode); } ///////////////////////////// // dmc dma end ///////////////////////////// apu.RunOneFirst(); if (cpu.RDY && !IRQ_delay) { cpu.IRQ = _irq_apu || Board.IrqSignal; } else if (special_case_delay || apu.dmc_dma_countdown == 3) { cpu.IRQ = _irq_apu || Board.IrqSignal; special_case_delay = false; } cpu.ExecuteOne(); Board.ClockCpu(); int s = apu.EmitSample(); if (s != old_s) { blip.AddDelta(apu.sampleclock, s - old_s); old_s = s; } apu.sampleclock++; apu.RunOneLast(); if (do_the_reread && cpu.RDY) { do_the_reread = false; } IRQ_delay = false; if (!dmc_dma_exec && !oam_dma_exec && !cpu.RDY) { cpu.RDY = true; IRQ_delay = true; } }
public byte DB; //old data bus values from previous reads internal void RunCpuOne() { /////////////////////////// // OAM DMA start /////////////////////////// if (oam_dma_exec && apu.dmc_dma_countdown != 1 && !dmc_realign) { if (cpu_deadcounter == 0) { if (oam_dma_index % 2 == 0) { oam_dma_byte = ReadMemory(oam_dma_addr); oam_dma_addr++; } else { WriteMemory(0x2004, oam_dma_byte); } oam_dma_index++; if (oam_dma_index == 512) { oam_dma_exec = false; } } else { cpu_deadcounter--; } } dmc_realign = false; ///////////////////////////// // OAM DMA end ///////////////////////////// ///////////////////////////// // dmc dma start ///////////////////////////// if (apu.dmc_dma_countdown > 0) { if (apu.dmc_dma_countdown == 1 && !apu.dmc.fill_glitch) { dmc_realign = true; } // By this point the cpu should be frozen, if it is not, then we are in a multi-write opcode, add another cycle delay if (!cpu.RDY && !cpu.rdy_freeze && (apu.dmc_dma_countdown == apu.DMC_RDY_check)) { //Console.WriteLine("dmc double " + cpu.TotalExecutedCycles + " " + cpu.opcode + " " + cpu.mi); apu.dmc_dma_countdown += 2; apu.DMC_RDY_check = -1; } cpu.RDY = false; dmc_dma_exec = true; apu.dmc_dma_countdown--; if (apu.dmc_dma_countdown == 0) { if (!apu.dmc.fill_glitch) { reread_trigger = true; // if the DMA address has the same bits set as the re-read address, they don't occur if ((apu.dmc.sample_address & 0x2007) != 0x2002) { do_the_reread_2002++; } if ((apu.dmc.sample_address & 0x2007) != 0x2007) { do_the_reread_2007++; } if ((apu.dmc.sample_address & 0x401F) != 0x4016) { do_the_reread_cont_1++; } if ((apu.dmc.sample_address & 0x401F) != 0x4017) { do_the_reread_cont_2++; } apu.RunDMCFetch(); } dmc_dma_exec = false; apu.dmc_dma_countdown = -1; apu.dmc.fill_glitch = false; /* * //if (apu.dmc.timer == (apu.dmc.timer_reload-0) && apu.dmc.out_bits_remaining == 7) * //if (apu.dmc.timer == 2 && apu.dmc.out_bits_remaining == 0) * { * Console.WriteLine("close " + cpu.TotalExecutedCycles + " " + apu.dmc.timer + " " + apu.dmc.sample_length); * apu.dmc.fill_glitch = true; * apu.dmc.delay = 3; * } */ //Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + cpu.opcode + " " + cpu.mi + " " + apu.dmc.timer); } } ///////////////////////////// // dmc dma end ///////////////////////////// apu.RunOneFirst(); if (cpu.RDY && !IRQ_delay) { cpu.IRQ = _irq_apu || Board.IrqSignal; } else if (special_case_delay || apu.dmc_dma_countdown == 3) { cpu.IRQ = _irq_apu || Board.IrqSignal; //if (cpu.IRQ) { Console.WriteLine("something IRQ"); } special_case_delay = false; } cpu.ExecuteOne(); Board.ClockCpu(); int s = apu.EmitSample(); if (s != old_s) { blip.AddDelta(apu.sampleclock, s - old_s); old_s = s; } apu.sampleclock++; apu.RunOneLast(); if (reread_trigger && cpu.RDY) { do_the_reread_2002 = 0; do_the_reread_2007 = 0; do_the_reread_cont_1 = 0; do_the_reread_cont_2 = 0; reread_trigger = false; } IRQ_delay = false; if (!dmc_dma_exec && !oam_dma_exec && !cpu.RDY) { cpu.RDY = true; IRQ_delay = true; } }
public void tick() { // there are 8 cpu cycles for every psg cycle bool sound_out_A; bool sound_out_B; bool sound_out_C; psg_clock++; master_audio_clock++; if (psg_clock == 8) { psg_clock = 0; clock_A--; clock_B--; clock_C--; noise_clock--; env_clock--; // clock noise if (noise_clock == 0) { noise = (noise >> 1) ^ (noise.Bit(0) ? 0x10004 : 0); noise_clock = noise_per; } if (env_clock == 0) { env_clock = env_per; env_E += E_up_down; if (env_E == 16 || env_E == -1) { // we just completed a period of the envelope, determine what to do now based on the envelope shape if (env_shape == 0 || env_shape == 1 || env_shape == 3 || env_shape == 9) { E_up_down = 0; env_E = 0; } else if (env_shape == 5 || env_shape == 7) { E_up_down = 0; env_E = 15; } else if (env_shape == 4 || env_shape == 8) { if (env_E == 16) { env_E = 15; E_up_down = -1; } else { env_E = 0; E_up_down = 1; } } else if (env_shape == 2) { env_E = 15; } else { env_E = 0; } } } if (clock_A == 0) { A_up = !A_up; clock_A = sq_per_A; } if (clock_B == 0) { B_up = !B_up; clock_B = sq_per_B; } if (clock_C == 0) { C_up = !C_up; clock_C = sq_per_C; } sound_out_A = (noise.Bit(0) | A_noise) & (A_on | A_up); sound_out_B = (noise.Bit(0) | B_noise) & (B_on | B_up); sound_out_C = (noise.Bit(0) | C_noise) & (C_on | C_up); // now calculate the volume of each channel and add them together int v; if (env_vol_A == 0) { v = (short)(sound_out_A ? VolumeTable[vol_A] : 0); } else { v = (short)(sound_out_A ? VolumeTable[vol_A] : 0); } if (env_vol_B == 0) { v += (short)(sound_out_B ? VolumeTable[vol_B] : 0); } else { v += (short)(sound_out_B ? VolumeTable[env_E] : 0); } if (env_vol_C == 0) { v += (short)(sound_out_C ? VolumeTable[vol_C] : 0); } else { v += (short)(sound_out_C ? VolumeTable[env_E] : 0); } current_sample = (short)v; if (current_sample != old_sample) { _blip.AddDelta(master_audio_clock, current_sample - old_sample); old_sample = current_sample; } } }
public void generate_sound(int cycles_to_do) { // there are 4 cpu cycles for every psg cycle bool sound_out_A; bool sound_out_B; bool sound_out_C; for (int i = 0; i < cycles_to_do; i++) { psg_clock++; if (psg_clock == 4) { psg_clock = 0; total_clock++; clock_A--; clock_B--; clock_C--; noise_clock--; env_clock--; // clock noise if (noise_clock == 0) { noise = (noise >> 1) ^ (noise.Bit(0) ? 0x10004 : 0); noise_clock = noise_per; } if (env_clock == 0) { env_clock = env_per; env_E += E_up_down; if (env_E == 16 || env_E == -1) { // we just completed a period of the envelope, determine what to do now based on the envelope shape if (env_shape == 0 || env_shape == 1 || env_shape == 3 || env_shape == 9) { E_up_down = 0; env_E = 0; } else if (env_shape == 5 || env_shape == 7) { E_up_down = 0; env_E = 15; } else if (env_shape == 4 || env_shape == 8) { if (env_E == 16) { env_E = 15; E_up_down = -1; } else { env_E = 0; E_up_down = 1; } } else if (env_shape == 2) { env_E = 15; } else { env_E = 0; } } } if (clock_A == 0) { A_up = !A_up; clock_A = sq_per_A; } if (clock_B == 0) { B_up = !B_up; clock_B = sq_per_B; } if (clock_C == 0) { C_up = !C_up; clock_C = sq_per_C; } sound_out_A = (noise.Bit(0) | A_noise) & (A_on | A_up); sound_out_B = (noise.Bit(0) | B_noise) & (B_on | B_up); sound_out_C = (noise.Bit(0) | C_noise) & (C_on | C_up); // now calculate the volume of each channel and add them together int v; if (env_vol_A == 0) { v = (short)(sound_out_A ? VolumeTable[vol_A] : 0); } else { int shift_A = 3 - env_vol_A; if (shift_A < 0) { shift_A = 0; } v = (short)(sound_out_A ? (VolumeTable[env_E] >> shift_A) : 0); } if (env_vol_B == 0) { v += (short)(sound_out_B ? VolumeTable[vol_B] : 0); } else { int shift_B = 3 - env_vol_B; if (shift_B < 0) { shift_B = 0; } v += (short)(sound_out_B ? (VolumeTable[env_E] >> shift_B) : 0); } if (env_vol_C == 0) { v += (short)(sound_out_C ? VolumeTable[vol_C] : 0); } else { int shift_C = 3 - env_vol_C; if (shift_C < 0) { shift_C = 0; } v += (short)(sound_out_C ? (VolumeTable[env_E] >> shift_C) : 0); } if (v != _latchedSample) { _blip.AddDelta((uint)_sampleClock, v - _latchedSample); _latchedSample = v; } _sampleClock++; } } }
public byte DB; //old data bus values from previous reads internal void RunCpuOne() { /////////////////////////// // OAM DMA start /////////////////////////// if (sprdma_countdown > 0) { sprdma_countdown--; if (sprdma_countdown == 0) { if (cpu.TotalExecutedCycles % 2 == 0) { cpu_deadcounter = 2; } else { cpu_deadcounter = 1; } oam_dma_exec = true; cpu.RDY = false; oam_dma_index = 0; special_case_delay = true; } } if (oam_dma_exec && apu.dmc_dma_countdown != 1 && !dmc_realign) { if (cpu_deadcounter == 0) { if (oam_dma_index % 2 == 0) { oam_dma_byte = ReadMemory(oam_dma_addr); oam_dma_addr++; } else { WriteMemory(0x2004, oam_dma_byte); } oam_dma_index++; if (oam_dma_index == 512) { oam_dma_exec = false; } } else { cpu_deadcounter--; } } else if (apu.dmc_dma_countdown == 1) { dmc_realign = true; } else if (dmc_realign) { dmc_realign = false; } ///////////////////////////// // OAM DMA end ///////////////////////////// ///////////////////////////// // dmc dma start ///////////////////////////// if (apu.dmc_dma_countdown > 0) { cpu.RDY = false; dmc_dma_exec = true; apu.dmc_dma_countdown--; if (apu.dmc_dma_countdown == 0) { apu.RunDMCFetch(); dmc_dma_exec = false; apu.dmc_dma_countdown = -1; do_the_reread = true; } } ///////////////////////////// // dmc dma end ///////////////////////////// apu.RunOneFirst(); if (cpu.RDY && !IRQ_delay) { cpu.IRQ = _irq_apu || Board.IRQSignal; } else if (special_case_delay || apu.dmc_dma_countdown == 3) { cpu.IRQ = _irq_apu || Board.IRQSignal; special_case_delay = false; } cpu.ExecuteOne(); Board.ClockCPU(); int s = apu.EmitSample(); if (s != old_s) { blip.AddDelta(apu.sampleclock, s - old_s); old_s = s; } apu.sampleclock++; apu.RunOneLast(); if (ppu.double_2007_read > 0) { ppu.double_2007_read--; } if (do_the_reread && cpu.RDY) { do_the_reread = false; } if (IRQ_delay) { IRQ_delay = false; } if (!dmc_dma_exec && !oam_dma_exec && !cpu.RDY) { cpu.RDY = true; IRQ_delay = true; } }