diff --git a/agb-fixnum/src/lib.rs b/agb-fixnum/src/lib.rs index efa6586e..ebbe2179 100644 --- a/agb-fixnum/src/lib.rs +++ b/agb-fixnum/src/lib.rs @@ -9,10 +9,13 @@ use core::{ }, }; +#[doc(hidden)] +pub use agb_macros::num as num_inner; + #[macro_export] macro_rules! num { ($value:literal) => {{ - $crate::Num::new_from_parts(agb_macros::num!($value)) + $crate::Num::new_from_parts($crate::num_inner!($value)) }}; } diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs index 6077dc1c..c9c58898 100644 --- a/agb-image-converter/src/lib.rs +++ b/agb-image-converter/src/lib.rs @@ -115,7 +115,7 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream { for frame in frames { let width = frame.width(); - assert!(width == frame.height() && width.is_power_of_two() && width <= 32); + assert!(width == frame.height() && width.is_power_of_two() && width <= 64); let image = Image::load_from_dyn_image(frame); add_to_optimiser( @@ -154,7 +154,7 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream { quote! { Sprite::new( &PALETTES[#assignment], - #data, + align_bytes!(u16, #data), Size::from_width_height(#width, #height) ) } diff --git a/agb/src/display/object.rs b/agb/src/display/object.rs index 0b88c3e1..04a33587 100644 --- a/agb/src/display/object.rs +++ b/agb/src/display/object.rs @@ -135,11 +135,32 @@ pub enum Size { S32x64 = 0b10_11, } +#[repr(C)] // guarantee 'bytes' comes after '_align' +pub struct AlignedAs<Align, Bytes: ?Sized> { + pub _align: [Align; 0], + pub bytes: Bytes, +} + +#[macro_export] +macro_rules! align_bytes { + ($align_ty:ty, $data:literal) => {{ + use $crate::display::object::AlignedAs; + + const ALIGNED: &AlignedAs<$align_ty, [u8]> = &AlignedAs { + _align: [], + bytes: *$data, + }; + + &ALIGNED.bytes + }}; +} + #[macro_export] macro_rules! include_aseprite { ($($aseprite_path: expr),*) => {{ use $crate::display::object::{Size, Sprite, Tag, TagMap, Graphics}; use $crate::display::palette16::Palette16; + use $crate::align_bytes; $crate::include_aseprite_inner!($($aseprite_path),*); @@ -249,8 +270,11 @@ impl Tag { } #[must_use] - pub fn sprite(&self, idx: usize) -> &'static Sprite { - &self.sprites()[idx] + pub const fn sprite(&self, idx: usize) -> &'static Sprite { + if idx >= self.len { + panic!("out of bounds access to sprite"); + } + unsafe { &*self.sprites.add(idx) } } #[inline] diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index a2a2ce15..6caa8956 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -17,7 +17,7 @@ const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> = static TILE_ALLOCATOR: BlockAllocator = unsafe { BlockAllocator::new(StartEnd { - start: || TILE_RAM_START, + start: || TILE_RAM_START + 8 * 8, end: || TILE_RAM_START + 0x8000, }) }; diff --git a/agb/src/sound/mixer/mixer.s b/agb/src/sound/mixer/mixer.s index 33f59172..4af591e1 100644 --- a/agb/src/sound/mixer/mixer.s +++ b/agb/src/sound/mixer/mixer.s @@ -95,10 +95,12 @@ agb_arm_func agb_rs__mixer_add_stereo @ Arguments @ r0 - pointer to the data to be copied (u8 array) @ r1 - pointer to the sound buffer (i16 array which will alternate left and right channels, 32-bit aligned) + @ r2 - volume to play the sound at @ @ The sound buffer must be SOUND_BUFFER_SIZE * 2 in size = 176 * 2 - push {r4-r8} + push {r4-r9} + mov r9, r2 ldr r5, =0x00000FFF ldr r8, =agb_rs__buffer_size @@ -128,7 +130,7 @@ agb_arm_func agb_rs__mixer_add_stereo lsl r6, r6, #24 @ r6 = | R | 0 | 0 | 0 | drop everything except the right sample orr r6, r7, r6, asr #8 @ r6 = | 1 | R | 1 | L | now we have it perfectly set up - add r4, r4, r6, lsl #4 @ r4 += r6 << 4 (calculating both the left and right samples together) + mla r4, r6, r9, r4 @ r4 += r6 * r9 (calculating both the left and right samples together) str r4, [r1], #4 @ store the new value, and increment the pointer .endr @@ -136,7 +138,7 @@ agb_arm_func agb_rs__mixer_add_stereo subs r8, r8, #4 @ loop counter bne 1b @ jump back if we're done with the loop - pop {r4-r8} + pop {r4-r9} bx lr agb_arm_end agb_rs__mixer_add_stereo diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 9b72e599..ac01dba7 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -375,4 +375,18 @@ impl SoundChannel { pub fn stop(&mut self) { self.is_done = true; } + + /// Gets how far along the sound has played. + #[inline] + #[must_use] + pub fn pos(&self) -> Num<usize, 8> { + self.pos + } + + /// Sets the playback position + #[inline] + pub fn set_pos(&mut self, pos: impl Into<Num<usize, 8>>) -> &mut Self { + self.pos = pos.into(); + self + } } diff --git a/agb/src/sound/mixer/sw_mixer.rs b/agb/src/sound/mixer/sw_mixer.rs index 676c0ed8..80b5b139 100644 --- a/agb/src/sound/mixer/sw_mixer.rs +++ b/agb/src/sound/mixer/sw_mixer.rs @@ -25,7 +25,11 @@ extern "C" { right_amount: Num<i16, 4>, ); - fn agb_rs__mixer_add_stereo(sound_data: *const u8, sound_buffer: *mut Num<i16, 4>); + fn agb_rs__mixer_add_stereo( + sound_data: *const u8, + sound_buffer: *mut Num<i16, 4>, + volume: Num<i16, 4>, + ); fn agb_rs__mixer_collapse(sound_buffer: *mut i8, input_buffer: *const Num<i16, 4>); } @@ -447,6 +451,7 @@ impl MixerBuffer { agb_rs__mixer_add_stereo( channel.data.as_ptr().add(channel.pos.floor()), buffer.as_mut_ptr(), + channel.volume, ); } } else {