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
|
agb_arm_func \fn_name
|
||||||
@ Arguments
|
@ Arguments
|
||||||
@ r0 - pointer to the sample data from the beginning
|
@ r0 - pointer to the sample data from the beginning
|
||||||
|
@ -26,7 +26,11 @@ agb_arm_func \fn_name
|
||||||
|
|
||||||
.irp reg, r7,r8,r9,r10
|
.irp reg, r7,r8,r9,r10
|
||||||
cmp r4, r5, lsr #8 @ check if we're overflowing
|
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
|
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
|
mov r11, r5, lsr #8 @ calculate the next location to get a value from
|
||||||
ldrsb r11, [r0, r11] @ load a single value
|
ldrsb r11, [r0, r11] @ load a single value
|
||||||
|
@ -44,6 +48,35 @@ agb_arm_func \fn_name
|
||||||
subs r2, r2, #4
|
subs r2, r2, #4
|
||||||
bne 1b
|
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
|
mov r0, r5 @ return the playback position
|
||||||
pop {{r4-r11,lr}}
|
pop {{r4-r11,lr}}
|
||||||
|
|
||||||
|
@ -51,8 +84,10 @@ agb_arm_func \fn_name
|
||||||
agb_arm_end \fn_name
|
agb_arm_end \fn_name
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
mono_add_fn_loop agb_rs__mixer_add_mono_loop_first true
|
mono_add_fn_loop agb_rs__mixer_add_mono_loop_first true true
|
||||||
mono_add_fn_loop agb_rs__mixer_add_mono_loop false
|
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
|
.macro stereo_add_fn fn_name:req is_first:req
|
||||||
agb_arm_func \fn_name
|
agb_arm_func \fn_name
|
||||||
|
|
|
@ -19,6 +19,21 @@ use crate::{
|
||||||
timer::Timer,
|
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
|
// Defined in mixer.s
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn agb_rs__mixer_add_stereo(
|
fn agb_rs__mixer_add_stereo(
|
||||||
|
@ -41,27 +56,10 @@ extern "C" {
|
||||||
num_samples: usize,
|
num_samples: usize,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn agb_rs__mixer_add_mono_loop_first(
|
add_mono_fn!(agb_rs__mixer_add_mono_loop_first);
|
||||||
sample_data: *const u8,
|
add_mono_fn!(agb_rs__mixer_add_mono_loop);
|
||||||
sample_buffer: *mut i32,
|
add_mono_fn!(agb_rs__mixer_add_mono_first);
|
||||||
buffer_size: usize,
|
add_mono_fn!(agb_rs__mixer_add_mono);
|
||||||
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>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main software mixer struct.
|
/// The main software mixer struct.
|
||||||
|
@ -518,9 +516,10 @@ impl MixerBuffer {
|
||||||
let mul_amount =
|
let mul_amount =
|
||||||
((left_amount.to_raw() as i32) << 16) | (right_amount.to_raw() as i32 & 0x0000ffff);
|
((left_amount.to_raw() as i32) << 16) | (right_amount.to_raw() as i32 & 0x0000ffff);
|
||||||
|
|
||||||
if IS_FIRST && channel.should_loop {
|
macro_rules! call_mono_fn {
|
||||||
|
($fn_name:ident) => {
|
||||||
channel.pos = unsafe {
|
channel.pos = unsafe {
|
||||||
agb_rs__mixer_add_mono_loop_first(
|
$fn_name(
|
||||||
channel.data.as_ptr(),
|
channel.data.as_ptr(),
|
||||||
working_buffer_i32.as_mut_ptr(),
|
working_buffer_i32.as_mut_ptr(),
|
||||||
working_buffer_i32.len(),
|
working_buffer_i32.len(),
|
||||||
|
@ -530,44 +529,20 @@ impl MixerBuffer {
|
||||||
channel.playback_speed,
|
channel.playback_speed,
|
||||||
mul_amount,
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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