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 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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue