Compare commits
3 commits
main
...
stinky-deb
Author | SHA1 | Date | |
---|---|---|---|
Alex Janka | e2bbd98f2d | ||
Alex Janka | 37fbdb0ed0 | ||
Alex Janka | 0636cb7dc3 |
|
@ -3,4 +3,4 @@ xtask = "run --package xtask --release --"
|
|||
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
lto = "thin"
|
||||
lto = "off"
|
||||
|
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -455,6 +455,8 @@ where
|
|||
}
|
||||
|
||||
fn render_window(&mut self) {
|
||||
println!("gpu sending frame");
|
||||
self.window.display(&self.buffer);
|
||||
println!("gpu finished sending frame");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue