Skip to content

Commit

Permalink
added prelaminar MidiAudio and dependent
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderARodin committed Jan 2, 2024
1 parent 476e8b4 commit a21fa26
Show file tree
Hide file tree
Showing 10 changed files with 647 additions and 18 deletions.
19 changes: 11 additions & 8 deletions src/base_domik_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const VERS: &str = "v0.0.3";

use crate::raadbg::log;

use crate::midi_audio::MidiAudio;

pub struct BaseDomikView {
pub title: String,
Expand All @@ -19,18 +20,20 @@ impl BaseDomikView {
pressed: false,
}
}
pub fn updateUI(&mut self, ui: &mut egui::Ui, example_text: &mut String) {
pub fn updateUI(&mut self, ui: &mut egui::Ui, midi_audio: &mut MidiAudio) {
ui.label( format!("DoMiK {}", VERS) );
ui.separator();
ui.label( format!("device status: [active = {}]", midi_audio.is_active()) );
ui.horizontal( |ui| {
let btn = ui.button( "try to ??? TEXT" );
ui.label( format!(" <{}>", self.pressed) );
if btn.clicked(){
log::simple("clicked with PRESSURE!!!");
self.pressed = true;
let btn = ui.button("start");
if btn.clicked() {
let _res = midi_audio.start();
}
let btnStop = ui.button("stop");
if btnStop.clicked() {
midi_audio.stop();
}
});
ui.text_edit_singleline(example_text);
ui.separator();
ui.label( format!("just edited: [{}]", example_text) );
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod log_view;
mod root_app;
mod midi_audio;
mod midi_lib;
use root_app::RootApp;

mod base_domik_view;
Expand Down
36 changes: 36 additions & 0 deletions src/midi_audio/audio_device_parameters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use tinyaudio::prelude::OutputDeviceParameters;

use crate::raadbg::log;

pub struct AudioDeviceParameters {
pub sample_rate: usize,
pub block_size: usize,
pub blocks_count: usize,
}

impl AudioDeviceParameters {
pub fn new() -> Self {
Self {
sample_rate: 44100,
block_size: 441,
blocks_count: 8
}
}
pub fn get_output_device_parameters(&self) -> OutputDeviceParameters {
OutputDeviceParameters{
sample_rate: self.sample_rate,
channels_count: 2,
channel_sample_count: self.block_size * self.blocks_count
}
}
pub fn get_tick_time(&self) -> f32 {
let res = 2. * (self.block_size as f32) / (self.sample_rate as f32);
log::simple( format!("tick time = {res}").as_str() );
return res;
}
}
impl Default for AudioDeviceParameters {
fn default() -> Self {
Self::new()
}
}
96 changes: 87 additions & 9 deletions src/midi_audio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
use std::error::Error;
use tinyaudio::prelude::BaseAudioOutputDevice;

use std::sync::{Arc,Mutex};
use tinyaudio::prelude::{BaseAudioOutputDevice,run_output_device};

use crate::raadbg::log;
//use crate::midi_lib::MidiMessage;

mod audio_device_parameters;
use audio_device_parameters::AudioDeviceParameters;

mod render_holder;
use render_holder::RenderHolder;
pub use render_holder::SoundRender as SoundRender;

// // // // // // // //
// core
// CORE
// // // // // // // //

pub struct MidiAudio {
device: Option<
Box< dyn BaseAudioOutputDevice>
>,
params: AudioDeviceParameters,
device: Option< Box< dyn BaseAudioOutputDevice> >,
render_holder: Arc<Mutex<RenderHolder>>,
}

impl MidiAudio {
pub fn new() -> Self {
let res = Self {
params: Default::default(),
device: None,
render_holder: RenderHolder::new_arc_mutex(),
};
log::create("MidiAudio");
return res;
Expand All @@ -45,9 +54,8 @@ impl MidiAudio {
}else{
log::info("MidiAudio", "starting");
}
Ok(())
//self.refresh_tick_time();
//self.run_device_loop()
self.refresh_tick_time();
self.run_device_loop()
}
pub fn stop(&mut self) {
self.device = None;
Expand All @@ -68,4 +76,74 @@ impl MidiAudio {
// internal interface
// // // // // // // //

impl MidiAudio {
fn run_device_loop(&mut self) -> Result< (), Box<dyn Error>> {
let params = self.params.get_output_device_parameters();
let render_holder_clone = self.render_holder.clone();

let device = run_output_device( params, {
let render_holder = render_holder_clone;
let block_chunk = 2*self.params.block_size;
let mut left :Vec<f32> = vec![ 0_f32; self.params.block_size ];
let mut right:Vec<f32> = vec![ 0_f32; self.params.block_size ];
move |data: &mut [f32]| {
let mut render_holder_lock = render_holder.lock()
.expect("panic on locking render_holder_lock");
for chunk in data.chunks_mut(block_chunk) {
render_holder_lock.render( &mut left, &mut right );
for (i, l_sample) in left.iter().enumerate() {
chunk[i*2] = *l_sample;
chunk[i*2 + 1] = right[i];
}
}
}
});

match device {
Err(e) => {
let errmsg = format!("{:?}",e);
log::error("MidiAudio", &errmsg);
return Err(e)
},
Ok(running_device) => self.device = Some(running_device),
}
Ok(())
}

fn refresh_tick_time(&self) {
let mut holder_lock = self.render_holder.lock()
.expect("panic on lockin holder_lock");
holder_lock.tick_time = self.params.get_tick_time();
}
}


// // // // // // // //
// TESTS
// // // // // // // //

#[cfg(test)]
mod test {
use super::*;

#[test]
fn create_inactive() {
let audio = MidiAudio::new();
assert!(!audio.is_active());
}
#[test]
fn start_active() {
let mut audio = MidiAudio::new();
let _ = audio.start();
assert!(audio.is_active());
}
#[test]
fn start_stop() {
let mut audio = MidiAudio::new();
let _ = audio.start();
assert!(audio.is_active());
audio.stop();
assert!(!audio.is_active());
}
}

67 changes: 67 additions & 0 deletions src/midi_audio/render_holder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::sync::{Arc,Mutex};
use crate::raadbg::log;
use super::super::midi_lib::{MidiMessage,MidiReceiver,MidiSequence};


pub trait SoundRender: MidiReceiver + Sync + Send {
fn render(&mut self, left: &mut [f32], right: &mut [f32]);
fn get_as_midi_receiver(&mut self) -> &mut dyn MidiReceiver;
}

pub(crate) struct RenderHolder {
test_seq: MidiSequence,
pub(crate) tick_time: f32,
pub(crate) sound_render: Option< Arc<Mutex<dyn SoundRender>> >,
}
impl RenderHolder {
pub fn new_arc_mutex() -> Arc<Mutex<Self>> {
Arc::new(Mutex::new( Self::new() ))
}
pub fn new() -> Self {
let mut seq = MidiSequence::new();
seq.push( 0.0, &MidiMessage::NoteOn( 1,90,80) );
seq.push( 0.5, &MidiMessage::NoteOff(1,90,80) );
seq.push( 0., &MidiMessage::NoteOn( 1,91,80) );
seq.push( 0.5, &MidiMessage::NoteOff(1,91,80) );
seq.push( 0., &MidiMessage::NoteOn( 1,92,80) );
seq.push( 1., &MidiMessage::NoteOff(1,92,80) );
seq.push( 1., &MidiMessage::NoteOff(1,92,80) );
let res = Self{
test_seq: seq,
tick_time: 0.,
sound_render: None
};
log::create("RenderHolder");
return res;
}

pub fn render(&mut self, left: &mut [f32], right: &mut [f32]) {
match &self.sound_render {
None => {
for sample in left {
*sample = 0_f32;
}
for sample in right {
*sample = 0_f32;
}
},
Some(sound_render) => {
let mut locked_sound_render = sound_render.lock()
.expect("FATAL: can't lock SoundRender!");
let midi_recevier: &mut dyn MidiReceiver = locked_sound_render.get_as_midi_receiver();
self.test_seq.send_next_sequence( self.tick_time, midi_recevier );
locked_sound_render.render(left, right);
if self.test_seq.is_finished() {
self.test_seq.restart();
}
}
}
}
}

impl Drop for RenderHolder {
fn drop(&mut self) {
log::on_drop("RenderHolder");
}
}

Loading

0 comments on commit a21fa26

Please sign in to comment.