mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-26 00:56:38 +11:00
Remove setup_interrupt_handler and after_vblank in the mixer
This commit is contained in:
parent
cc8824fc21
commit
b74c5e39c0
1 changed files with 31 additions and 64 deletions
|
@ -1,4 +1,5 @@
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
use core::pin::Pin;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
@ -79,7 +80,11 @@ extern "C" {
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Mixer {
|
pub struct Mixer {
|
||||||
buffer: MixerBuffer,
|
interrupt_timer: Timer,
|
||||||
|
// SAFETY: Has to go before buffer because it holds a reference to it
|
||||||
|
_interrupt_handler: InterruptHandler<'static>,
|
||||||
|
|
||||||
|
buffer: Pin<Box<MixerBuffer>>,
|
||||||
channels: [Option<SoundChannel>; 8],
|
channels: [Option<SoundChannel>; 8],
|
||||||
indices: [i32; 8],
|
indices: [i32; 8],
|
||||||
frequency: Frequency,
|
frequency: Frequency,
|
||||||
|
@ -112,12 +117,35 @@ pub struct ChannelId(usize, i32);
|
||||||
|
|
||||||
impl Mixer {
|
impl Mixer {
|
||||||
pub(super) fn new(frequency: Frequency) -> Self {
|
pub(super) fn new(frequency: Frequency) -> Self {
|
||||||
|
let buffer = Box::pin(MixerBuffer::new(frequency));
|
||||||
|
|
||||||
|
// SAFETY: you can only ever have 1 Mixer at a time
|
||||||
|
let mut interrupt_timer = unsafe { Timer::new(1) };
|
||||||
|
interrupt_timer
|
||||||
|
.set_cascade(true)
|
||||||
|
.set_divider(Divider::Divider1)
|
||||||
|
.set_interrupt(true)
|
||||||
|
.set_overflow_amount(frequency.buffer_size() as u16);
|
||||||
|
|
||||||
|
let buffer_pointer_for_interrupt_handler: &MixerBuffer = &buffer;
|
||||||
|
|
||||||
|
// SAFETY: dropping the lifetime, sound because interrupt handler dropped before the buffer is
|
||||||
|
// In the case of the mixer being forgotten, both stay alive so okay
|
||||||
|
let buffer_pointer_for_interrupt_handler: &MixerBuffer =
|
||||||
|
unsafe { core::mem::transmute(buffer_pointer_for_interrupt_handler) };
|
||||||
|
let interrupt_handler = add_interrupt_handler(interrupt_timer.interrupt(), |cs| {
|
||||||
|
buffer_pointer_for_interrupt_handler.swap(cs);
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
frequency,
|
frequency,
|
||||||
buffer: MixerBuffer::new(frequency),
|
buffer,
|
||||||
channels: Default::default(),
|
channels: Default::default(),
|
||||||
indices: Default::default(),
|
indices: Default::default(),
|
||||||
|
|
||||||
|
interrupt_timer,
|
||||||
|
_interrupt_handler: interrupt_handler,
|
||||||
|
|
||||||
timer: unsafe { Timer::new(0) },
|
timer: unsafe { Timer::new(0) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,69 +157,8 @@ impl Mixer {
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
hw::set_timer_counter_for_frequency_and_enable(&mut self.timer, self.frequency.frequency());
|
hw::set_timer_counter_for_frequency_and_enable(&mut self.timer, self.frequency.frequency());
|
||||||
hw::set_sound_control_register_for_mixer();
|
hw::set_sound_control_register_for_mixer();
|
||||||
}
|
|
||||||
|
|
||||||
/// Do post-vblank work. You can use either this or [`setup_interrupt_handler()`](Mixer::setup_interrupt_handler),
|
self.interrupt_timer.set_enabled(true);
|
||||||
/// but not both. Note that this is not available if using 32768Hz sounds since those require more irregular timings.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust,no_run
|
|
||||||
/// # #![no_std]
|
|
||||||
/// # #![no_main]
|
|
||||||
/// # use agb::sound::mixer::*;
|
|
||||||
/// # use agb::*;
|
|
||||||
/// # fn foo(gba: &mut Gba) {
|
|
||||||
/// # let mut mixer = gba.mixer.mixer(agb::sound::mixer::Frequency::Hz10512);
|
|
||||||
/// # let vblank = agb::interrupt::VBlank::get();
|
|
||||||
/// loop {
|
|
||||||
/// mixer.frame();
|
|
||||||
/// vblank.wait_for_vblank();
|
|
||||||
/// mixer.after_vblank();
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(not(feature = "freq32768"))]
|
|
||||||
pub fn after_vblank(&mut self) {
|
|
||||||
free(|cs| self.buffer.swap(cs));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Use timer interrupts to do the timing required for ensuring the music runs smoothly.
|
|
||||||
///
|
|
||||||
/// Note that if you set up an interrupt handler, you should not call [`after_vblank`](Mixer::after_vblank) any more
|
|
||||||
/// You are still required to call [`frame`](Mixer::frame).
|
|
||||||
///
|
|
||||||
/// This is required if using 32768Hz music, but optional for other frequencies.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust,no_run
|
|
||||||
/// # #![no_std]
|
|
||||||
/// # #![no_main]
|
|
||||||
/// # use agb::sound::mixer::*;
|
|
||||||
/// # use agb::*;
|
|
||||||
/// # fn foo(gba: &mut Gba) {
|
|
||||||
/// # let mut mixer = gba.mixer.mixer(agb::sound::mixer::Frequency::Hz10512);
|
|
||||||
/// # let vblank = agb::interrupt::VBlank::get();
|
|
||||||
/// // you must set this to a named variable to ensure that the scope is long enough
|
|
||||||
/// let _mixer_interrupt = mixer.setup_interrupt_handler();
|
|
||||||
///
|
|
||||||
/// loop {
|
|
||||||
/// mixer.frame();
|
|
||||||
/// vblank.wait_for_vblank();
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn setup_interrupt_handler(&self) -> InterruptHandler<'_> {
|
|
||||||
let mut timer1 = unsafe { Timer::new(1) };
|
|
||||||
timer1
|
|
||||||
.set_cascade(true)
|
|
||||||
.set_divider(Divider::Divider1)
|
|
||||||
.set_interrupt(true)
|
|
||||||
.set_overflow_amount(self.frequency.buffer_size() as u16)
|
|
||||||
.set_enabled(true);
|
|
||||||
|
|
||||||
add_interrupt_handler(timer1.interrupt(), move |cs| self.buffer.swap(cs))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Do the CPU intensive mixing for the next frame's worth of data.
|
/// Do the CPU intensive mixing for the next frame's worth of data.
|
||||||
|
|
Loading…
Add table
Reference in a new issue