gb-emu/gb-vst/src/lib.rs

161 lines
4.4 KiB
Rust
Raw Normal View History

2023-03-07 08:51:23 +11:00
use async_ringbuf::AsyncHeapConsumer;
use futures::executor;
use gb_emu_lib::{
connect::{AudioOutput, EmulatorMessage, RomFile},
EmulatorCore,
};
2023-03-05 20:18:06 +11:00
use nih_plug::prelude::*;
2023-03-07 08:51:23 +11:00
use std::sync::{
mpsc::{channel, Sender},
Arc,
};
use ui::{Emulator, EmulatorRenderer};
2023-03-04 09:15:25 +11:00
2023-03-05 20:18:06 +11:00
mod ui;
const WIDTH: u32 = 320;
const HEIGHT: u32 = 240;
#[derive(Params, Default)]
struct EmuParams {}
2023-03-04 09:15:25 +11:00
2023-03-07 08:51:23 +11:00
struct EmuVars {
rx: AsyncHeapConsumer<[f32; 2]>,
sender: Sender<EmulatorMessage>,
emulator_core: EmulatorCore,
}
2023-03-04 09:15:25 +11:00
#[derive(Default)]
2023-03-07 08:51:23 +11:00
pub struct GameboyEmu {
vars: Option<EmuVars>,
}
const ROM: &[u8; 32768] = include_bytes!("../../test-roms/Tetris.gb");
2023-03-04 09:15:25 +11:00
impl Plugin for GameboyEmu {
const NAME: &'static str = "Gameboy";
const VENDOR: &'static str = "Alex Janka";
const URL: &'static str = "alexjanka.com";
const EMAIL: &'static str = "alex@alexjanka.com";
const VERSION: &'static str = "0.1";
2023-03-05 20:18:06 +11:00
const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[AudioIOLayout {
main_input_channels: NonZeroU32::new(2),
main_output_channels: NonZeroU32::new(2),
aux_input_ports: &[],
aux_output_ports: &[],
// Individual ports and the layout as a whole can be named here. By default these names
// are generated as needed. This layout will be called 'Stereo', while the other one is
// given the name 'Mono' based no the number of input and output channels.
names: PortNames::const_default(),
}];
2023-03-04 09:15:25 +11:00
type SysExMessage = ();
type BackgroundTask = ();
fn params(&self) -> Arc<dyn Params> {
2023-03-05 20:18:06 +11:00
Arc::new(EmuParams::default())
2023-03-04 09:15:25 +11:00
}
fn process(
&mut self,
2023-03-07 08:51:23 +11:00
buffer: &mut Buffer,
2023-03-05 20:18:06 +11:00
_: &mut AuxiliaryBuffers,
_: &mut impl ProcessContext<Self>,
2023-03-04 09:15:25 +11:00
) -> ProcessStatus {
2023-03-07 08:51:23 +11:00
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
2023-03-04 09:15:25 +11:00
}
2023-03-05 20:18:06 +11:00
fn editor(&self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
Some(Box::new(Emulator::new()))
}
2023-03-04 09:15:25 +11:00
2023-03-05 20:18:06 +11:00
fn initialize(
&mut self,
_audio_io_layout: &AudioIOLayout,
2023-03-07 08:51:23 +11:00
buffer_config: &BufferConfig,
2023-03-05 20:18:06 +11:00
_context: &mut impl InitContext<Self>,
) -> bool {
2023-03-07 08:51:23 +11:00
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,
});
2023-03-05 20:18:06 +11:00
true
}
2023-03-07 08:51:23 +11:00
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"),
}
}
}
2023-03-04 09:15:25 +11:00
}
2023-03-05 20:18:06 +11:00
impl Vst3Plugin for GameboyEmu {
const VST3_CLASS_ID: [u8; 16] = *b"alexjankagbemula";
2023-03-04 09:15:25 +11:00
2023-03-05 20:18:06 +11:00
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Distortion, Vst3SubCategory::Dynamics];
2023-03-04 09:15:25 +11:00
}
nih_export_vst3!(GameboyEmu);