@@ -45,6 +45,67 @@ pub struct DspMessage {
4545 pub channel_audio_data : Vec < Vec < f32 > > ,
4646}
4747
48+ fn is_relevant_audio_device ( name : & str ) -> bool {
49+ let name_lower = name. to_lowercase ( ) ;
50+ // Filter out dummy/silent devices
51+ if name_lower == "null" {
52+ return false ;
53+ }
54+ // Filter out virtual multi-channel surround setups (not suitable for normal stereo playback/recording)
55+ if name_lower. contains ( "surround" ) {
56+ return false ;
57+ }
58+ // Filter out internal mixer and snooping plugins
59+ if name_lower. starts_with ( "dmix" ) || name_lower. starts_with ( "dsnoop" ) {
60+ return false ;
61+ }
62+ // Filter out legacy or internal virtual interfaces/plugins
63+ if name_lower. starts_with ( "adsp" ) {
64+ return false ;
65+ }
66+ if name_lower. starts_with ( "speex" ) || name_lower. contains ( "speexrate" ) {
67+ return false ;
68+ }
69+ if name_lower. contains ( "upmix" ) || name_lower. contains ( "vdownmix" ) {
70+ return false ;
71+ }
72+ if name_lower. contains ( "samplerate" ) || name_lower. contains ( "lavrate" ) {
73+ return false ;
74+ }
75+ true
76+ }
77+
78+ pub fn get_available_audio_devices ( mic : bool ) -> Vec < String > {
79+ let host = cpal:: default_host ( ) ;
80+ let devices = if mic {
81+ host. input_devices ( )
82+ } else {
83+ host. output_devices ( )
84+ } ;
85+
86+ let mut names = Vec :: new ( ) ;
87+ if let Ok ( devices) = devices {
88+ for d in devices {
89+ if let Ok ( name) = d. name ( ) {
90+ if is_relevant_audio_device ( & name) {
91+ names. push ( name) ;
92+ }
93+ }
94+ }
95+ }
96+ names
97+ }
98+
99+ pub fn get_default_audio_device_name ( mic : bool ) -> Option < String > {
100+ let host = cpal:: default_host ( ) ;
101+ let default_device = if mic {
102+ host. default_input_device ( )
103+ } else {
104+ host. default_output_device ( )
105+ } ;
106+ default_device. and_then ( |d| d. name ( ) . ok ( ) )
107+ }
108+
48109pub fn spawn_dsp_thread (
49110 rx : Receiver < DspMessage > ,
50111 shared_state : Arc < Mutex < AppState > > ,
@@ -191,6 +252,7 @@ pub fn spawn_dsp_thread(
191252 }
192253 let wave_clone = state. raw_waveform . clone ( ) ;
193254 state. waveform_history . push_back ( wave_clone) ;
255+ state. waveform_history_push_count += 1 ;
194256 last_waveform_push = now;
195257 }
196258
@@ -380,7 +442,8 @@ struct MidiEvent {
380442}
381443
382444struct MidiSource {
383- sequencer : MidiFileSequencer ,
445+ sequencer : Option < MidiFileSequencer > ,
446+ pos_silent : f64 ,
384447 events : Vec < MidiEvent > ,
385448 event_idx : usize ,
386449 channel_vus : Vec < f32 > ,
@@ -398,17 +461,34 @@ unsafe impl Send for MidiSource {}
398461
399462impl MidiSource {
400463 pub fn new ( file_path : & str , soundfont_path : & str , sample_rate : i32 ) -> anyhow:: Result < Self > {
401- let mut sf2_file = File :: open ( soundfont_path) ?;
402- let sf2 = Arc :: new ( SoundFont :: new ( & mut sf2_file) . map_err ( |e| anyhow:: anyhow!( "SoundFont error: {:?}" , e) ) ?) ;
403- let settings = SynthesizerSettings :: new ( sample_rate) ;
404- let synth = Synthesizer :: new ( & sf2, & settings) . map_err ( |e| anyhow:: anyhow!( "Synth error: {:?}" , e) ) ?;
405- let mut sequencer = MidiFileSequencer :: new ( synth) ;
464+ let mut artist_suffix = "" ;
465+ let sf2_file_opt = File :: open ( soundfont_path) . ok ( ) ;
466+ let mut sequencer = if let Some ( mut sf2_file) = sf2_file_opt {
467+ if let Ok ( sf2) = SoundFont :: new ( & mut sf2_file) {
468+ let sf2 = Arc :: new ( sf2) ;
469+ let settings = SynthesizerSettings :: new ( sample_rate) ;
470+ if let Ok ( synth) = Synthesizer :: new ( & sf2, & settings) {
471+ Some ( MidiFileSequencer :: new ( synth) )
472+ } else {
473+ artist_suffix = " (No SoundFont)" ;
474+ None
475+ }
476+ } else {
477+ artist_suffix = " (No SoundFont)" ;
478+ None
479+ }
480+ } else {
481+ artist_suffix = " (No SoundFont)" ;
482+ None
483+ } ;
406484
407485 let mut midi_file = File :: open ( file_path) ?;
408486 let midi = Arc :: new ( MidiFile :: new ( & mut midi_file) . map_err ( |e| anyhow:: anyhow!( "Midi parse error: {:?}" , e) ) ?) ;
409487
410488 let duration = midi. get_length ( ) ;
411- sequencer. play ( & midi, false ) ;
489+ if let Some ( seq) = & mut sequencer {
490+ seq. play ( & midi, false ) ;
491+ }
412492
413493 let data = std:: fs:: read ( file_path) ?;
414494 let smf = Smf :: parse ( & data) . map_err ( |e| anyhow:: anyhow!( "Midly parse error: {:?}" , e) ) ?;
@@ -508,9 +588,13 @@ impl MidiSource {
508588 if artist. is_empty ( ) {
509589 artist = "Unknown MIDI" . to_string ( ) ;
510590 }
591+ if !artist_suffix. is_empty ( ) {
592+ artist. push_str ( artist_suffix) ;
593+ }
511594
512595 Ok ( Self {
513596 sequencer,
597+ pos_silent : 0.0 ,
514598 events : parsed_events,
515599 event_idx : 0 ,
516600 channel_vus : vec ! [ 0.0 ; 16 ] ,
@@ -530,18 +614,34 @@ impl AudioSource for MidiSource {
530614 fn read_frames ( & mut self , hardware_channels : usize , _sample_rate : u32 , output : & mut [ f32 ] ) -> usize {
531615 let frames_to_render = output. len ( ) / hardware_channels;
532616
533- if self . left_buf . len ( ) < frames_to_render {
534- self . left_buf . resize ( frames_to_render, 0.0 ) ;
535- self . right_buf . resize ( frames_to_render, 0.0 ) ;
536- }
537-
538- self . sequencer . render ( & mut self . left_buf [ ..frames_to_render] , & mut self . right_buf [ ..frames_to_render] ) ;
617+ let pos = if let Some ( ref mut seq) = self . sequencer {
618+ if self . left_buf . len ( ) < frames_to_render {
619+ self . left_buf . resize ( frames_to_render, 0.0 ) ;
620+ self . right_buf . resize ( frames_to_render, 0.0 ) ;
621+ }
622+ seq. render ( & mut self . left_buf [ ..frames_to_render] , & mut self . right_buf [ ..frames_to_render] ) ;
623+ for i in 0 ..frames_to_render {
624+ let l = self . left_buf [ i] ;
625+ let r = self . right_buf [ i] ;
626+ output[ i * hardware_channels] = l;
627+ if hardware_channels > 1 {
628+ output[ i * hardware_channels + 1 ] = r;
629+ for j in 2 ..hardware_channels {
630+ output[ i * hardware_channels + j] = 0.0 ;
631+ }
632+ }
633+ }
634+ seq. get_position ( )
635+ } else {
636+ output. fill ( 0.0 ) ;
637+ self . pos_silent = ( self . pos_silent + frames_to_render as f64 / _sample_rate as f64 ) . min ( self . duration ) ;
638+ self . pos_silent
639+ } ;
539640
540641 for c in 0 ..16 {
541642 self . channel_vus [ c] = ( self . channel_vus [ c] - 0.02 ) . max ( 0.0 ) ;
542643 }
543644
544- let pos = self . sequencer . get_position ( ) ;
545645 while self . event_idx < self . events . len ( ) && self . events [ self . event_idx ] . time_sec <= pos {
546646 let ev = & self . events [ self . event_idx ] ;
547647 if ev. is_note_on {
@@ -553,38 +653,41 @@ impl AudioSource for MidiSource {
553653 self . event_idx += 1 ;
554654 }
555655
556- for i in 0 ..frames_to_render {
557- let l = self . left_buf [ i] ;
558- let r = self . right_buf [ i] ;
559-
560- output[ i * hardware_channels] = l;
561- if hardware_channels > 1 {
562- output[ i * hardware_channels + 1 ] = r;
563- for j in 2 ..hardware_channels {
564- output[ i * hardware_channels + j] = 0.0 ;
565- }
566- }
567- }
656+ let is_end = if let Some ( ref seq) = self . sequencer {
657+ seq. end_of_sequence ( )
658+ } else {
659+ pos >= self . duration
660+ } ;
568661
569- if self . sequencer . end_of_sequence ( ) {
662+ if is_end {
570663 0
571664 } else {
572665 frames_to_render
573666 }
574667 }
575668
576669 fn get_duration_seconds ( & mut self ) -> f64 { self . duration }
577- fn get_position_seconds ( & mut self ) -> f64 { self . sequencer . get_position ( ) }
670+ fn get_position_seconds ( & mut self ) -> f64 {
671+ if let Some ( ref seq) = self . sequencer {
672+ seq. get_position ( )
673+ } else {
674+ self . pos_silent
675+ }
676+ }
578677
579678 fn set_position_seconds ( & mut self , pos : f64 ) {
580- if pos < self . get_position_seconds ( ) {
581- self . sequencer . play ( & self . midi_file , false ) ;
582- }
583-
584- let mut trash_left = vec ! [ 0.0 ; 8192 ] ;
585- let mut trash_right = vec ! [ 0.0 ; 8192 ] ;
586- while self . sequencer . get_position ( ) < pos && !self . sequencer . end_of_sequence ( ) {
587- self . sequencer . render ( & mut trash_left, & mut trash_right) ;
679+ if let Some ( ref mut seq) = self . sequencer {
680+ if pos < seq. get_position ( ) {
681+ seq. play ( & self . midi_file , false ) ;
682+ }
683+
684+ let mut trash_left = vec ! [ 0.0 ; 8192 ] ;
685+ let mut trash_right = vec ! [ 0.0 ; 8192 ] ;
686+ while seq. get_position ( ) < pos && !seq. end_of_sequence ( ) {
687+ seq. render ( & mut trash_left, & mut trash_right) ;
688+ }
689+ } else {
690+ self . pos_silent = pos. clamp ( 0.0 , self . duration ) ;
588691 }
589692
590693 self . event_idx = 0 ;
@@ -621,7 +724,7 @@ impl AudioSource for MidiSource {
621724
622725 fn get_current_order ( & mut self ) -> i32 { 0 }
623726 fn get_current_row ( & mut self ) -> i32 {
624- ( self . sequencer . get_position ( ) * ( self . tempo as f64 / 60.0 ) * 4.0 ) as i32
727+ ( self . get_position_seconds ( ) * ( self . tempo as f64 / 60.0 ) * 4.0 ) as i32
625728 }
626729
627730 fn get_tracker_channels ( & mut self ) -> Option < i32 > { Some ( 16 ) }
@@ -1443,7 +1546,7 @@ pub fn start_audio_thread(file_path: &str, mic: bool, shared_state: Arc<Mutex<Ap
14431546 _ => & codec_name,
14441547 } . to_string ( ) ;
14451548
1446- let video_suffix = if has_video { " (Video stream available)" } else { "" } ;
1549+ let video_suffix = if has_video { " (Video available: 'v' to view )" } else { "" } ;
14471550
14481551 {
14491552 let mut state = shared_state. lock ( ) . unwrap ( ) ;
@@ -1476,8 +1579,52 @@ pub fn start_audio_thread(file_path: &str, mic: bool, shared_state: Arc<Mutex<Ap
14761579 target_channels = 2 ;
14771580 }
14781581
1582+ let selected_device_name = {
1583+ let state = shared_state. lock ( ) . unwrap ( ) ;
1584+ state. selected_audio_device . clone ( )
1585+ } ;
1586+
1587+ let device = if mic {
1588+ let mut dev = None ;
1589+ if let Some ( ref name) = selected_device_name {
1590+ if let Ok ( devices) = host. input_devices ( ) {
1591+ for d in devices {
1592+ if let Ok ( d_name) = d. name ( ) {
1593+ if & d_name == name {
1594+ dev = Some ( d) ;
1595+ break ;
1596+ }
1597+ }
1598+ }
1599+ }
1600+ }
1601+ if let Some ( d) = dev {
1602+ d
1603+ } else {
1604+ host. default_input_device ( ) . context ( "No input device available" ) ?
1605+ }
1606+ } else {
1607+ let mut dev = None ;
1608+ if let Some ( ref name) = selected_device_name {
1609+ if let Ok ( devices) = host. output_devices ( ) {
1610+ for d in devices {
1611+ if let Ok ( d_name) = d. name ( ) {
1612+ if & d_name == name {
1613+ dev = Some ( d) ;
1614+ break ;
1615+ }
1616+ }
1617+ }
1618+ }
1619+ }
1620+ if let Some ( d) = dev {
1621+ d
1622+ } else {
1623+ host. default_output_device ( ) . context ( "No output device available" ) ?
1624+ }
1625+ } ;
1626+
14791627 let supported_config = if mic {
1480- let device = host. default_input_device ( ) . context ( "No input device available" ) ?;
14811628 let supported_configs_range = device. supported_input_configs ( ) . context ( "error while querying input configs" ) ?;
14821629 supported_configs_range
14831630 . into_iter ( )
@@ -1492,9 +1639,7 @@ pub fn start_audio_thread(file_path: &str, mic: bool, shared_state: Arc<Mutex<Ap
14921639 . or_else ( || device. default_input_config ( ) . ok ( ) )
14931640 . context ( "No supported config?!" ) ?
14941641 } else {
1495- let device = host. default_output_device ( ) . context ( "No output device available" ) ?;
14961642 let supported_configs_range = device. supported_output_configs ( ) . context ( "error while querying output configs" ) ?;
1497-
14981643 let mut configs: Vec < _ > = supported_configs_range
14991644 . filter ( |c| {
15001645 c. sample_format ( ) == cpal:: SampleFormat :: F32 || c. sample_format ( ) == cpal:: SampleFormat :: I16
@@ -1529,12 +1674,6 @@ pub fn start_audio_thread(file_path: &str, mic: bool, shared_state: Arc<Mutex<Ap
15291674 . context ( "No supported config?!" ) ?
15301675 } ;
15311676
1532- let device = if mic {
1533- host. default_input_device ( ) . context ( "No input device available" ) ?
1534- } else {
1535- host. default_output_device ( ) . context ( "No output device available" ) ?
1536- } ;
1537-
15381677 let config: cpal:: StreamConfig = supported_config. clone ( ) . into ( ) ;
15391678 let ( tx, rx) = bounded :: < DspMessage > ( 32 ) ;
15401679
0 commit comments