mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-11 17:41:33 +11:00
Merge pull request #84 from gwilymk/modify-running-sound
Modify running sound
This commit is contained in:
commit
0cafd8eaca
|
@ -5,6 +5,8 @@ extern crate agb;
|
||||||
|
|
||||||
use agb::sound::mixer::SoundChannel;
|
use agb::sound::mixer::SoundChannel;
|
||||||
use agb::Gba;
|
use agb::Gba;
|
||||||
|
use agb::input::{ButtonController, Tri, Button};
|
||||||
|
use agb::number::Num;
|
||||||
|
|
||||||
// Music - "I will not let you let me down" by Josh Woodward, free download at http://joshwoodward.com
|
// Music - "I will not let you let me down" by Josh Woodward, free download at http://joshwoodward.com
|
||||||
const I_WILL_NOT_LET_YOU_LET_ME_DOWN: &[u8] = include_bytes!("i-will-not-let-you-let-me-down.raw");
|
const I_WILL_NOT_LET_YOU_LET_ME_DOWN: &[u8] = include_bytes!("i-will-not-let-you-let-me-down.raw");
|
||||||
|
@ -12,15 +14,42 @@ const I_WILL_NOT_LET_YOU_LET_ME_DOWN: &[u8] = include_bytes!("i-will-not-let-you
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main() -> ! {
|
pub fn main() -> ! {
|
||||||
let mut gba = Gba::new();
|
let mut gba = Gba::new();
|
||||||
|
let mut input = ButtonController::new();
|
||||||
let vblank_provider = gba.display.vblank.get();
|
let vblank_provider = gba.display.vblank.get();
|
||||||
|
|
||||||
let mut mixer = gba.mixer.mixer();
|
let mut mixer = gba.mixer.mixer();
|
||||||
mixer.enable();
|
mixer.enable();
|
||||||
|
|
||||||
let channel = SoundChannel::new(I_WILL_NOT_LET_YOU_LET_ME_DOWN);
|
let channel = SoundChannel::new(I_WILL_NOT_LET_YOU_LET_ME_DOWN);
|
||||||
mixer.play_sound(channel);
|
let channel_id = mixer.play_sound(channel).unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
input.update();
|
||||||
|
|
||||||
|
{
|
||||||
|
if let Some(channel) = mixer.get_channel(&channel_id) {
|
||||||
|
let half: Num<i16, 4> = Num::new(1) / 2;
|
||||||
|
let half_usize: Num<usize, 8> = Num::new(1) / 2;
|
||||||
|
match input.x_tri() {
|
||||||
|
Tri::Negative => channel.panning(-half),
|
||||||
|
Tri::Zero => channel.panning(0.into()),
|
||||||
|
Tri::Positive => channel.panning(half),
|
||||||
|
};
|
||||||
|
|
||||||
|
match input.y_tri() {
|
||||||
|
Tri::Negative => channel.playback(half_usize.change_base() + 1),
|
||||||
|
Tri::Zero => channel.playback(1.into()),
|
||||||
|
Tri::Positive => channel.playback(half_usize),
|
||||||
|
};
|
||||||
|
|
||||||
|
if input.is_pressed(Button::L) {
|
||||||
|
channel.volume(half);
|
||||||
|
} else {
|
||||||
|
channel.volume(1.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vblank_provider.wait_for_VBlank();
|
vblank_provider.wait_for_VBlank();
|
||||||
mixer.vblank();
|
mixer.vblank();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub struct SoundChannel {
|
||||||
should_loop: bool,
|
should_loop: bool,
|
||||||
|
|
||||||
playback_speed: Num<usize, 8>,
|
playback_speed: Num<usize, 8>,
|
||||||
|
volume: Num<i16, 4>, // between 0 and 1
|
||||||
|
|
||||||
panning: Num<i16, 4>, // between -1 and 1
|
panning: Num<i16, 4>, // between -1 and 1
|
||||||
is_done: bool,
|
is_done: bool,
|
||||||
|
@ -47,20 +48,34 @@ impl SoundChannel {
|
||||||
panning: 0.into(),
|
panning: 0.into(),
|
||||||
is_done: false,
|
is_done: false,
|
||||||
priority: SoundPriority::Low,
|
priority: SoundPriority::Low,
|
||||||
|
volume: 1.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_loop(mut self) -> Self {
|
pub fn new_high_priority(data: &'static [u8]) -> Self {
|
||||||
|
SoundChannel {
|
||||||
|
data,
|
||||||
|
pos: 0.into(),
|
||||||
|
should_loop: false,
|
||||||
|
playback_speed: 1.into(),
|
||||||
|
panning: 0.into(),
|
||||||
|
is_done: false,
|
||||||
|
priority: SoundPriority::High,
|
||||||
|
volume: 1.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_loop(&mut self) -> &mut Self {
|
||||||
self.should_loop = true;
|
self.should_loop = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn playback(mut self, playback_speed: Num<usize, 8>) -> Self {
|
pub fn playback(&mut self, playback_speed: Num<usize, 8>) -> &mut Self {
|
||||||
self.playback_speed = playback_speed;
|
self.playback_speed = playback_speed;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panning(mut self, panning: Num<i16, 4>) -> Self {
|
pub fn panning(&mut self, panning: Num<i16, 4>) -> &mut Self {
|
||||||
debug_assert!(panning >= Num::new(-1), "panning value must be >= -1");
|
debug_assert!(panning >= Num::new(-1), "panning value must be >= -1");
|
||||||
debug_assert!(panning <= Num::new(1), "panning value must be <= 1");
|
debug_assert!(panning <= Num::new(1), "panning value must be <= 1");
|
||||||
|
|
||||||
|
@ -68,8 +83,15 @@ impl SoundChannel {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn high_priority(mut self) -> Self {
|
pub fn volume(&mut self, volume: Num<i16, 4>) -> &mut Self {
|
||||||
self.priority = SoundPriority::High;
|
assert!(volume <= Num::new(1), "volume must be <= 1");
|
||||||
|
assert!(volume >= Num::new(0), "volume must be >= 0");
|
||||||
|
|
||||||
|
self.volume = volume;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self) {
|
||||||
|
self.is_done = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,17 @@ use crate::number::Num;
|
||||||
pub struct Mixer {
|
pub struct Mixer {
|
||||||
buffer: MixerBuffer,
|
buffer: MixerBuffer,
|
||||||
channels: [Option<SoundChannel>; 16],
|
channels: [Option<SoundChannel>; 16],
|
||||||
|
indices: [i32; 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ChannelId(usize, i32);
|
||||||
|
|
||||||
impl Mixer {
|
impl Mixer {
|
||||||
pub(super) fn new() -> Self {
|
pub(super) fn new() -> Self {
|
||||||
Mixer {
|
Mixer {
|
||||||
buffer: MixerBuffer::new(),
|
buffer: MixerBuffer::new(),
|
||||||
channels: Default::default(),
|
channels: Default::default(),
|
||||||
|
indices: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +33,8 @@ impl Mixer {
|
||||||
.write_channels(self.channels.iter_mut().flatten());
|
.write_channels(self.channels.iter_mut().flatten());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn play_sound(&mut self, new_channel: SoundChannel) {
|
pub fn play_sound(&mut self, new_channel: SoundChannel) -> Option<ChannelId> {
|
||||||
for channel in self.channels.iter_mut() {
|
for (i, channel) in self.channels.iter_mut().enumerate() {
|
||||||
if let Some(some_channel) = channel {
|
if let Some(some_channel) = channel {
|
||||||
if !some_channel.is_done {
|
if !some_channel.is_done {
|
||||||
continue;
|
continue;
|
||||||
|
@ -38,24 +42,36 @@ impl Mixer {
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.replace(new_channel);
|
channel.replace(new_channel);
|
||||||
return;
|
self.indices[i] += 1;
|
||||||
|
return Some(ChannelId(i, self.indices[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_channel.priority == SoundPriority::Low {
|
if new_channel.priority == SoundPriority::Low {
|
||||||
return; // don't bother even playing it
|
return None; // don't bother even playing it
|
||||||
}
|
}
|
||||||
|
|
||||||
for channel in self.channels.iter_mut() {
|
for (i, channel) in self.channels.iter_mut().enumerate() {
|
||||||
if channel.as_ref().unwrap().priority == SoundPriority::High {
|
if channel.as_ref().unwrap().priority == SoundPriority::High {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.replace(new_channel);
|
channel.replace(new_channel);
|
||||||
return;
|
self.indices[i] += 1;
|
||||||
|
return Some(ChannelId(i, self.indices[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
panic!("Cannot play more than 16 sounds at once");
|
panic!("Cannot play more than 16 sounds at once");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_channel(&mut self, id: &ChannelId) -> Option<&'_ mut SoundChannel> {
|
||||||
|
if let Some(channel) = &mut self.channels[id.0] {
|
||||||
|
if self.indices[id.0] == id.1 && !channel.is_done {
|
||||||
|
return Some(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// I've picked one frequency that works nicely. But there are others that work nicely
|
// I've picked one frequency that works nicely. But there are others that work nicely
|
||||||
|
@ -101,8 +117,8 @@ impl MixerBuffer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let right_amount = (channel.panning + 1) / 2;
|
let right_amount = ((channel.panning + 1) / 2) * channel.volume;
|
||||||
let left_amount = -right_amount + 1;
|
let left_amount = ((-channel.panning + 1) / 2) * channel.volume;
|
||||||
|
|
||||||
if channel.pos + channel.playback_speed * SOUND_BUFFER_SIZE >= channel.data.len().into()
|
if channel.pos + channel.playback_speed * SOUND_BUFFER_SIZE >= channel.data.len().into()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue