Skip to content

Commit

Permalink
Change configuration methods
Browse files Browse the repository at this point in the history
  • Loading branch information
MyBlackMIDIScore committed Aug 18, 2024
1 parent a7fc1ee commit cd2d91c
Show file tree
Hide file tree
Showing 18 changed files with 200 additions and 167 deletions.
23 changes: 13 additions & 10 deletions core/src/channel/channel_sf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ use crate::{

use super::voice_spawner::VoiceSpawnerMatrix;

#[derive(Default, PartialEq, Eq, Clone, Copy, Debug)]
pub struct ProgramDescriptor {
pub bank: u8,
pub preset: u8,
}

pub struct ChannelSoundfont {
soundfonts: Vec<Arc<dyn SoundfontBase>>,
matrix: VoiceSpawnerMatrix,
curr_bank: u8,
curr_preset: u8,
curr_program: ProgramDescriptor,
}

impl Deref for ChannelSoundfont {
Expand All @@ -29,8 +34,7 @@ impl ChannelSoundfont {
ChannelSoundfont {
soundfonts: Vec::new(),
matrix: VoiceSpawnerMatrix::new(),
curr_bank: 0,
curr_preset: 0,
curr_program: Default::default(),
}
}

Expand All @@ -41,10 +45,9 @@ impl ChannelSoundfont {
}
}

pub fn change_program(&mut self, bank: u8, preset: u8) {
if self.curr_bank != bank || self.curr_preset != preset {
self.curr_bank = bank;
self.curr_preset = preset;
pub fn change_program(&mut self, program: ProgramDescriptor) {
if self.curr_program != program {
self.curr_program = program;
self.rebuild_matrix();
}
}
Expand All @@ -55,8 +58,8 @@ impl ChannelSoundfont {
// if a preset/instr. has regions in any bank other than 0, all missing banks will be muted.
// For drum patches the same applies with bank and preset switched.

let bank = self.curr_bank;
let preset = self.curr_preset;
let bank = self.curr_program.bank;
let preset = self.curr_program.preset;

for k in 0..128u8 {
for v in 0..128u8 {
Expand Down
4 changes: 4 additions & 0 deletions core/src/channel/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ pub enum ChannelConfigEvent {

/// Sets the layer count for the soundfont
SetLayerCount(Option<usize>),

/// Controls whether the channel will be standard or percussion.
/// Setting to `true` will make the channel only use percussion patches.
SetPercussionMode(bool),
}

/// MIDI events for a channel.
Expand Down
32 changes: 6 additions & 26 deletions core/src/channel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,10 @@ struct ControlEventData {
cutoff: Option<f32>,
resonance: Option<f32>,
expression: ValueLerp,
preset: u8,
bank: u8,
}

impl ControlEventData {
pub fn new_defaults(sample_rate: u32, drums_only: bool) -> Self {
pub fn new_defaults(sample_rate: u32) -> Self {
ControlEventData {
selected_lsb: -1,
selected_msb: -1,
Expand All @@ -114,8 +112,6 @@ impl ControlEventData {
cutoff: None,
resonance: None,
expression: ValueLerp::new(1.0, sample_rate),
preset: 0,
bank: if drums_only { 128 } else { 0 },
}
}
}
Expand All @@ -130,19 +126,13 @@ pub struct ChannelInitOptions {
///
/// Default: `false`
pub fade_out_killing: bool,

/// If set to true, the channel will only use drum patches.
///
/// Default: `false`
pub drums_only: bool,
}

#[allow(clippy::derivable_impls)]
impl Default for ChannelInitOptions {
fn default() -> Self {
Self {
fade_out_killing: false,
drums_only: false,
}
}
}
Expand Down Expand Up @@ -173,7 +163,6 @@ pub struct VoiceChannel {
threadpool: Option<Arc<rayon::ThreadPool>>,

stream_params: AudioStreamParams,
options: ChannelInitOptions,

/// The helper struct for keeping track of MIDI control event data
control_event_data: ControlEventData,
Expand Down Expand Up @@ -216,12 +205,8 @@ impl VoiceChannel {
threadpool,

stream_params,
options,

control_event_data: ControlEventData::new_defaults(
stream_params.sample_rate,
options.drums_only,
),
control_event_data: ControlEventData::new_defaults(stream_params.sample_rate),
voice_control_data: VoiceControlData::new_defaults(),

cutoff: MultiChannelBiQuad::new(
Expand Down Expand Up @@ -273,9 +258,7 @@ impl VoiceChannel {
}

fn push_key_events_and_render(&mut self, out: &mut [f32]) {
self.params
.channel_sf
.change_program(self.control_event_data.bank, self.control_event_data.preset);
self.params.load_program();

out.fill(0.0);
match self.threadpool.as_ref() {
Expand Down Expand Up @@ -332,9 +315,7 @@ impl VoiceChannel {
ControlEvent::Raw(controller, value) => match controller {
0x00 => {
// Bank select
if !self.options.drums_only {
self.control_event_data.bank = value;
}
self.params.set_bank(value);
}
0x64 => {
self.control_event_data.selected_lsb = value as i8;
Expand Down Expand Up @@ -563,7 +544,7 @@ impl VoiceChannel {
self.process_control_event(control);
}
ChannelAudioEvent::ProgramChange(preset) => {
self.control_event_data.preset = preset;
self.params.set_preset(preset);
}
},
ChannelEvent::Config(config) => self.params.process_config_event(config),
Expand All @@ -579,8 +560,7 @@ impl VoiceChannel {
}

fn reset_control(&mut self) {
self.control_event_data =
ControlEventData::new_defaults(self.stream_params.sample_rate, self.options.drums_only);
self.control_event_data = ControlEventData::new_defaults(self.stream_params.sample_rate);
self.voice_control_data = VoiceControlData::new_defaults();
self.process_event(ChannelEvent::Audio(ChannelAudioEvent::ProgramChange(0)));
self.propagate_voice_controls();
Expand Down
29 changes: 28 additions & 1 deletion core/src/channel/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use std::sync::{atomic::AtomicU64, Arc};

use crate::AudioStreamParams;

use super::{channel_sf::ChannelSoundfont, ChannelConfigEvent};
use super::{
channel_sf::{ChannelSoundfont, ProgramDescriptor},
ChannelConfigEvent,
};

/// Holds the statistics for an instance of VoiceChannel.
#[derive(Debug, Clone)]
Expand All @@ -24,6 +27,7 @@ pub struct VoiceChannelParams {
pub stats: VoiceChannelStats,
pub layers: Option<usize>,
pub channel_sf: ChannelSoundfont,
pub program: ProgramDescriptor,
pub constant: VoiceChannelConst,
}

Expand All @@ -48,6 +52,7 @@ impl VoiceChannelParams {
stats: VoiceChannelStats::new(),
layers: Some(4),
channel_sf,
program: Default::default(),
constant: VoiceChannelConst { stream_params },
}
}
Expand All @@ -60,8 +65,30 @@ impl VoiceChannelParams {
ChannelConfigEvent::SetLayerCount(count) => {
self.layers = count;
}
ChannelConfigEvent::SetPercussionMode(set) => {
if set {
self.program.bank = 128;
} else {
self.program.bank = 0;
}
self.channel_sf.change_program(self.program);
}
}
}

pub fn set_bank(&mut self, bank: u8) {
if self.program.bank != 128 {
self.program.bank = bank.min(127);
}
}

pub fn set_preset(&mut self, preset: u8) {
self.program.preset = preset.min(127);
}

pub fn load_program(&mut self) {
self.channel_sf.change_program(self.program);
}
}

impl VoiceChannelStatsReader {
Expand Down
12 changes: 3 additions & 9 deletions core/src/channel_group/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,11 @@ pub struct ChannelGroupConfig {
/// See the `ChannelInitOptions` documentation for more information.
pub channel_init_options: ChannelInitOptions,

/// Amount of VoiceChannel objects to be created
/// (Number of MIDI channels)
/// The MIDI 1 spec uses 16 channels.
/// Amount of VoiceChannel objects to be created (Number of MIDI channels).
/// The MIDI 1 spec uses 16 channels. If the channel count is 16 or
/// greater, then MIDI channel 10 will be set as the percussion channel.
pub channel_count: u32,

/// A vector which specifies which of the created channels (indexes) will be used for drums.
///
/// For example in a conventional 16 MIDI channel setup where channel 10 is used for
/// drums, the vector would be set as vec!\[9\] (counting from 0).
pub drums_channels: Vec<u32>,

/// Parameters of the output audio.
/// See the `AudioStreamParams` documentation for more information.
pub audio_params: AudioStreamParams,
Expand Down
16 changes: 6 additions & 10 deletions core/src/channel_group/events.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
use crate::channel::{ChannelAudioEvent, ChannelConfigEvent};
use crate::channel::ChannelEvent;

/// Wrapper enum for various events to be sent to a MIDI synthesizer.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum SynthEvent {
/// An audio event to be sent to the specified channel.
/// See `ChannelAudioEvent` documentation for more information.
Channel(u32, ChannelAudioEvent),
/// A channel event to be sent to the specified channel.
/// See `ChannelEvent` documentation for more information.
Channel(u32, ChannelEvent),

/// An audio event to be sent to all available channels.
/// A channel event to be sent to all available channels.
/// See `ChannelAudioEvent` documentation for more information.
AllChannels(ChannelAudioEvent),

/// Configuration event for all channels.
/// See `ChannelConfigEvent` documentation for more information.
ChannelConfig(ChannelConfigEvent),
AllChannels(ChannelEvent),
}
56 changes: 32 additions & 24 deletions core/src/channel_group/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::sync::Arc;

use crate::{
channel::{ChannelAudioEvent, ChannelEvent, VoiceChannel},
channel::{ChannelAudioEvent, ChannelConfigEvent, ChannelEvent, VoiceChannel},
helpers::{prepapre_cache_vec, sum_simd},
AudioPipe, AudioStreamParams,
};
Expand Down Expand Up @@ -59,19 +59,22 @@ impl ChannelGroup {
),
};

for i in 0..config.channel_count {
let mut init = config.channel_init_options;
init.drums_only = config.drums_channels.clone().into_iter().any(|c| c == i);

for _ in 0..config.channel_count {
channels.push(VoiceChannel::new(
init,
config.channel_init_options,
config.audio_params,
channel_pool.clone(),
));
channel_events_cache.push(Vec::new());
sample_cache_vecs.push(Vec::new());
}

if config.channel_count >= 16 {
channels[9].push_events_iter(std::iter::once(ChannelEvent::Config(
ChannelConfigEvent::SetPercussionMode(true),
)))
}

Self {
thread_pool: group_pool,
cached_event_count: 0,
Expand All @@ -86,27 +89,32 @@ impl ChannelGroup {
/// See the `SynthEvent` documentation for more information.
pub fn send_event(&mut self, event: SynthEvent) {
match event {
SynthEvent::Channel(channel, event) => {
self.channel_events_cache[channel as usize].push(event);
self.cached_event_count += 1;
if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
self.flush_events();
}
}
SynthEvent::AllChannels(event) => {
for channel in self.channel_events_cache.iter_mut() {
channel.push(event);
SynthEvent::Channel(channel, event) => match event {
ChannelEvent::Audio(e) => {
self.channel_events_cache[channel as usize].push(e);
self.cached_event_count += 1;
if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
self.flush_events();
}
}
self.cached_event_count += self.channel_events_cache.len() as u32;
if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
self.flush_events();
ChannelEvent::Config(_) => self.channels[channel as usize].process_event(event),
},
SynthEvent::AllChannels(event) => match event {
ChannelEvent::Audio(e) => {
for channel in self.channel_events_cache.iter_mut() {
channel.push(e);
}
self.cached_event_count += self.channel_events_cache.len() as u32;
if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
self.flush_events();
}
}
}
SynthEvent::ChannelConfig(config) => {
for channel in self.channels.iter_mut() {
channel.process_event(ChannelEvent::Config(config.clone()));
ChannelEvent::Config(_) => {
for channel in self.channels.iter_mut() {
channel.process_event(event.clone());
}
}
}
},
}
}

Expand Down
6 changes: 3 additions & 3 deletions realtime/examples/bench.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::time::{Duration, Instant};
use xsynth_core::channel::ChannelAudioEvent;
use xsynth_core::channel::{ChannelAudioEvent, ChannelEvent};

use xsynth_realtime::{RealtimeSynth, SynthEvent};

Expand All @@ -12,13 +12,13 @@ fn main() {
for _ in 0..100 {
synth.send_event(SynthEvent::Channel(
0,
ChannelAudioEvent::NoteOn { key: 0, vel: 5 },
ChannelEvent::Audio(ChannelAudioEvent::NoteOn { key: 0, vel: 5 }),
));
}
for _ in 0..100 {
synth.send_event(SynthEvent::Channel(
0,
ChannelAudioEvent::NoteOff { key: 0 },
ChannelEvent::Audio(ChannelAudioEvent::NoteOff { key: 0 }),
));
}
}
Expand Down
Loading

0 comments on commit cd2d91c

Please sign in to comment.