1
1
use projectm_rs:: core:: ProjectMHandle ;
2
2
use sdl2:: audio:: { AudioCallback , AudioDevice , AudioSpecDesired } ;
3
+ use std:: sync:: Arc ;
4
+ use std:: sync:: Mutex ;
3
5
4
6
use super :: config:: FrameRate ;
7
+ use super :: ProjectMWrapped ;
5
8
6
9
type AudioDeviceIndex = u32 ;
7
10
type SampleFormat = f32 ; // format of audio samples
@@ -16,12 +19,13 @@ pub struct Audio {
16
19
device_index : AudioDeviceIndex ,
17
20
is_capturing : bool ,
18
21
frame_rate : Option < FrameRate > ,
19
- capturing_device : Option < AudioDevice < AudioCaptureCallback > > ,
20
- projectm : ProjectMHandle ,
22
+ capturing_device : Option < Box < AudioDevice < AudioCaptureCallback > > > ,
23
+ projectm : ProjectMWrapped ,
21
24
}
22
25
26
+ /// Wrapper around the audio subsystem to capture audio and pass it to projectM.
23
27
impl Audio {
24
- pub fn new ( sdl_context : & sdl2:: Sdl , projectm : ProjectMHandle ) -> Self {
28
+ pub fn new ( sdl_context : & sdl2:: Sdl , projectm : ProjectMWrapped ) -> Self {
25
29
let audio_subsystem = sdl_context. audio ( ) . unwrap ( ) ;
26
30
27
31
Self {
@@ -52,7 +56,8 @@ impl Audio {
52
56
}
53
57
}
54
58
55
- pub fn set_device ( & mut self , device_index : AudioDeviceIndex ) {
59
+ /// Start capturing audio from device_index.
60
+ pub fn capture_device ( & mut self , device_index : AudioDeviceIndex ) {
56
61
self . stop_audio_capture ( ) ;
57
62
self . device_index = device_index;
58
63
self . begin_audio_capture ( ) ;
@@ -64,12 +69,14 @@ impl Audio {
64
69
. expect ( "could not get audio device" )
65
70
}
66
71
72
+ /// Select a new audio device and start capturing audio from it.
67
73
pub fn open_next_device ( & mut self ) {
68
74
let device_list = self . get_device_list ( ) ;
69
75
let current_device_index = self . device_index ;
70
76
71
- let next_device_index = current_device_index + 1 % device_list. len ( ) as AudioDeviceIndex ;
72
- self . set_device ( next_device_index) ;
77
+ let next_device_index = ( current_device_index + 1 ) % device_list. len ( ) as AudioDeviceIndex ;
78
+ println ! ( "Opening next device: {}" , next_device_index) ;
79
+ self . capture_device ( next_device_index) ;
73
80
}
74
81
75
82
fn get_device_list ( & self ) -> Vec < AudioCaptureDevice > {
@@ -96,66 +103,75 @@ impl Audio {
96
103
let sample_rate: u32 = 44100 ;
97
104
let frame_rate = self . frame_rate . unwrap ( ) ;
98
105
99
- // should be enough for 1 frame
100
- let buffer_size = ( sample_rate / frame_rate) as u16 ;
106
+ // how many samples to capture at a time
107
+ // should be enough for 1 frame or less
108
+ // should not be larger than max_samples / channels
109
+ let max_samples: usize = projectm_rs:: core:: Projectm :: pcm_get_max_samples ( )
110
+ . try_into ( )
111
+ . unwrap ( ) ;
112
+ let samples_per_frame = ( sample_rate / frame_rate) as usize ;
113
+ let buffer_size = std:: cmp:: min ( max_samples / 2 , samples_per_frame) ;
114
+ println ! ( "Buffer size: {}" , buffer_size) ;
101
115
102
116
let desired_spec = AudioSpecDesired {
103
117
freq : Some ( sample_rate. try_into ( ) . unwrap ( ) ) ,
104
118
channels : Some ( 2 ) ,
105
- samples : Some ( buffer_size) ,
119
+ samples : Some ( buffer_size. try_into ( ) . unwrap ( ) ) ,
106
120
} ;
107
121
108
- let audio_device = self
122
+ // open audio device for capture
123
+ let device_name = self . get_current_device_name ( ) ;
124
+ let audio_device = match self
109
125
. audio_subsystem // sdl
110
- . open_capture ( None , & desired_spec, |_spec| {
111
- println ! (
112
- "Beginning audio capture for device {}" ,
113
- self . get_current_device_name( )
114
- ) ;
126
+ . open_capture ( device_name. as_str ( ) , & desired_spec, |_spec| {
127
+ println ! ( "Beginning audio capture for device {}" , device_name) ;
115
128
116
129
// print spec
117
130
println ! ( "Audio Spec: {:?}" , _spec) ;
118
131
119
132
// return callback fn
120
133
AudioCaptureCallback {
121
- pm : self . projectm ,
122
- // spec,
123
- // buffer_size,
124
- // buffer: vec![0; buffer_size as usize],
125
- // position: 0,
134
+ pm : self . projectm . clone ( ) ,
126
135
}
127
- } )
128
- . unwrap ( ) ;
136
+ } ) {
137
+ Ok ( device) => device,
138
+ Err ( e) => {
139
+ println ! ( "Error opening audio device: {}" , e) ;
140
+ return ;
141
+ }
142
+ } ;
143
+
144
+ // start capturing
145
+ audio_device. resume ( ) ;
129
146
130
147
// take ownership of device
131
- self . capturing_device = Some ( audio_device) ;
148
+ self . capturing_device = Some ( Box :: new ( audio_device) ) ;
132
149
self . is_capturing = true ;
133
-
134
- // play device
135
- self . capturing_device . as_mut ( ) . unwrap ( ) . resume ( ) ;
136
150
}
137
151
138
152
pub fn stop_audio_capture ( & mut self ) {
139
153
let current_device_name = self . get_current_device_name ( ) ;
140
154
println ! ( "Stopping audio capture for device {}" , current_device_name) ;
141
155
142
156
println ! (
143
- "current capture device: {:?}" ,
157
+ "Current capture device status : {:?}" ,
144
158
self . capturing_device. as_ref( ) . unwrap( ) . status( )
145
159
) ;
146
160
161
+ // take ownership of device
162
+ // capture device will be dropped when this function returns
163
+ // and the audio callback will stop being called
164
+ let device = self . capturing_device . take ( ) . unwrap ( ) ;
165
+ device. pause ( ) ;
166
+
147
167
self . is_capturing = false ;
148
- // drop(self.capturing_device); // stop capturing
149
- self . capturing_device = None ;
150
168
}
151
169
}
152
170
153
171
struct AudioCaptureCallback {
154
- pm : ProjectMHandle ,
155
- // spec: sdl2::audio::AudioSpec,
156
- // buffer_size: SampleFormat,
157
- // buffer: Vec<u8>,
158
- // position: usize,
172
+ // we need to keep a reference to the projectm instance to
173
+ // add the audio data to it
174
+ pm : Arc < Mutex < ProjectMHandle > > ,
159
175
}
160
176
unsafe impl Send for AudioCaptureCallback { }
161
177
unsafe impl Sync for AudioCaptureCallback { }
@@ -166,7 +182,7 @@ impl AudioCallback for AudioCaptureCallback {
166
182
// we are receiving some chunk of audio data
167
183
// we need to pass it to projectm
168
184
fn callback ( & mut self , out : & mut [ SampleFormat ] ) {
169
- let pm = self . pm ;
185
+ let pm = * self . pm . lock ( ) . unwrap ( ) ;
170
186
projectm_rs:: core:: Projectm :: pcm_add_float ( pm, out. to_vec ( ) , 2 ) ;
171
187
}
172
188
}
0 commit comments