mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
commit
241e8b369e
|
@ -4,7 +4,7 @@
|
||||||
use agb::fixnum::Num;
|
use agb::fixnum::Num;
|
||||||
use agb::input::{Button, ButtonController, Tri};
|
use agb::input::{Button, ButtonController, Tri};
|
||||||
use agb::sound::mixer::SoundChannel;
|
use agb::sound::mixer::SoundChannel;
|
||||||
use agb::{include_wav, Gba, fixnum::num};
|
use agb::{fixnum::num, include_wav, Gba};
|
||||||
|
|
||||||
// Music - "Dead Code" by Josh Woodward, free download at http://joshwoodward.com
|
// Music - "Dead Code" by Josh Woodward, free download at http://joshwoodward.com
|
||||||
const DEAD_CODE: &[u8] = include_wav!("examples/JoshWoodward-DeadCode.wav");
|
const DEAD_CODE: &[u8] = include_wav!("examples/JoshWoodward-DeadCode.wav");
|
||||||
|
|
BIN
agb/examples/sfx/jump.wav
Normal file
BIN
agb/examples/sfx/jump.wav
Normal file
Binary file not shown.
BIN
agb/examples/sfx/my_bgm.wav
Normal file
BIN
agb/examples/sfx/my_bgm.wav
Normal file
Binary file not shown.
|
@ -20,9 +20,38 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,no_run
|
||||||
/// let backdrop = InfiniteScrolledMap::new(
|
/// # #![no_std]
|
||||||
/// background.background(Priority::P2, RegularBackgroundSize::Background32x32),
|
/// # #![no_main]
|
||||||
|
/// extern crate alloc;
|
||||||
|
///
|
||||||
|
/// use alloc::boxed::Box;
|
||||||
|
///
|
||||||
|
/// use agb::display::tiled::{
|
||||||
|
/// InfiniteScrolledMap,
|
||||||
|
/// TileSetting,
|
||||||
|
/// RegularBackgroundSize,
|
||||||
|
/// TileSet,
|
||||||
|
/// TileFormat,
|
||||||
|
/// };
|
||||||
|
/// use agb::display::Priority;
|
||||||
|
///
|
||||||
|
/// mod tilemap {
|
||||||
|
/// pub const BACKGROUND_MAP: &[u16] = &[ // Probably load this from a file
|
||||||
|
/// # 0, 1, 2];
|
||||||
|
/// pub const WIDTH: i32 = // set it to some width
|
||||||
|
/// # 12;
|
||||||
|
/// pub const MAP_TILES: &[u8] = &[ // probably load this from a file
|
||||||
|
/// # 0];
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # fn foo(mut gba: agb::Gba) {
|
||||||
|
/// let (gfx, mut vram) = gba.display.video.tiled0();
|
||||||
|
///
|
||||||
|
/// let tileset = TileSet::new(&tilemap::MAP_TILES, TileFormat::FourBpp);
|
||||||
|
///
|
||||||
|
/// let mut backdrop = InfiniteScrolledMap::new(
|
||||||
|
/// gfx.background(Priority::P2, RegularBackgroundSize::Background32x32),
|
||||||
/// Box::new(|pos| {
|
/// Box::new(|pos| {
|
||||||
/// (
|
/// (
|
||||||
/// &tileset,
|
/// &tileset,
|
||||||
|
@ -40,6 +69,7 @@ use crate::{
|
||||||
/// backdrop.set_pos(&mut vram, (3, 5).into());
|
/// backdrop.set_pos(&mut vram, (3, 5).into());
|
||||||
/// backdrop.commit(&mut vram);
|
/// backdrop.commit(&mut vram);
|
||||||
/// backdrop.show();
|
/// backdrop.show();
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct InfiniteScrolledMap<'a> {
|
pub struct InfiniteScrolledMap<'a> {
|
||||||
map: MapLoan<'a, RegularMap>,
|
map: MapLoan<'a, RegularMap>,
|
||||||
|
@ -83,11 +113,57 @@ impl<'a> InfiniteScrolledMap<'a> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,no_run
|
||||||
/// background.init(&mut vram, start_position, || {
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # extern crate alloc;
|
||||||
|
/// #
|
||||||
|
/// # use alloc::boxed::Box;
|
||||||
|
/// #
|
||||||
|
/// # use agb::display::tiled::{
|
||||||
|
/// # InfiniteScrolledMap,
|
||||||
|
/// # TileSetting,
|
||||||
|
/// # RegularBackgroundSize,
|
||||||
|
/// # TileSet,
|
||||||
|
/// # TileFormat,
|
||||||
|
/// # };
|
||||||
|
/// # use agb::display::Priority;
|
||||||
|
/// #
|
||||||
|
/// # mod tilemap {
|
||||||
|
/// # pub const BACKGROUND_MAP: &[u16] = &[0, 1, 2];
|
||||||
|
/// # pub const WIDTH: i32 = 12;
|
||||||
|
/// # pub const MAP_TILES: &[u8] = &[0];
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # fn foo(mut gba: agb::Gba) {
|
||||||
|
/// # let (gfx, mut vram) = gba.display.video.tiled0();
|
||||||
|
/// #
|
||||||
|
/// # let tileset = TileSet::new(&tilemap::MAP_TILES, TileFormat::FourBpp);
|
||||||
|
/// #
|
||||||
|
/// # let mut backdrop = InfiniteScrolledMap::new(
|
||||||
|
/// # gfx.background(Priority::P2, RegularBackgroundSize::Background32x32),
|
||||||
|
/// # Box::new(|pos| {
|
||||||
|
/// # (
|
||||||
|
/// # &tileset,
|
||||||
|
/// # TileSetting::from_raw(
|
||||||
|
/// # *tilemap::BACKGROUND_MAP
|
||||||
|
/// # .get((pos.x + tilemap::WIDTH * pos.y) as usize)
|
||||||
|
/// # .unwrap_or(&0),
|
||||||
|
/// # ),
|
||||||
|
/// # )
|
||||||
|
/// # }),
|
||||||
|
/// # );
|
||||||
|
/// #
|
||||||
|
/// # let vblank = agb::interrupt::VBlank::get();
|
||||||
|
/// # let mut mixer = gba.mixer.mixer();
|
||||||
|
/// let start_position = agb::fixnum::Vector2D::new(10, 10);
|
||||||
|
/// backdrop.init(&mut vram, start_position, &mut || {
|
||||||
/// vblank.wait_for_vblank();
|
/// vblank.wait_for_vblank();
|
||||||
/// mixer.frame();
|
/// mixer.frame();
|
||||||
/// });
|
/// });
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn init(
|
pub fn init(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -111,11 +187,58 @@ impl<'a> InfiniteScrolledMap<'a> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,no_run
|
||||||
/// while background.init_partial(&mut vram, start_position) == PartialUpdateStatus::Continue {
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # extern crate alloc;
|
||||||
|
/// #
|
||||||
|
/// # use alloc::boxed::Box;
|
||||||
|
/// #
|
||||||
|
/// # use agb::display::tiled::{
|
||||||
|
/// # InfiniteScrolledMap,
|
||||||
|
/// # TileSetting,
|
||||||
|
/// # RegularBackgroundSize,
|
||||||
|
/// # TileSet,
|
||||||
|
/// # TileFormat,
|
||||||
|
/// # PartialUpdateStatus,
|
||||||
|
/// # };
|
||||||
|
/// # use agb::display::Priority;
|
||||||
|
/// #
|
||||||
|
/// # mod tilemap {
|
||||||
|
/// # pub const BACKGROUND_MAP: &[u16] = &[0, 1, 2];
|
||||||
|
/// # pub const WIDTH: i32 = 12;
|
||||||
|
/// # pub const MAP_TILES: &[u8] = &[0];
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # fn foo(mut gba: agb::Gba) {
|
||||||
|
/// # let (gfx, mut vram) = gba.display.video.tiled0();
|
||||||
|
/// #
|
||||||
|
/// # let tileset = TileSet::new(&tilemap::MAP_TILES, TileFormat::FourBpp);
|
||||||
|
/// #
|
||||||
|
/// # let mut backdrop = InfiniteScrolledMap::new(
|
||||||
|
/// # gfx.background(Priority::P2, RegularBackgroundSize::Background32x32),
|
||||||
|
/// # Box::new(|pos| {
|
||||||
|
/// # (
|
||||||
|
/// # &tileset,
|
||||||
|
/// # TileSetting::from_raw(
|
||||||
|
/// # *tilemap::BACKGROUND_MAP
|
||||||
|
/// # .get((pos.x + tilemap::WIDTH * pos.y) as usize)
|
||||||
|
/// # .unwrap_or(&0),
|
||||||
|
/// # ),
|
||||||
|
/// # )
|
||||||
|
/// # }),
|
||||||
|
/// # );
|
||||||
|
/// #
|
||||||
|
/// # let vblank = agb::interrupt::VBlank::get();
|
||||||
|
/// # let mut mixer = gba.mixer.mixer();
|
||||||
|
/// let start_position = agb::fixnum::Vector2D::new(10, 10);
|
||||||
|
/// while backdrop.init_partial(&mut vram, start_position) == PartialUpdateStatus::Continue {
|
||||||
/// vblank.wait_for_vblank();
|
/// vblank.wait_for_vblank();
|
||||||
/// mixer.frame();
|
/// mixer.frame();
|
||||||
/// }
|
/// }
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn init_partial(
|
pub fn init_partial(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -235,10 +235,17 @@ fn interrupt_to_root(interrupt: Interrupt) -> &'static InterruptRoot {
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,no_run
|
||||||
/// let _a = add_interrupt_handler(Interrupt::VBlank, |_: &CriticalSection| {
|
/// # #![no_std]
|
||||||
/// println!("Woah there! There's been a vblank!");
|
/// # #![no_main]
|
||||||
|
/// use bare_metal::CriticalSection;
|
||||||
|
///
|
||||||
|
/// # fn foo() {
|
||||||
|
/// # use agb::interrupt::{add_interrupt_handler, Interrupt};
|
||||||
|
/// let _a = add_interrupt_handler(Interrupt::VBlank, |_: CriticalSection| {
|
||||||
|
/// agb::println!("Woah there! There's been a vblank!");
|
||||||
/// });
|
/// });
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_interrupt_handler<'a>(
|
pub fn add_interrupt_handler<'a>(
|
||||||
interrupt: Interrupt,
|
interrupt: Interrupt,
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
///
|
///
|
||||||
/// This will generate something along the lines of the following:
|
/// This will generate something along the lines of the following:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,ignore
|
||||||
/// // module name comes from the name of the toml file, so `sprites` in this case because it is
|
/// // module name comes from the name of the toml file, so `sprites` in this case because it is
|
||||||
/// // called `sprites.toml`
|
/// // called `sprites.toml`
|
||||||
/// mod sprites {
|
/// mod sprites {
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// In `src/main.rs`
|
/// In `src/main.rs`
|
||||||
/// ```
|
/// ```rust,ignore
|
||||||
/// mod gfx {
|
/// mod gfx {
|
||||||
/// use agb::display::object::ObjectControl;
|
/// use agb::display::object::ObjectControl;
|
||||||
///
|
///
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// In `src/main.rs`:
|
/// In `src/main.rs`:
|
||||||
/// ```
|
/// ```rust,ignore
|
||||||
/// mod gfx {
|
/// mod gfx {
|
||||||
/// use agb::display::background::BackgroundDistributor;
|
/// use agb::display::background::BackgroundDistributor;
|
||||||
///
|
///
|
||||||
|
@ -139,7 +139,7 @@ macro_rules! include_font {
|
||||||
/// Doing this will ensure that `agb` can correctly set up the environment to call your rust function on start up.
|
/// Doing this will ensure that `agb` can correctly set up the environment to call your rust function on start up.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```no_run,rust
|
||||||
/// #![no_std]
|
/// #![no_std]
|
||||||
/// #![no_main]
|
/// #![no_main]
|
||||||
///
|
///
|
||||||
|
@ -206,7 +206,7 @@ static mut GBASINGLE: single::Singleton<Gba> = single::Singleton::new(unsafe { G
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```no_run,rust
|
||||||
/// #![no_std]
|
/// #![no_std]
|
||||||
/// #![no_main]
|
/// #![no_main]
|
||||||
///
|
///
|
||||||
|
|
|
@ -35,9 +35,13 @@
|
||||||
//! To create a sound mixer, you will need to get it out of the [`Gba`](crate::Gba) struct
|
//! To create a sound mixer, you will need to get it out of the [`Gba`](crate::Gba) struct
|
||||||
//! as follows:
|
//! as follows:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```rust,no_run
|
||||||
|
//! # #![no_std]
|
||||||
|
//! # #![no_main]
|
||||||
|
//! # fn foo(gba: &mut agb::Gba) {
|
||||||
//! let mut mixer = gba.mixer.mixer();
|
//! let mut mixer = gba.mixer.mixer();
|
||||||
//! mixer.enable();
|
//! mixer.enable();
|
||||||
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ## Doing the per-frame work
|
//! ## Doing the per-frame work
|
||||||
|
@ -48,22 +52,34 @@
|
||||||
//!
|
//!
|
||||||
//! Without interrupts:
|
//! Without interrupts:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```rust,no_run
|
||||||
|
//! # #![no_std]
|
||||||
|
//! # #![no_main]
|
||||||
|
//! # fn foo(gba: &mut agb::Gba) {
|
||||||
|
//! # let mut mixer = gba.mixer.mixer();
|
||||||
|
//! # let vblank = agb::interrupt::VBlank::get();
|
||||||
//! // Somewhere in your main loop:
|
//! // Somewhere in your main loop:
|
||||||
//! mixer.frame();
|
//! mixer.frame();
|
||||||
//! vblank.wait_for_vblank();
|
//! vblank.wait_for_vblank();
|
||||||
//! mixer.after_vblank();
|
//! mixer.after_vblank();
|
||||||
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Or with interrupts:
|
//! Or with interrupts:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```rust,no_run
|
||||||
|
//! # #![no_std]
|
||||||
|
//! # #![no_main]
|
||||||
|
//! # fn foo(gba: &mut agb::Gba) {
|
||||||
|
//! # let mut mixer = gba.mixer.mixer();
|
||||||
|
//! # let vblank = agb::interrupt::VBlank::get();
|
||||||
//! // outside your main loop, close to initialisation
|
//! // outside your main loop, close to initialisation
|
||||||
//! let _mixer_interrupt = mixer.setup_interrupt_handler();
|
//! let _mixer_interrupt = mixer.setup_interrupt_handler();
|
||||||
//!
|
//!
|
||||||
//! // inside your main loop
|
//! // inside your main loop
|
||||||
//! mixer.frame();
|
//! mixer.frame();
|
||||||
//! vblank.wait_for_vblank();
|
//! vblank.wait_for_vblank();
|
||||||
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Despite being high performance, the mixer still takes a sizable portion of CPU time (6-10%
|
//! Despite being high performance, the mixer still takes a sizable portion of CPU time (6-10%
|
||||||
|
@ -79,14 +95,21 @@
|
||||||
//! Use the [`include_wav!`](crate::include_wav) macro in order to load the sound. This will produce
|
//! Use the [`include_wav!`](crate::include_wav) macro in order to load the sound. This will produce
|
||||||
//! an error if your wav file is of the wrong frequency.
|
//! an error if your wav file is of the wrong frequency.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```rust,no_run
|
||||||
|
//! # #![no_std]
|
||||||
|
//! # #![no_main]
|
||||||
|
//! # fn foo(gba: &mut agb::Gba) {
|
||||||
|
//! # let mut mixer = gba.mixer.mixer();
|
||||||
|
//! # let vblank = agb::interrupt::VBlank::get();
|
||||||
|
//! # use agb::{*, sound::mixer::*};
|
||||||
//! // Outside your main function in global scope:
|
//! // Outside your main function in global scope:
|
||||||
//! const MY_CRAZY_SOUND: &[u8] = include_wav!("sfx/my_crazy_sound.wav");
|
//! const MY_CRAZY_SOUND: &[u8] = include_wav!("examples/sfx/jump.wav");
|
||||||
//!
|
//!
|
||||||
//! // Then to play the sound:
|
//! // Then to play the sound:
|
||||||
//! let mut channel = SoundChannel::new(MY_CRAZY_SOUND);
|
//! let mut channel = SoundChannel::new(MY_CRAZY_SOUND);
|
||||||
//! channel.stereo();
|
//! channel.stereo();
|
||||||
//! let _ = mixer.play_sound(channel); // we don't mind if this sound doesn't actually play
|
//! let _ = mixer.play_sound(channel); // we don't mind if this sound doesn't actually play
|
||||||
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! See the [`SoundChannel`] struct for more details on how you can configure the sounds to play.
|
//! See the [`SoundChannel`] struct for more details on how you can configure the sounds to play.
|
||||||
|
@ -152,25 +175,39 @@ enum SoundPriority {
|
||||||
/// play regardless of whether you have lots of sound effects playing. You create a high
|
/// play regardless of whether you have lots of sound effects playing. You create a high
|
||||||
/// priority sound channel using [`new_high_priority`](SoundChannel::new_high_priority).
|
/// priority sound channel using [`new_high_priority`](SoundChannel::new_high_priority).
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,no_run
|
||||||
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # use agb::sound::mixer::*;
|
||||||
|
/// # use agb::*;
|
||||||
/// // in global scope:
|
/// // in global scope:
|
||||||
/// const MY_BGM: [u8] = include_wav!("sfx/my_bgm.wav");
|
/// const MY_BGM: &[u8] = include_wav!("examples/sfx/my_bgm.wav");
|
||||||
///
|
///
|
||||||
/// // somewhere in code
|
/// // somewhere in code
|
||||||
|
/// # fn foo(gba: &mut Gba) {
|
||||||
|
/// # let mut mixer = gba.mixer.mixer();
|
||||||
/// let mut bgm = SoundChannel::new_high_priority(MY_BGM);
|
/// let mut bgm = SoundChannel::new_high_priority(MY_BGM);
|
||||||
/// bgm.stereo().should_loop();
|
/// bgm.stereo().should_loop();
|
||||||
/// let _ = mixer.play_sound(bgm);
|
/// let _ = mixer.play_sound(bgm);
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## Playing a sound effect
|
/// ## Playing a sound effect
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,no_run
|
||||||
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # use agb::sound::mixer::*;
|
||||||
|
/// # use agb::*;
|
||||||
/// // in global scope:
|
/// // in global scope:
|
||||||
/// const JUMP_SOUND: [u8] = include_wav!("sfx/jump_sound.wav");
|
/// const JUMP_SOUND: &[u8] = include_wav!("examples/sfx/jump.wav");
|
||||||
///
|
///
|
||||||
/// // somewhere in code
|
/// // somewhere in code
|
||||||
/// let jump_sound = SoundChannel::new(MY_JUMP_SOUND);
|
/// # fn foo(gba: &mut Gba) {
|
||||||
|
/// # let mut mixer = gba.mixer.mixer();
|
||||||
|
/// let jump_sound = SoundChannel::new(JUMP_SOUND);
|
||||||
/// let _ = mixer.play_sound(jump_sound);
|
/// let _ = mixer.play_sound(jump_sound);
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct SoundChannel {
|
pub struct SoundChannel {
|
||||||
data: &'static [u8],
|
data: &'static [u8],
|
||||||
|
@ -198,13 +235,20 @@ impl SoundChannel {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
/// // in global scope:
|
/// // in global scope:
|
||||||
/// const JUMP_SOUND: [u8] = include_wav!("sfx/jump_sound.wav");
|
/// const JUMP_SOUND: &[u8] = include_wav!("examples/sfx/jump.wav");
|
||||||
///
|
///
|
||||||
/// // somewhere in code
|
/// // somewhere in code
|
||||||
/// let jump_sound = SoundChannel::new(MY_JUMP_SOUND);
|
/// let jump_sound = SoundChannel::new(JUMP_SOUND);
|
||||||
/// let _ = mixer.play_sound(jump_sound);
|
/// let _ = mixer.play_sound(jump_sound);
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -233,14 +277,21 @@ impl SoundChannel {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
/// // in global scope:
|
/// // in global scope:
|
||||||
/// const MY_BGM: [u8] = include_wav!("sfx/my_bgm.wav");
|
/// const MY_BGM: &[u8] = include_wav!("examples/sfx/my_bgm.wav");
|
||||||
///
|
///
|
||||||
/// // somewhere in code
|
/// // somewhere in code
|
||||||
/// let mut bgm = SoundChannel::new_high_priority(MY_BGM);
|
/// let mut bgm = SoundChannel::new_high_priority(MY_BGM);
|
||||||
/// bgm.stereo().should_loop();
|
/// bgm.stereo().should_loop();
|
||||||
/// let _ = mixer.play_sound(bgm);
|
/// let _ = mixer.play_sound(bgm);
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
|
@ -36,15 +36,28 @@ extern "C" {
|
||||||
/// You should not create this struct directly, instead creating it through the [`Gba`](crate::Gba)
|
/// You should not create this struct directly, instead creating it through the [`Gba`](crate::Gba)
|
||||||
/// struct as follows:
|
/// struct as follows:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust,no_run
|
||||||
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # use agb::sound::mixer::*;
|
||||||
|
/// # use agb::*;
|
||||||
|
/// # fn foo(gba: &mut Gba) {
|
||||||
/// let mut mixer = gba.mixer.mixer();
|
/// let mut mixer = gba.mixer.mixer();
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
|
/// # let vblank = agb::interrupt::VBlank::get();
|
||||||
/// // Outside your main function in global scope:
|
/// // Outside your main function in global scope:
|
||||||
/// const MY_CRAZY_SOUND: &[u8] = include_wav!("sfx/my_crazy_sound.wav");
|
/// const MY_CRAZY_SOUND: &[u8] = include_wav!("examples/sfx/jump.wav");
|
||||||
///
|
///
|
||||||
/// // in your main function:
|
/// // in your main function:
|
||||||
/// let mut mixer = gba.mixer.mixer();
|
/// let mut mixer = gba.mixer.mixer();
|
||||||
|
@ -57,6 +70,7 @@ extern "C" {
|
||||||
/// vblank.wait_for_vblank();
|
/// vblank.wait_for_vblank();
|
||||||
/// mixer.after_vblank();
|
/// mixer.after_vblank();
|
||||||
/// }
|
/// }
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Mixer {
|
pub struct Mixer {
|
||||||
buffer: MixerBuffer,
|
buffer: MixerBuffer,
|
||||||
|
@ -72,12 +86,20 @@ pub struct Mixer {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
|
/// # const MY_BGM: &[u8] = include_wav!("examples/sfx/my_bgm.wav");
|
||||||
/// let mut channel = SoundChannel::new_high_priority(MY_BGM);
|
/// let mut channel = SoundChannel::new_high_priority(MY_BGM);
|
||||||
/// let bgm_channel_id = mixer.play_sound(channel).unwrap(); // will always be Some if high priority
|
/// let bgm_channel_id = mixer.play_sound(channel).unwrap(); // will always be Some if high priority
|
||||||
///
|
///
|
||||||
/// // Later, stop that particular channel
|
/// // Later, stop that particular channel
|
||||||
/// mixer.channel(bgm_channel_id).stop();
|
/// mixer.channel(&bgm_channel_id).expect("Expected to still be playing").stop();
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct ChannelId(usize, i32);
|
pub struct ChannelId(usize, i32);
|
||||||
|
|
||||||
|
@ -106,12 +128,20 @@ impl Mixer {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
|
/// # let vblank = agb::interrupt::VBlank::get();
|
||||||
/// loop {
|
/// loop {
|
||||||
/// mixer.frame();
|
/// mixer.frame();
|
||||||
/// vblank.wait_for_vblank();
|
/// vblank.wait_for_vblank();
|
||||||
/// mixer.after_vblank();
|
/// mixer.after_vblank();
|
||||||
/// }
|
/// }
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "freq32768"))]
|
#[cfg(not(feature = "freq32768"))]
|
||||||
pub fn after_vblank(&mut self) {
|
pub fn after_vblank(&mut self) {
|
||||||
|
@ -127,7 +157,14 @@ impl Mixer {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
|
/// # let vblank = agb::interrupt::VBlank::get();
|
||||||
/// // you must set this to a named variable to ensure that the scope is long enough
|
/// // you must set this to a named variable to ensure that the scope is long enough
|
||||||
/// let _mixer_interrupt = mixer.setup_interrupt_handler();
|
/// let _mixer_interrupt = mixer.setup_interrupt_handler();
|
||||||
///
|
///
|
||||||
|
@ -135,6 +172,7 @@ impl Mixer {
|
||||||
/// mixer.frame();
|
/// mixer.frame();
|
||||||
/// vblank.wait_for_vblank();
|
/// vblank.wait_for_vblank();
|
||||||
/// }
|
/// }
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn setup_interrupt_handler(&self) -> InterruptHandler<'_> {
|
pub fn setup_interrupt_handler(&self) -> InterruptHandler<'_> {
|
||||||
let mut timer1 = unsafe { Timer::new(1) };
|
let mut timer1 = unsafe { Timer::new(1) };
|
||||||
|
@ -157,12 +195,20 @@ impl Mixer {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
|
/// # let vblank = agb::interrupt::VBlank::get();
|
||||||
/// loop {
|
/// loop {
|
||||||
/// mixer.frame();
|
/// mixer.frame();
|
||||||
/// vblank.wait_for_vblank();
|
/// vblank.wait_for_vblank();
|
||||||
/// mixer.after_vblank(); // optional, only if not using interrupts
|
/// mixer.after_vblank(); // optional, only if not using interrupts
|
||||||
/// }
|
/// }
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn frame(&mut self) {
|
pub fn frame(&mut self) {
|
||||||
if !self.buffer.should_calculate() {
|
if !self.buffer.should_calculate() {
|
||||||
|
@ -188,9 +234,17 @@ impl Mixer {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
|
/// # const MY_BGM: &[u8] = include_wav!("examples/sfx/my_bgm.wav");
|
||||||
/// let mut channel = SoundChannel::new_high_priority(MY_BGM);
|
/// let mut channel = SoundChannel::new_high_priority(MY_BGM);
|
||||||
/// let bgm_channel_id = mixer.play_sound(channel).unwrap(); // will always be Some if high priority
|
/// let bgm_channel_id = mixer.play_sound(channel).unwrap(); // will always be Some if high priority
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn play_sound(&mut self, new_channel: SoundChannel) -> Option<ChannelId> {
|
pub fn play_sound(&mut self, new_channel: SoundChannel) -> Option<ChannelId> {
|
||||||
for (i, channel) in self.channels.iter_mut().enumerate() {
|
for (i, channel) in self.channels.iter_mut().enumerate() {
|
||||||
|
@ -229,12 +283,20 @@ impl Mixer {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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();
|
||||||
|
/// # const MY_BGM: &[u8] = include_wav!("examples/sfx/my_bgm.wav");
|
||||||
/// let mut channel = SoundChannel::new_high_priority(MY_BGM);
|
/// let mut channel = SoundChannel::new_high_priority(MY_BGM);
|
||||||
/// let bgm_channel_id = mixer.play_sound(channel).unwrap(); // will always be Some if high priority
|
/// let bgm_channel_id = mixer.play_sound(channel).unwrap(); // will always be Some if high priority
|
||||||
///
|
///
|
||||||
/// // Later, stop that particular channel
|
/// // Later, stop that particular channel
|
||||||
/// mixer.channel(bgm_channel_id).stop();
|
/// mixer.channel(&bgm_channel_id).expect("Expected still to be playing").stop();
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn channel(&mut self, id: &ChannelId) -> Option<&'_ mut SoundChannel> {
|
pub fn channel(&mut self, id: &ChannelId) -> Option<&'_ mut SoundChannel> {
|
||||||
if let Some(channel) = &mut self.channels[id.0] {
|
if let Some(channel) = &mut self.channels[id.0] {
|
||||||
|
|
5
justfile
5
justfile
|
@ -17,6 +17,9 @@ test:
|
||||||
test-release:
|
test-release:
|
||||||
just _test-release agb
|
just _test-release agb
|
||||||
|
|
||||||
|
doctest-agb:
|
||||||
|
(cd agb && cargo test --doc -Z doctest-xcompile)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
just _all-crates _clean
|
just _all-crates _clean
|
||||||
|
|
||||||
|
@ -34,7 +37,7 @@ run-game game:
|
||||||
run-game-debug game:
|
run-game-debug game:
|
||||||
(cd "examples/{{game}}" && cargo run)
|
(cd "examples/{{game}}" && cargo run)
|
||||||
|
|
||||||
ci: build-debug clippy test build-release test-release build-roms build-book
|
ci: build-debug clippy test build-release test-release doctest-agb build-roms build-book
|
||||||
|
|
||||||
build-roms:
|
build-roms:
|
||||||
just _build-rom "examples/the-purple-night" "PURPLENIGHT"
|
just _build-rom "examples/the-purple-night" "PURPLENIGHT"
|
||||||
|
|
Loading…
Reference in a new issue