Compare commits

...

3 commits

Author SHA1 Message Date
Alex Janka e2bbd98f2d update nih-plug 2023-03-28 12:11:38 +11:00
Alex Janka 37fbdb0ed0 stink 2023-03-26 21:33:09 +11:00
Alex Janka 0636cb7dc3 lol 2023-03-25 19:06:28 +11:00
10 changed files with 96 additions and 37 deletions

View file

@ -3,4 +3,4 @@ xtask = "run --package xtask --release --"
[profile.dev]
opt-level = 3
lto = "thin"
lto = "off"

4
Cargo.lock generated
View file

@ -1607,9 +1607,9 @@ dependencies = [
[[package]]
name = "nih_log"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "016c1e345f1130730057d9b5381f423a36393b21c4f38f3ed05638448b6a5c48"
checksum = "f1d8a01d9663de15dbec9eaa9b7c261588e615ec204797b63039a2b0f30680fd"
dependencies = [
"atty",
"log",

View file

@ -115,6 +115,7 @@ impl Plugin for GameboyEmu {
context: &mut impl ProcessContext<Self>,
) -> ProcessStatus {
if let Some(ref mut vars) = self.vars {
nih_warn!("processing audio...");
while let Some(event) = context.next_event() {
if let Some(Basic(as_bytes)) = event.as_midi() {
match event {
@ -182,21 +183,31 @@ impl Plugin for GameboyEmu {
}
}
}
nih_warn!("...finished processing note events");
if buffer.channels() != 2 {
nih_warn!("literally just panicking because there number of channels != 2 and if this is the problem you are literally stupid");
panic!()
}
nih_warn!("...not stupid");
for sample in buffer.iter_samples() {
if vars.rx.is_empty() {
nih_warn!("...rx empty: running until buffer full");
vars.emulator_core.run_until_buffer_full();
nih_warn!("...buffer full");
}
if let Some(a) = executor::block_on(vars.rx.pop()) {
for (source, dest) in a.iter().zip(sample) {
*dest = *source;
}
} else {
nih_warn!("...could not rx audio from emulator")
}
}
nih_warn!("...running emulator until buffer is full again");
vars.emulator_core.run_until_buffer_full();
nih_warn!("...finished with processing audio");
} else {
nih_warn!("processing audio before emulator init");
while context.next_event().is_some() {}
}
self.update_save_state();
@ -204,6 +215,7 @@ impl Plugin for GameboyEmu {
}
fn editor(&self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
nih_warn!("creating first editor instance");
Some(Box::new(Emulator::new(
self.frame_receiver.clone(),
self.key_handler.clone(),
@ -216,6 +228,7 @@ impl Plugin for GameboyEmu {
buffer_config: &BufferConfig,
_context: &mut impl InitContext<Self>,
) -> bool {
nih_warn!("begin initialize");
if let Some(ref mut vars) = self.vars {
let (output, rx) = AudioOutput::new(
buffer_config.sample_rate,
@ -241,8 +254,11 @@ impl Plugin for GameboyEmu {
let (window, frame_receiver, key_handler) = EmulatorRenderer::new();
*self.frame_receiver.lock().unwrap() = Some(frame_receiver);
*self.key_handler.lock().unwrap() = Some(key_handler);
*self
.frame_receiver
.lock()
.expect("could not lock frame receiver") = Some(frame_receiver);
*self.key_handler.lock().expect("could not lock key handler") = Some(key_handler);
let (serial_tx, gb_serial_rx) = mpsc::channel::<u8>();
let serial_target = SerialTarget::Custom {
@ -250,6 +266,8 @@ impl Plugin for GameboyEmu {
tx: None,
};
nih_warn!("creating emulator core");
#[cfg(feature = "savestate")]
let mut emulator_core = if let Some(state) =
self.params.last_save_state.state.lock().unwrap().take()

View file

@ -23,6 +23,7 @@ pub struct Emulator {
impl Emulator {
pub fn new(frame_receiver: Arc<FrameReceiver>, joypad_sender: Arc<JoypadSender>) -> Self {
nih_warn!("new emulator rx/tx struct");
Self {
frame_receiver,
joypad_sender,
@ -40,6 +41,8 @@ impl Editor for Emulator {
parent: ParentWindowHandle,
_context: Arc<dyn GuiContext>,
) -> Box<dyn std::any::Any + Send> {
nih_warn!("spawning editor");
let fr_cloned = self.frame_receiver.clone();
let js_cloned = self.joypad_sender.clone();
@ -55,6 +58,7 @@ impl Editor for Emulator {
)
};
nih_warn!("opening window");
Window::open_parented(
&parent,
WindowOpenOptions {
@ -72,18 +76,26 @@ impl Editor for Emulator {
}
fn size(&self) -> (u32, u32) {
nih_warn!("editor size");
((WIDTH * EXTRA_SCALE) as u32, (HEIGHT * EXTRA_SCALE) as u32)
}
fn set_scale_factor(&self, _factor: f32) -> bool {
nih_warn!("editor scale factor");
true
}
fn param_value_changed(&self, _id: &str, _normalized_value: f32) {}
fn param_value_changed(&self, _id: &str, _normalized_value: f32) {
nih_warn!("editor param value changed");
}
fn param_modulation_changed(&self, _id: &str, _modulation_offset: f32) {}
fn param_modulation_changed(&self, _id: &str, _modulation_offset: f32) {
nih_warn!("editor param modulator changed");
}
fn param_values_changed(&self) {}
fn param_values_changed(&self) {
nih_warn!("editor param valueS changed");
}
}
pub struct EmulatorWindow {
@ -100,6 +112,7 @@ impl EmulatorWindow {
frame_receiver: Arc<FrameReceiver>,
joypad_sender: Arc<JoypadSender>,
) -> Self {
nih_warn!("creating emulatorwindow");
let info = WindowInfo::from_logical_size(
Size::new(WIDTH as f64, HEIGHT as f64),
EXTRA_SCALE as f64,
@ -118,6 +131,7 @@ impl EmulatorWindow {
}
fn init_pixbuf(info: WindowInfo, window: &mut Window) -> (Pixels, usize, Vec<[u8; 4]>) {
nih_warn!("initializing pixbuf");
let physical_size = info.physical_size();
let scale = (physical_size.width as usize / WIDTH).min(physical_size.height as usize / HEIGHT);
let scaled_buf = vec![[0, 0, 0, 0xFF]; WIDTH * scale * HEIGHT * scale];
@ -127,7 +141,7 @@ fn init_pixbuf(info: WindowInfo, window: &mut Window) -> (Pixels, usize, Vec<[u8
physical_size.height,
SurfaceTexture::new(physical_size.width, physical_size.height, window),
)
.unwrap(),
.expect("could not init pixbuf"),
scale,
scaled_buf,
)
@ -135,8 +149,11 @@ fn init_pixbuf(info: WindowInfo, window: &mut Window) -> (Pixels, usize, Vec<[u8
impl WindowHandler for EmulatorWindow {
fn on_frame(&mut self, _window: &mut Window) {
nih_warn!("rendering window frame");
if let Some(ref mut receiver) = *self.frame_receiver.lock().expect("failed to lock mutex") {
nih_warn!("...got frame receiver");
if let Some(ref buf) = receiver.try_iter().last() {
nih_warn!("...got frame");
if self.scale != 1 {
scale_buffer_in_place(buf, &mut self.scaled_buf, WIDTH, HEIGHT, self.scale);
}
@ -148,12 +165,15 @@ impl WindowHandler for EmulatorWindow {
{
pixel.copy_from_slice(source);
}
self.pix.render().unwrap();
self.pix
.render()
.expect("could not render pixbuf to window");
}
}
}
fn on_event(&mut self, window: &mut Window, event: baseview::Event) -> EventStatus {
nih_warn!("window event");
match event {
Event::Window(WindowEvent::Resized(info)) => {
(self.pix, self.scale, self.scaled_buf) = init_pixbuf(info, window);
@ -175,7 +195,9 @@ impl WindowHandler for EmulatorWindow {
if let Some(ref mut sender) =
*self.joypad_sender.lock().expect("failed to lock mutex")
{
sender.send((button, status)).unwrap();
sender
.send((button, status))
.expect("could not send button status");
}
EventStatus::Captured
} else {
@ -196,6 +218,7 @@ pub struct EmulatorRenderer {
impl EmulatorRenderer {
#[allow(clippy::type_complexity)]
pub(super) fn new() -> (Self, Receiver<Vec<[u8; 4]>>, Sender<(JoypadButtons, bool)>) {
nih_warn!("creating emulator renderer");
let (tx, rx) = mpsc::channel::<Vec<[u8; 4]>>();
let (keys_tx, keys) = mpsc::channel::<(JoypadButtons, bool)>();
(
@ -211,14 +234,19 @@ impl EmulatorRenderer {
}
impl Renderer<[u8; 4]> for EmulatorRenderer {
fn prepare(&mut self, _width: usize, _height: usize) {}
fn prepare(&mut self, _width: usize, _height: usize) {
nih_warn!("preparing emulator");
}
#[allow(unused_must_use)]
fn display(&mut self, buffer: &[[u8; 4]]) {
nih_warn!("sending frame from emulator thread");
self.tx.send(buffer.to_vec());
nih_warn!("...finished sending frame");
}
fn latest_joypad_state(&mut self) -> JoypadState {
nih_warn!("begin getting latest joypad state");
while let Ok((key, state)) = self.keys.try_recv() {
match key {
JoypadButtons::Down => self.joypad.down = state,
@ -231,6 +259,7 @@ impl Renderer<[u8; 4]> for EmulatorRenderer {
JoypadButtons::A => self.joypad.a = state,
}
}
nih_warn!("end getting latest joypad state");
self.joypad
}
}

View file

@ -147,21 +147,23 @@ where
}
pub fn run_until_buffer_full(&mut self) {
println!("hello from gameboy");
while !self.cpu.memory.is_audio_buffer_full() {
self.run();
}
println!("gooby from gameboy");
}
fn run_cycle(&mut self) {
let will_pause = unsafe { PAUSE_QUEUED };
let pause_enabled = unsafe { PAUSE_ENABLED };
// let will_pause = unsafe { PAUSE_QUEUED };
// let pause_enabled = unsafe { PAUSE_ENABLED };
self.cpu.exec_next();
if !pause_enabled && self.cpu.reg.pc >= 0x100 {
unsafe { PAUSE_ENABLED = true };
}
if will_pause {
pause_then_step();
}
// if !pause_enabled && self.cpu.reg.pc >= 0x100 {
// unsafe { PAUSE_ENABLED = true };
// }
// if will_pause {
// pause_then_step();
// }
}
fn process_messages(&mut self) {

View file

@ -331,7 +331,7 @@ where
pub fn increment_timers(&mut self, machine_cycles: u8) {
let steps = (machine_cycles as usize) * 4;
self.memory.camera.lock().unwrap().tick(steps);
// self.memory.camera.lock().unwrap().tick(steps);
let timer_return = self.memory.timers.tick(steps);
@ -359,12 +359,12 @@ where
.interrupts
.set_interrupt(Interrupt::LcdStat, gpu_interrupts.lcd_stat);
if gpu_interrupts.vblank {
let latest_state = self.memory.gpu.window.latest_joypad_state();
let joypad_interrupt = self.memory.update_pressed_keys(latest_state);
self.memory
.interrupts
.set_interrupt(Interrupt::Joypad, joypad_interrupt);
}
// if gpu_interrupts.vblank {
// let latest_state = self.memory.gpu.window.latest_joypad_state();
// let joypad_interrupt = self.memory.update_pressed_keys(latest_state);
// self.memory
// .interrupts
// .set_interrupt(Interrupt::Joypad, joypad_interrupt);
// }
}
}

View file

@ -147,8 +147,10 @@ impl Apu {
.collect(),
);
if self.buffer.len() >= CYCLES_PER_FRAME {
println!("finished 1 frame of audio... pushing...");
self.next_audio();
} else if !self.out_buffer.is_empty() {
println!("pushing remainder...");
self.push_audio();
}
}
@ -173,12 +175,17 @@ impl Apu {
self.out_buffer.len().min(self.output.send_rb.free_len())
};
executor::block_on(
self.output
.send_rb
.push_slice(&self.out_buffer.drain(..length).collect::<Vec<[f32; 2]>>()),
)
.unwrap();
if length > 0 {
executor::block_on(
self.output
.send_rb
.push_slice(&self.out_buffer.drain(..length).collect::<Vec<[f32; 2]>>()),
)
.expect("APU: error sending audio to output ringbuffer");
} else {
println!("buffer already full - skipped filling");
}
println!("finished pushing audio");
}
pub fn is_buffer_full(&self) -> bool {

View file

@ -455,6 +455,8 @@ where
}
fn render_window(&mut self) {
println!("gpu sending frame");
self.window.display(&self.buffer);
println!("gpu finished sending frame");
}
}

View file

@ -204,11 +204,12 @@ impl Serial {
match &self.target {
SerialTarget::Stdout => {
print!("{}", self.output_byte as char);
stdout().flush().unwrap();
stdout().flush().expect("Serial: error sending to stdout");
}
SerialTarget::Custom { rx: _, tx } => {
if let Some(tx) = tx {
tx.send(self.output_byte).unwrap();
tx.send(self.output_byte)
.expect("Serial: error sending to custom tx");
}
}
SerialTarget::None => {}

@ -1 +1 @@
Subproject commit 16f40eff4adb0a03a176d6e0fa7a4f794b484756
Subproject commit e6546c1aad139028253ddd4fb586f19463f5c881