1
- use projectm:: core:: ProjectM ;
2
- use sdl3:: audio:: {
3
- AudioDevice , AudioDeviceID , AudioRecordingCallback , AudioSpec , AudioStreamWithCallback ,
4
- } ;
1
+ use sdl3:: audio:: { AudioDevice , AudioDeviceID , AudioSpec , AudioStream } ;
2
+ use std:: io:: Read ;
5
3
6
4
use super :: config:: FrameRate ;
7
5
use super :: ProjectMWrapped ;
8
6
9
- use std:: rc:: Rc ;
10
-
11
7
// let the user cycle through audio devices
12
8
type AudioDeviceIndex = usize ;
13
9
14
10
type SampleFormat = f32 ; // format of audio samples
15
11
16
12
pub struct Audio {
17
13
audio_subsystem : sdl3:: AudioSubsystem ,
18
-
19
- current_recording_device : Option < AudioDevice > ,
20
- capture_stream : Option < Box < AudioStreamWithCallback < AudioCaptureCallback > > > ,
14
+ recording_stream : Option < Box < AudioStream > > ,
21
15
is_capturing : bool ,
22
-
23
16
frame_rate : Option < FrameRate > ,
24
17
projectm : ProjectMWrapped ,
18
+ current_device_id : Option < AudioDeviceID > ,
25
19
}
26
20
27
- /// Wrapper around the audio subsystem to capture audio and pass it to projectM.
21
+ /// Wrapper around the audio subsystem to record audio and pass it to projectM.
28
22
impl Audio {
29
23
pub fn new ( sdl_context : & sdl3:: Sdl , projectm : ProjectMWrapped ) -> Self {
30
24
let audio_subsystem = sdl_context. audio ( ) . unwrap ( ) ;
@@ -36,9 +30,9 @@ impl Audio {
36
30
Self {
37
31
is_capturing : false ,
38
32
audio_subsystem,
39
- current_recording_device : None ,
40
33
frame_rate : None ,
41
- capture_stream : None ,
34
+ current_device_id : None ,
35
+ recording_stream : None ,
42
36
projectm,
43
37
}
44
38
}
@@ -49,7 +43,7 @@ impl Audio {
49
43
self . frame_rate = frame_rate. into ( ) ;
50
44
51
45
#[ cfg( not( feature = "dummy_audio" ) ) ]
52
- self . begin_audio_capture ( self . get_default_recording_device ( ) . id ( ) ) ;
46
+ self . begin_audio_capture ( None ) ;
53
47
}
54
48
55
49
pub fn list_devices ( & self ) {
@@ -62,124 +56,145 @@ impl Audio {
62
56
}
63
57
64
58
/// Start capturing audio from device_id.
65
- pub fn capture_device ( & mut self , device_id : AudioDeviceID ) {
59
+ pub fn begin_audio_capture ( & mut self , device_id : Option < AudioDeviceID > ) {
60
+ // stop capturing from current stream/device
66
61
self . stop_audio_capture ( ) ;
67
- self . begin_audio_capture ( device_id) ;
68
- }
69
-
70
- fn get_default_recording_device ( & self ) -> AudioDevice {
71
- self . audio_subsystem . default_recording_device ( )
72
- }
73
62
74
- /// Select a new audio device and start capturing audio from it.
75
- pub fn open_next_device ( & mut self ) {
76
- let device_list = self . get_device_list ( ) ;
77
- let current_device = self . current_recording_device . as_ref ( ) . unwrap ( ) ;
78
- let current_device_id = current_device. id ( ) ;
79
- let current_device_index = device_list
80
- . iter ( )
81
- . position ( |d| d. eq ( & current_device_id) )
82
- . unwrap ( ) ;
83
- let next_device_index = ( current_device_index + 1 ) % device_list. len ( ) ;
84
- let next_device_id = device_list[ next_device_index] ;
85
- self . capture_device ( next_device_id) ;
86
- }
87
-
88
- fn get_device_list ( & self ) -> Vec < AudioDeviceID > {
89
- let audio_subsystem = & self . audio_subsystem ;
90
-
91
- audio_subsystem. audio_recording_device_ids ( ) . unwrap ( )
92
- }
93
-
94
- pub fn begin_audio_capture ( & mut self , device_id : AudioDeviceID ) {
95
63
let sample_rate: u32 = 44100 ;
96
64
let frame_rate = self . frame_rate . unwrap ( ) ;
97
65
98
66
// how many samples to capture at a time
99
67
// should be enough for 1 frame or less
100
68
// should not be larger than max_samples / channels
101
- let max_samples: usize = ProjectM :: pcm_get_max_samples ( ) . try_into ( ) . unwrap ( ) ;
102
- let samples_per_frame = ( sample_rate / frame_rate) as usize ;
103
- let buffer_size = std:: cmp:: min ( max_samples / 2 , samples_per_frame) ;
104
- println ! ( "Capturing audio from device {}" , device_id. name( ) ) ;
105
- println ! ( "Buffer size: {}" , buffer_size) ;
69
+ // let max_samples: usize = ProjectM::pcm_get_max_samples().try_into().unwrap();
70
+ // let samples_per_frame = (sample_rate / frame_rate) as usize;
71
+ // let buffer_size = std::cmp::min(max_samples / 2, samples_per_frame);
72
+ // println!("Buffer size: {}", buffer_size);
106
73
107
74
let desired_spec = AudioSpec {
108
75
freq : Some ( sample_rate. try_into ( ) . unwrap ( ) ) ,
109
76
channels : Some ( 2 ) ,
110
77
format : Some ( sdl3:: audio:: AudioFormat :: f32_sys ( ) ) ,
111
78
} ;
112
79
113
- // open audio device for capture
114
- let device = AudioDevice :: new ( device_id) ;
115
- let audio_stream = device
116
- // move this to open_recording_device
117
- . open_recording_stream_with_callback (
118
- & desired_spec,
119
- AudioCaptureCallback {
120
- pm : Rc :: clone ( & self . projectm ) ,
121
- } ,
122
- )
123
- . unwrap ( ) ;
80
+ // open audio device for capture (use default device if none specified)
81
+ let device_id = ( device_id
82
+ . or_else ( || Some ( self . get_default_recording_device ( ) . id ( ) ) )
83
+ . unwrap ( ) ) ;
84
+
85
+ let audio_stream = match AudioStream :: open_device_stream ( device_id, Some ( & desired_spec) ) {
86
+ Ok ( stream) => stream,
87
+ Err ( e) => {
88
+ println ! ( "Failed to open audio stream: {}" , e) ;
89
+ return ;
90
+ }
91
+ } ;
92
+ println ! ( "Capturing audio from device {:?}" , audio_stream) ;
93
+
94
+ let device_id = audio_stream. device_id ( ) ;
95
+ if device_id. is_none ( ) {
96
+ println ! ( "Failed to get begin audio capture: {:?}" , audio_stream) ;
97
+ return ;
98
+ }
124
99
125
100
// start capturing
126
101
audio_stream
127
102
. resume ( )
128
103
. expect ( "Failed to start audio capture" ) ;
129
104
130
105
// take ownership of device
131
- self . capture_stream = Some ( Box :: new ( audio_stream) ) ;
132
- self . current_recording_device = Some ( device ) ;
106
+ self . recording_stream = Some ( Box :: new ( audio_stream) ) ;
107
+ self . current_device_id = device_id ;
133
108
self . is_capturing = true ;
134
109
}
135
110
111
+ fn get_default_recording_device ( & self ) -> AudioDevice {
112
+ self . audio_subsystem . default_recording_device ( )
113
+ }
114
+
115
+ /// Select a new audio device and start capturing audio from it.
116
+ pub fn open_next_device ( & mut self ) {
117
+ let current_device_id = self . current_device_id ;
118
+ if current_device_id. is_none ( ) {
119
+ self . begin_audio_capture ( None ) ;
120
+ return ;
121
+ }
122
+ let current_device_id = current_device_id. unwrap ( ) ;
123
+
124
+ // get list of devices
125
+ let device_list = self . get_device_list ( ) ;
126
+
127
+ println ! ( "Device list: {:?}" , device_list) ;
128
+ println ! ( "Current device: {:?}" , current_device_id) ;
129
+
130
+ // find current device in list
131
+ let mut current_device_index = device_list. iter ( ) . position ( |d| d. eq ( & current_device_id) ) ;
132
+
133
+ // if current device not found, start from the beginning
134
+ if current_device_index. is_none ( ) {
135
+ println ! ( "Current device not found in device list" ) ;
136
+ self . begin_audio_capture ( None ) ;
137
+ return ;
138
+ }
139
+
140
+ // select next device
141
+ let next_device_index = ( current_device_index. unwrap ( ) + 1 ) % device_list. len ( ) ;
142
+ let next_device_id = device_list[ next_device_index] ;
143
+
144
+ // start capturing from next device
145
+ self . begin_audio_capture ( Some ( next_device_id) ) ;
146
+ }
147
+
148
+ fn get_device_list ( & self ) -> Vec < AudioDeviceID > {
149
+ let audio_subsystem = & self . audio_subsystem ;
150
+
151
+ audio_subsystem. audio_recording_device_ids ( ) . unwrap ( )
152
+ }
153
+
136
154
pub fn recording_device_name ( & self ) -> Option < String > {
137
- self . current_recording_device
138
- . as_ref ( )
139
- . map ( |device| device. name ( ) )
155
+ self . current_device_id . and_then ( |id| Some ( id. name ( ) ) )
140
156
}
141
157
142
158
pub fn stop_audio_capture ( & mut self ) {
143
- if self . current_recording_device . is_none ( ) {
159
+ let mut recording_stream = & mut self . recording_stream ;
160
+ if recording_stream. is_none ( ) {
144
161
return ;
145
162
}
146
163
147
- let current_device_name = self . recording_device_name ( ) ;
164
+ // take ownership of stream
165
+ let stream = recording_stream. take ( ) . unwrap ( ) ;
166
+
167
+ let current_device_name = stream. device_name ( ) ;
148
168
println ! (
149
169
"Stopping audio capture for device {}" ,
150
- current_device_name. unwrap_or ( "unknown" . to_string( ) )
170
+ current_device_name. unwrap_or_else ( || "unknown" . to_string( ) )
151
171
) ;
152
172
153
- // take ownership of device
154
- // capture device will be dropped when this function returns
155
- // and the audio callback will stop being called
156
- let device = self . capture_stream . take ( ) . unwrap ( ) ;
157
- device. pause ( ) . expect ( "Failed to stop audio capture" ) ;
158
-
173
+ // the recording device will be closed when the stream is dropped
159
174
self . is_capturing = false ;
160
- drop ( device ) ;
175
+ drop ( stream ) ;
161
176
}
162
177
}
163
178
164
- struct AudioCaptureCallback {
165
- // we need to keep a reference to the projectm instance to
166
- // add the audio data to it
167
- pm : ProjectMWrapped ,
168
- }
169
- unsafe impl Send for AudioCaptureCallback { }
170
- unsafe impl Sync for AudioCaptureCallback { }
171
-
172
- impl AudioRecordingCallback < SampleFormat > for AudioCaptureCallback {
173
- // we are receiving some chunk of audio data
174
- // we need to pass it to projectm
175
- fn callback ( & mut self , out : & [ SampleFormat ] ) {
176
- println ! ( "Received {} samples" , out. len( ) ) ;
177
- let mut out = out;
178
- let max_samples = ProjectM :: pcm_get_max_samples ( ) as usize ;
179
- if ( out. len ( ) > max_samples) {
180
- // remove some samples
181
- out = & out[ ..max_samples] ;
182
- }
183
- self . pm . pcm_add_float ( out. to_vec ( ) , 2 ) ;
184
- }
185
- }
179
+ // struct AudioCaptureCallback {
180
+ // // we need to keep a reference to the projectm instance to
181
+ // // add the audio data to it
182
+ // pm: ProjectMWrapped,
183
+ // }
184
+ // unsafe impl Send for AudioCaptureCallback {}
185
+ // unsafe impl Sync for AudioCaptureCallback {}
186
+ //
187
+ // impl AudioRecordingCallback<SampleFormat> for AudioCaptureCallback {
188
+ // // we are receiving some chunk of audio data
189
+ // // we need to pass it to projectm
190
+ // fn callback(&mut self, out: &[SampleFormat]) {
191
+ // println!("Received {} samples", out.len());
192
+ // let mut out = out;
193
+ // let max_samples = ProjectM::pcm_get_max_samples() as usize;
194
+ // if (out.len() > max_samples) {
195
+ // // remove some samples
196
+ // out = &out[..max_samples];
197
+ // }
198
+ // self.pm.pcm_add_float(out.to_vec(), 2);
199
+ // }
200
+ // }
0 commit comments