mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Give the same assembly treatment to mono sounds
This commit is contained in:
parent
de666a54f9
commit
49b9a07a87
|
@ -1,4 +1,4 @@
|
|||
.macro mono_add_fn_loop fn_name:req is_first:req
|
||||
.macro mono_add_fn_loop fn_name:req is_first:req is_loop:req
|
||||
agb_arm_func \fn_name
|
||||
@ Arguments
|
||||
@ r0 - pointer to the sample data from the beginning
|
||||
|
@ -26,11 +26,15 @@ agb_arm_func \fn_name
|
|||
|
||||
.irp reg, r7,r8,r9,r10
|
||||
cmp r4, r5, lsr #8 @ check if we're overflowing
|
||||
.ifc \is_loop,true
|
||||
suble r5, r5, r3 @ if we are, subtract the overflow amount
|
||||
.else
|
||||
ble 2f @ if we are, zero the rest of the buffer
|
||||
.endif
|
||||
|
||||
mov r11, r5, lsr #8 @ calculate the next location to get a value from
|
||||
ldrsb r11, [r0, r11] @ load a single value
|
||||
.ifc \is_first,true @ multiply the sample value, but only add if not the first call
|
||||
.ifc \is_first,true @ multiply the sample value, but only add if not the first call
|
||||
mul \reg, r11, r12
|
||||
.else
|
||||
mla \reg, r11, r12, \reg
|
||||
|
@ -44,6 +48,35 @@ agb_arm_func \fn_name
|
|||
subs r2, r2, #4
|
||||
bne 1b
|
||||
|
||||
.ifc \is_loop,false
|
||||
b 3f
|
||||
|
||||
2:
|
||||
.ifc \is_first,true @ zero the rest of the buffer as this sample has ended
|
||||
ands r7, r2, #3
|
||||
sub r2, r2, r7
|
||||
beq 5f
|
||||
|
||||
4:
|
||||
mov r8, #0
|
||||
4:
|
||||
stmia r1!, {{r8}}
|
||||
subs r7, r7, #1
|
||||
bne 4b
|
||||
|
||||
5:
|
||||
.irp reg, r7,r8,r9,r10
|
||||
mov \reg, #0
|
||||
.endr
|
||||
5:
|
||||
stmia r1!, {{r7-r10}}
|
||||
subs r2, r2, #4
|
||||
bne 5b
|
||||
.endif
|
||||
3:
|
||||
.endif
|
||||
|
||||
|
||||
mov r0, r5 @ return the playback position
|
||||
pop {{r4-r11,lr}}
|
||||
|
||||
|
@ -51,8 +84,10 @@ agb_arm_func \fn_name
|
|||
agb_arm_end \fn_name
|
||||
.endm
|
||||
|
||||
mono_add_fn_loop agb_rs__mixer_add_mono_loop_first true
|
||||
mono_add_fn_loop agb_rs__mixer_add_mono_loop false
|
||||
mono_add_fn_loop agb_rs__mixer_add_mono_loop_first true true
|
||||
mono_add_fn_loop agb_rs__mixer_add_mono_loop false true
|
||||
mono_add_fn_loop agb_rs__mixer_add_mono_first true false
|
||||
mono_add_fn_loop agb_rs__mixer_add_mono false false
|
||||
|
||||
.macro stereo_add_fn fn_name:req is_first:req
|
||||
agb_arm_func \fn_name
|
||||
|
|
|
@ -19,6 +19,21 @@ use crate::{
|
|||
timer::Timer,
|
||||
};
|
||||
|
||||
macro_rules! add_mono_fn {
|
||||
($name:ident) => {
|
||||
fn $name(
|
||||
sample_data: *const u8,
|
||||
sample_buffer: *mut i32,
|
||||
buffer_size: usize,
|
||||
restart_amount: Num<u32, 8>,
|
||||
channel_length: usize,
|
||||
current_pos: Num<u32, 8>,
|
||||
playback_speed: Num<u32, 8>,
|
||||
mul_amount: i32,
|
||||
) -> Num<u32, 8>;
|
||||
};
|
||||
}
|
||||
|
||||
// Defined in mixer.s
|
||||
extern "C" {
|
||||
fn agb_rs__mixer_add_stereo(
|
||||
|
@ -41,27 +56,10 @@ extern "C" {
|
|||
num_samples: usize,
|
||||
);
|
||||
|
||||
fn agb_rs__mixer_add_mono_loop_first(
|
||||
sample_data: *const u8,
|
||||
sample_buffer: *mut i32,
|
||||
buffer_size: usize,
|
||||
restart_amount: Num<u32, 8>,
|
||||
channel_length: usize,
|
||||
current_pos: Num<u32, 8>,
|
||||
playback_speed: Num<u32, 8>,
|
||||
mul_amount: i32,
|
||||
) -> Num<u32, 8>;
|
||||
|
||||
fn agb_rs__mixer_add_mono_loop(
|
||||
sample_data: *const u8,
|
||||
sample_buffer: *mut i32,
|
||||
buffer_size: usize,
|
||||
restart_amount: Num<u32, 8>,
|
||||
channel_length: usize,
|
||||
current_pos: Num<u32, 8>,
|
||||
playback_speed: Num<u32, 8>,
|
||||
mul_amount: i32,
|
||||
) -> Num<u32, 8>;
|
||||
add_mono_fn!(agb_rs__mixer_add_mono_loop_first);
|
||||
add_mono_fn!(agb_rs__mixer_add_mono_loop);
|
||||
add_mono_fn!(agb_rs__mixer_add_mono_first);
|
||||
add_mono_fn!(agb_rs__mixer_add_mono);
|
||||
}
|
||||
|
||||
/// The main software mixer struct.
|
||||
|
@ -518,56 +516,33 @@ impl MixerBuffer {
|
|||
let mul_amount =
|
||||
((left_amount.to_raw() as i32) << 16) | (right_amount.to_raw() as i32 & 0x0000ffff);
|
||||
|
||||
if IS_FIRST && channel.should_loop {
|
||||
channel.pos = unsafe {
|
||||
agb_rs__mixer_add_mono_loop_first(
|
||||
channel.data.as_ptr(),
|
||||
working_buffer_i32.as_mut_ptr(),
|
||||
working_buffer_i32.len(),
|
||||
channel_len - channel.restart_point,
|
||||
channel.data.len(),
|
||||
channel.pos,
|
||||
channel.playback_speed,
|
||||
mul_amount,
|
||||
)
|
||||
};
|
||||
} else if !IS_FIRST && channel.should_loop {
|
||||
channel.pos = unsafe {
|
||||
agb_rs__mixer_add_mono_loop(
|
||||
channel.data.as_ptr(),
|
||||
working_buffer_i32.as_mut_ptr(),
|
||||
working_buffer_i32.len(),
|
||||
channel_len - channel.restart_point,
|
||||
channel.data.len(),
|
||||
channel.pos,
|
||||
channel.playback_speed,
|
||||
mul_amount,
|
||||
)
|
||||
};
|
||||
} else {
|
||||
for i in 0..self.frequency.buffer_size() {
|
||||
if channel.pos >= channel_len {
|
||||
channel.is_done = true;
|
||||
|
||||
break;
|
||||
macro_rules! call_mono_fn {
|
||||
($fn_name:ident) => {
|
||||
channel.pos = unsafe {
|
||||
$fn_name(
|
||||
channel.data.as_ptr(),
|
||||
working_buffer_i32.as_mut_ptr(),
|
||||
working_buffer_i32.len(),
|
||||
channel_len - channel.restart_point,
|
||||
channel.data.len(),
|
||||
channel.pos,
|
||||
channel.playback_speed,
|
||||
mul_amount,
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// SAFETY: channel.pos < channel_len by the above if statement and the fact we reduce the playback speed
|
||||
let value = unsafe { *channel.data.get_unchecked(channel.pos.floor() as usize) }
|
||||
as i8 as i32;
|
||||
|
||||
// SAFETY: working buffer length = self.frequency.buffer_size()
|
||||
if IS_FIRST {
|
||||
unsafe {
|
||||
*working_buffer_i32.get_unchecked_mut(i) = value.wrapping_mul(mul_amount);
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
let value_ref = working_buffer_i32.get_unchecked_mut(i);
|
||||
*value_ref = value_ref.wrapping_add(value.wrapping_mul(mul_amount));
|
||||
};
|
||||
}
|
||||
channel.pos += playback_speed;
|
||||
match (IS_FIRST, channel.should_loop) {
|
||||
(true, true) => call_mono_fn!(agb_rs__mixer_add_mono_loop_first),
|
||||
(false, true) => call_mono_fn!(agb_rs__mixer_add_mono_loop),
|
||||
(true, false) => {
|
||||
call_mono_fn!(agb_rs__mixer_add_mono_first);
|
||||
channel.is_done = channel.pos > channel_len;
|
||||
}
|
||||
(false, false) => {
|
||||
call_mono_fn!(agb_rs__mixer_add_mono);
|
||||
channel.is_done = channel.pos > channel_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue