vst works (but not really)
This commit is contained in:
parent
066a8690ba
commit
fbd3d51693
|
@ -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 std::sync::Arc;
|
||||
use ui::Emulator;
|
||||
use std::sync::{
|
||||
mpsc::{channel, Sender},
|
||||
Arc,
|
||||
};
|
||||
use ui::{Emulator, EmulatorRenderer};
|
||||
|
||||
mod ui;
|
||||
|
||||
|
@ -10,8 +19,18 @@ const HEIGHT: u32 = 240;
|
|||
#[derive(Params, Default)]
|
||||
struct EmuParams {}
|
||||
|
||||
struct EmuVars {
|
||||
rx: AsyncHeapConsumer<[f32; 2]>,
|
||||
sender: Sender<EmulatorMessage>,
|
||||
emulator_core: EmulatorCore,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct GameboyEmu {}
|
||||
pub struct GameboyEmu {
|
||||
vars: Option<EmuVars>,
|
||||
}
|
||||
|
||||
const ROM: &[u8; 32768] = include_bytes!("../../test-roms/Tetris.gb");
|
||||
|
||||
impl Plugin for GameboyEmu {
|
||||
const NAME: &'static str = "Gameboy";
|
||||
|
@ -47,11 +66,40 @@ impl Plugin for GameboyEmu {
|
|||
|
||||
fn process(
|
||||
&mut self,
|
||||
_buffer: &mut Buffer,
|
||||
buffer: &mut Buffer,
|
||||
_: &mut AuxiliaryBuffers,
|
||||
_: &mut impl ProcessContext<Self>,
|
||||
) -> 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>> {
|
||||
|
@ -61,11 +109,45 @@ impl Plugin for GameboyEmu {
|
|||
fn initialize(
|
||||
&mut self,
|
||||
_audio_io_layout: &AudioIOLayout,
|
||||
_buffer_config: &BufferConfig,
|
||||
buffer_config: &BufferConfig,
|
||||
_context: &mut impl InitContext<Self>,
|
||||
) -> 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
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -11,7 +11,7 @@ pub enum RomFile {
|
|||
Raw(Vec<u8>),
|
||||
}
|
||||
|
||||
pub trait Renderer {
|
||||
pub trait Renderer: Send + Sync {
|
||||
fn prepare(&mut self, width: usize, height: usize);
|
||||
|
||||
fn display(&mut self, buffer: &[u32]);
|
||||
|
@ -30,12 +30,23 @@ pub struct AudioOutput {
|
|||
|
||||
impl AudioOutput {
|
||||
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 = AsyncHeapRb::<[f32; 2]>::new(rb_len);
|
||||
let (mut send_rb, rx) = rb.split();
|
||||
|
||||
executor::block_on(send_rb.push_iter(vec![[0.; 2]; rb_len - 1].into_iter())).unwrap();
|
||||
let (send_rb, rx) = rb.split();
|
||||
|
||||
(
|
||||
Self {
|
||||
|
|
|
@ -154,6 +154,7 @@ impl EmulatorCore {
|
|||
}
|
||||
|
||||
pub fn run_until_buffer_full(&mut self) {
|
||||
println!("running until buffer full!!");
|
||||
while !self.cpu.memory.is_audio_buffer_full() {
|
||||
loop {
|
||||
self.run();
|
||||
|
|
|
@ -111,6 +111,7 @@ impl Apu {
|
|||
.map(|v| v.mixed(&self.mixer))
|
||||
.collect::<Vec<[f32; 2]>>(),
|
||||
);
|
||||
println!("pushing {} samples to queue", converted.len());
|
||||
executor::block_on(self.output.send_rb.push_slice(&converted)).unwrap();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ pub(super) const KB: usize = 1024;
|
|||
const ROM_BANK_SIZE: usize = 16 * KB;
|
||||
const RAM_BANK_SIZE: usize = 8 * KB;
|
||||
|
||||
pub(super) trait Mbc {
|
||||
pub(super) trait Mbc: Send + Sync {
|
||||
// addresses 0x0000 - 0x7FFF
|
||||
fn get(&self, address: Address) -> u8;
|
||||
// addresses 0xA000 - 0xBFFF
|
||||
|
|
Loading…
Reference in a new issue