vst works (but not really)

This commit is contained in:
Alex Janka 2023-03-07 08:51:23 +11:00
parent 066a8690ba
commit fbd3d51693
5 changed files with 106 additions and 11 deletions

View file

@ -1,6 +1,15 @@
use async_ringbuf::AsyncHeapConsumer;
use futures::executor;
use gb_emu_lib::{
connect::{AudioOutput, EmulatorMessage, RomFile},
EmulatorCore,
};
use nih_plug::prelude::*; use nih_plug::prelude::*;
use std::sync::Arc; use std::sync::{
use ui::Emulator; mpsc::{channel, Sender},
Arc,
};
use ui::{Emulator, EmulatorRenderer};
mod ui; mod ui;
@ -10,8 +19,18 @@ const HEIGHT: u32 = 240;
#[derive(Params, Default)] #[derive(Params, Default)]
struct EmuParams {} struct EmuParams {}
struct EmuVars {
rx: AsyncHeapConsumer<[f32; 2]>,
sender: Sender<EmulatorMessage>,
emulator_core: EmulatorCore,
}
#[derive(Default)] #[derive(Default)]
struct GameboyEmu {} pub struct GameboyEmu {
vars: Option<EmuVars>,
}
const ROM: &[u8; 32768] = include_bytes!("../../test-roms/Tetris.gb");
impl Plugin for GameboyEmu { impl Plugin for GameboyEmu {
const NAME: &'static str = "Gameboy"; const NAME: &'static str = "Gameboy";
@ -47,11 +66,40 @@ impl Plugin for GameboyEmu {
fn process( fn process(
&mut self, &mut self,
_buffer: &mut Buffer, buffer: &mut Buffer,
_: &mut AuxiliaryBuffers, _: &mut AuxiliaryBuffers,
_: &mut impl ProcessContext<Self>, _: &mut impl ProcessContext<Self>,
) -> ProcessStatus { ) -> ProcessStatus {
ProcessStatus::Normal nih_log!("processing");
if let Some(ref mut vars) = self.vars {
vars.emulator_core.run_until_buffer_full();
if buffer.channels() != 2 {
panic!()
}
let mut got_any = false;
let mut got_nonzero = false;
for sample in buffer.iter_samples() {
if let Some(a) = executor::block_on(vars.rx.pop()) {
got_any = true;
if (a[0] != 0.) || (a[1] != 0.) {
got_nonzero = true;
}
for (source, dest) in a.iter().zip(sample) {
*dest = *source;
}
}
}
if got_any {
if got_nonzero {
nih_log!("got some real data");
} else {
nih_log!("got some 0's");
}
}
} else {
nih_log!("vars not initialised");
}
ProcessStatus::KeepAlive
} }
fn editor(&self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> { fn editor(&self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
@ -61,11 +109,45 @@ impl Plugin for GameboyEmu {
fn initialize( fn initialize(
&mut self, &mut self,
_audio_io_layout: &AudioIOLayout, _audio_io_layout: &AudioIOLayout,
_buffer_config: &BufferConfig, buffer_config: &BufferConfig,
_context: &mut impl InitContext<Self>, _context: &mut impl InitContext<Self>,
) -> bool { ) -> bool {
let options = gb_emu_lib::Options {
rom: RomFile::Raw(ROM.to_vec()),
save_path: None,
no_save: true,
bootrom_path: None,
connect_serial: false,
verbose: true,
cycle_count: false,
};
let (sender, receiver) = channel::<EmulatorMessage>();
let (output, rx) = AudioOutput::new_unfilled(buffer_config.sample_rate);
let renderer = Box::<EmulatorRenderer>::default();
let mut emulator_core = EmulatorCore::init(receiver, options, renderer, output, None);
emulator_core.run_until_buffer_full();
self.vars = Some(EmuVars {
rx,
sender,
emulator_core,
});
true true
} }
fn deactivate(&mut self) {
nih_log!("deactivating");
if let Some(ref mut vars) = self.vars {
match vars.sender.send(EmulatorMessage::Stop) {
Ok(_) => self.vars = None,
Err(e) => nih_log!("error {e} sending message to emulator"),
}
}
}
} }
impl Vst3Plugin for GameboyEmu { impl Vst3Plugin for GameboyEmu {

View file

@ -11,7 +11,7 @@ pub enum RomFile {
Raw(Vec<u8>), Raw(Vec<u8>),
} }
pub trait Renderer { pub trait Renderer: Send + Sync {
fn prepare(&mut self, width: usize, height: usize); fn prepare(&mut self, width: usize, height: usize);
fn display(&mut self, buffer: &[u32]); fn display(&mut self, buffer: &[u32]);
@ -30,12 +30,23 @@ pub struct AudioOutput {
impl AudioOutput { impl AudioOutput {
pub fn new(sample_rate: f32) -> (Self, AsyncHeapConsumer<[f32; 2]>) { pub fn new(sample_rate: f32) -> (Self, AsyncHeapConsumer<[f32; 2]>) {
let (mut output, rx) = Self::new_unfilled(sample_rate);
executor::block_on(
output
.send_rb
.push_iter(vec![[0.; 2]; output.send_rb.len() - 1].into_iter()),
)
.unwrap();
(output, rx)
}
pub fn new_unfilled(sample_rate: f32) -> (Self, AsyncHeapConsumer<[f32; 2]>) {
let rb_len = sample_rate as usize / (60 * 2); let rb_len = sample_rate as usize / (60 * 2);
let rb = AsyncHeapRb::<[f32; 2]>::new(rb_len); let rb = AsyncHeapRb::<[f32; 2]>::new(rb_len);
let (mut send_rb, rx) = rb.split(); let (send_rb, rx) = rb.split();
executor::block_on(send_rb.push_iter(vec![[0.; 2]; rb_len - 1].into_iter())).unwrap();
( (
Self { Self {

View file

@ -154,6 +154,7 @@ impl EmulatorCore {
} }
pub fn run_until_buffer_full(&mut self) { pub fn run_until_buffer_full(&mut self) {
println!("running until buffer full!!");
while !self.cpu.memory.is_audio_buffer_full() { while !self.cpu.memory.is_audio_buffer_full() {
loop { loop {
self.run(); self.run();

View file

@ -111,6 +111,7 @@ impl Apu {
.map(|v| v.mixed(&self.mixer)) .map(|v| v.mixed(&self.mixer))
.collect::<Vec<[f32; 2]>>(), .collect::<Vec<[f32; 2]>>(),
); );
println!("pushing {} samples to queue", converted.len());
executor::block_on(self.output.send_rb.push_slice(&converted)).unwrap(); executor::block_on(self.output.send_rb.push_slice(&converted)).unwrap();
} }

View file

@ -15,7 +15,7 @@ pub(super) const KB: usize = 1024;
const ROM_BANK_SIZE: usize = 16 * KB; const ROM_BANK_SIZE: usize = 16 * KB;
const RAM_BANK_SIZE: usize = 8 * KB; const RAM_BANK_SIZE: usize = 8 * KB;
pub(super) trait Mbc { pub(super) trait Mbc: Send + Sync {
// addresses 0x0000 - 0x7FFF // addresses 0x0000 - 0x7FFF
fn get(&self, address: Address) -> u8; fn get(&self, address: Address) -> u8;
// addresses 0xA000 - 0xBFFF // addresses 0xA000 - 0xBFFF