1 use libc::c_void;
2 
3 use crate::enums::{ChannelData, FileTypes, MessageType, Status};
4 use crate::rtaudio::{CsAudioDevice, RtAudioParams};
5 
6 use csound_sys as raw;
7 
8 /// Struct containing the relevant info of files are opened by csound.
9 #[derive(Debug, Clone)]
10 pub struct FileInfo {
11     /// pathname of the file; either full or relative to current dir
12     pub name: Option<String>,
13     /// Enum equivalent code for the file type code from the enum CSOUND_FILETYPES
14     pub file_type: FileTypes,
15     /// true if Csound is writing the file, false if reading
16     pub is_writing: bool,
17     /// true if  it is a temporary file that Csound will delete; false if not
18     pub is_temp: bool,
19 }
20 
21 #[doc(hidden)]
22 #[derive(Default)]
23 pub struct Callbacks<'a> {
24     pub message_cb: Option<Box<dyn FnMut(MessageType, &str) + 'a>>,
25     pub devlist_cb: Option<Box<dyn FnMut(CsAudioDevice) + 'a>>,
26     pub play_open_cb: Option<Box<dyn FnMut(&RtAudioParams) -> Status + 'a>>,
27     pub rec_open_cb: Option<Box<dyn FnMut(&RtAudioParams) -> Status + 'a>>,
28     pub rt_play_cb: Option<Box<dyn FnMut(&[f64]) + 'a>>,
29     pub rt_rec_cb: Option<Box<dyn FnMut(&mut [f64]) -> usize + 'a>>,
30     pub sense_event_cb: Option<Box<dyn FnMut() + 'a>>,
31     pub keyboard_cb: Option<Box<dyn FnMut() -> char + 'a>>, // TODO this callback doesn't work at the
32     //csound side
33     pub rt_close_cb: Option<Box<dyn FnMut() + 'a>>,
34     pub cscore_cb: Option<Box<dyn FnMut() + 'a>>,
35     pub input_channel_cb: Option<Box<dyn FnMut(&str) -> ChannelData + 'a>>,
36     pub output_channel_cb: Option<Box<dyn FnMut(&str, ChannelData) + 'a>>,
37     pub file_open_cb: Option<Box<dyn FnMut(&FileInfo) + 'a>>,
38     pub midi_in_open_cb: Option<Box<dyn FnMut(&str) + 'a>>,
39     pub midi_out_open_cb: Option<Box<dyn FnMut(&str) + 'a>>,
40     pub midi_read_cb: Option<Box<dyn FnMut(&mut [u8]) -> usize + 'a>>,
41     pub midi_write_cb: Option<Box<dyn FnMut(&[u8]) -> usize + 'a>>,
42     pub midi_in_close_cb: Option<Box<dyn FnMut() + 'a>>,
43     pub midi_out_close_cb: Option<Box<dyn FnMut() + 'a>>,
44     pub yield_cb: Option<Box<dyn FnMut() -> bool + 'a>>,
45 }
46 
47 impl<'a> Callbacks<'a> {
set_message_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(MessageType, &str) + 'a,48     pub(crate) unsafe fn set_message_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
49     where
50         F: FnMut(MessageType, &str) + 'a,
51     {
52         self.message_cb = Some(Box::new(cb));
53         raw::csoundSetMessageStringCallback(csound, Trampoline::message_string_cb)
54     }
55 
set_devlist_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(CsAudioDevice) + 'a,56     pub(crate) unsafe fn set_devlist_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
57     where
58         F: FnMut(CsAudioDevice) + 'a,
59     {
60         self.devlist_cb = Some(Box::new(cb));
61         raw::csoundSetAudioDeviceListCallback(csound, Some(Trampoline::audioDeviceListCallback));
62     }
63 
set_play_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&RtAudioParams) -> Status + 'a,64     pub(crate) unsafe fn set_play_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
65     where
66         F: FnMut(&RtAudioParams) -> Status + 'a,
67     {
68         self.play_open_cb = Some(Box::new(cb));
69         raw::csoundSetPlayopenCallback(csound, Some(Trampoline::playOpenCallback));
70     }
71 
set_rec_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&RtAudioParams) -> Status + 'a,72     pub(crate) unsafe fn set_rec_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
73     where
74         F: FnMut(&RtAudioParams) -> Status + 'a,
75     {
76         self.play_open_cb = Some(Box::new(cb));
77         raw::csoundSetRecopenCallback(csound, Some(Trampoline::recOpenCallback));
78     }
79 
set_rt_play_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&[f64]) + 'a,80     pub(crate) unsafe fn set_rt_play_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
81     where
82         F: FnMut(&[f64]) + 'a,
83     {
84         self.rt_play_cb = Some(Box::new(cb));
85         csound_sys::csoundSetRtplayCallback(csound, Some(Trampoline::rtplayCallback));
86     }
87 
set_rt_rec_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&mut [f64]) -> usize + 'a,88     pub(crate) unsafe fn set_rt_rec_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
89     where
90         F: FnMut(&mut [f64]) -> usize + 'a,
91     {
92         self.rt_rec_cb = Some(Box::new(cb));
93         csound_sys::csoundSetRtrecordCallback(csound, Some(Trampoline::rtrecordCallback));
94     }
95 
set_rt_close_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut() + 'a,96     pub(crate) unsafe fn set_rt_close_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
97     where
98         F: FnMut() + 'a,
99     {
100         self.rt_close_cb = Some(Box::new(cb));
101         csound_sys::csoundSetRtcloseCallback(csound, Some(Trampoline::rtcloseCallback));
102     }
103 
set_sense_event_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut() + 'a,104     pub(crate) unsafe fn set_sense_event_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
105     where
106         F: FnMut() + 'a,
107     {
108         self.sense_event_cb = Some(Box::new(cb));
109         csound_sys::csoundRegisterSenseEventCallback(
110             csound,
111             Some(Trampoline::senseEventCallback),
112             ::std::ptr::null_mut() as *mut c_void,
113         );
114     }
115 
116     /*pub(crate) unsafe fn set_cscore_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
117     where
118         F: FnMut() + 'a,
119     {
120         self.cscore_cb = Some(Box::new(cb));
121         csound_sys::csoundSetCscoreCallback(
122             csound,
123             Some(Trampoline::scoreCallback),
124         );
125     }*/
126 
set_input_channel_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&str) -> ChannelData + 'a,127     pub(crate) unsafe fn set_input_channel_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
128     where
129         F: FnMut(&str) -> ChannelData + 'a,
130     {
131         self.input_channel_cb = Some(Box::new(cb));
132         csound_sys::csoundSetInputChannelCallback(csound, Some(Trampoline::inputChannelCallback));
133     }
134 
set_output_channel_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&str, ChannelData) + 'a,135     pub(crate) unsafe fn set_output_channel_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
136     where
137         F: FnMut(&str, ChannelData) + 'a,
138     {
139         self.output_channel_cb = Some(Box::new(cb));
140         csound_sys::csoundSetOutputChannelCallback(csound, Some(Trampoline::outputChannelCallback));
141     }
142 
set_file_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&FileInfo) + 'a,143     pub(crate) unsafe fn set_file_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
144     where
145         F: FnMut(&FileInfo) + 'a,
146     {
147         self.file_open_cb = Some(Box::new(cb));
148         csound_sys::csoundSetFileOpenCallback(csound, Some(Trampoline::fileOpenCallback));
149     }
150 
set_midi_in_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&str) + 'a,151     pub(crate) unsafe fn set_midi_in_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
152     where
153         F: FnMut(&str) + 'a,
154     {
155         self.midi_in_open_cb = Some(Box::new(cb));
156         csound_sys::csoundSetExternalMidiInOpenCallback(
157             csound,
158             Some(Trampoline::midiInOpenCallback),
159         );
160     }
161 
set_midi_out_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&str) + 'a,162     pub(crate) unsafe fn set_midi_out_open_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
163     where
164         F: FnMut(&str) + 'a,
165     {
166         self.midi_out_open_cb = Some(Box::new(cb));
167         csound_sys::csoundSetExternalMidiOutOpenCallback(
168             csound,
169             Some(Trampoline::midiOutOpenCallback),
170         );
171     }
172 
set_midi_read_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&mut [u8]) -> usize + 'a,173     pub(crate) unsafe fn set_midi_read_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
174     where
175         F: FnMut(&mut [u8]) -> usize + 'a,
176     {
177         self.midi_read_cb = Some(Box::new(cb));
178         csound_sys::csoundSetExternalMidiReadCallback(csound, Some(Trampoline::midiReadCallback));
179     }
180 
set_midi_write_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut(&[u8]) -> usize + 'a,181     pub(crate) unsafe fn set_midi_write_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
182     where
183         F: FnMut(&[u8]) -> usize + 'a,
184     {
185         self.midi_write_cb = Some(Box::new(cb));
186         csound_sys::csoundSetExternalMidiWriteCallback(csound, Some(Trampoline::midiWriteCallback));
187     }
188 
set_midi_in_close_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut() + 'a,189     pub(crate) unsafe fn set_midi_in_close_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
190     where
191         F: FnMut() + 'a,
192     {
193         self.midi_in_close_cb = Some(Box::new(cb));
194         csound_sys::csoundSetExternalMidiInCloseCallback(
195             csound,
196             Some(Trampoline::midiInCloseCallback),
197         );
198     }
199 
set_midi_out_close_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut() + 'a,200     pub(crate) unsafe fn set_midi_out_close_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
201     where
202         F: FnMut() + 'a,
203     {
204         self.midi_out_close_cb = Some(Box::new(cb));
205         csound_sys::csoundSetExternalMidiOutCloseCallback(
206             csound,
207             Some(Trampoline::midiOutCloseCallback),
208         );
209     }
210 
set_yield_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F) where F: FnMut() -> bool + 'a,211     pub(crate) unsafe fn set_yield_cb<F>(&'a mut self, csound: *mut raw::CSOUND, cb: F)
212     where
213         F: FnMut() -> bool + 'a,
214     {
215         self.yield_cb = Some(Box::new(cb));
216         csound_sys::csoundSetYieldCallback(csound, Some(Trampoline::yieldCallback));
217     }
218 }
219 
220 pub mod Trampoline {
221 
222     use csound_sys as raw;
223     use va_list::VaList;
224 
225     use super::*;
226     use crate::csound::CallbackHandler;
227     use crate::rtaudio::{CsAudioDevice, RtAudioParams};
228     use libc::{c_char, c_int, c_uchar, c_void, memcpy};
229     use std::ffi::{CStr, CString};
230     use std::panic::{self, AssertUnwindSafe};
231     use std::slice;
232 
ptr_to_string(ptr: *const c_char) -> Option<String>233     pub fn ptr_to_string(ptr: *const c_char) -> Option<String> {
234         if !ptr.is_null() {
235             let result = match unsafe { CStr::from_ptr(ptr) }.to_str().ok() {
236                 Some(str_slice) => Some(str_slice.to_owned()),
237                 None => None,
238             };
239             return result;
240         }
241         None
242     }
243 
convert_str_to_c<T>(string: T) -> Result<CString, &'static str> where T: AsRef<str>,244     pub fn convert_str_to_c<T>(string: T) -> Result<CString, &'static str>
245     where
246         T: AsRef<str>,
247     {
248         let string = string.as_ref();
249         if string.is_empty() {
250             return Err("Failed to convert empty string to C");
251         }
252         CString::new(string).map_err(|_| "Failed converting rust string to CString")
253     }
254 
catch<T, F: FnOnce() -> T>(f: F) -> Option<T>255     fn catch<T, F: FnOnce() -> T>(f: F) -> Option<T> {
256         match panic::catch_unwind(AssertUnwindSafe(f)) {
257             Ok(ret) => Some(ret),
258             Err(_) => {
259                 std::process::exit(-1);
260             }
261         }
262     }
263 
default_message_callback( _csound: *mut raw::CSOUND, _attr: c_int, _format: *const c_char, _args: VaList, )264     pub extern "C" fn default_message_callback(
265         _csound: *mut raw::CSOUND,
266         _attr: c_int,
267         _format: *const c_char,
268         _args: VaList,
269     ) {
270     }
271 
message_string_cb( csound: *mut raw::CSOUND, attr: c_int, message: *const c_char, )272     pub extern "C" fn message_string_cb(
273         csound: *mut raw::CSOUND,
274         attr: c_int,
275         message: *const c_char,
276     ) {
277         catch(|| unsafe {
278             let info = CStr::from_ptr(message);
279             if let Ok(s) = info.to_str() {
280                 if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
281                     .callbacks
282                     .message_cb
283                     .as_mut()
284                 {
285                     fun(MessageType::from(attr as u32), s);
286                 }
287             }
288         });
289     }
290 
291     /****** Event callbacks functions *******************************************************************/
292 
senseEventCallback(csound: *mut raw::CSOUND, _userData: *mut c_void)293     pub extern "C" fn senseEventCallback(csound: *mut raw::CSOUND, _userData: *mut c_void) {
294         catch(|| unsafe {
295             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
296                 .callbacks
297                 .sense_event_cb
298                 .as_mut()
299             {
300                 fun();
301             }
302         });
303     }
304 
305     /****** real time audio callbacks functions *******************************************************************/
306 
playOpenCallback( csound: *mut raw::CSOUND, dev: *const raw::csRtAudioParams, ) -> c_int307     pub extern "C" fn playOpenCallback(
308         csound: *mut raw::CSOUND,
309         dev: *const raw::csRtAudioParams,
310     ) -> c_int {
311         catch(|| unsafe {
312             let rtParams = RtAudioParams {
313                 devName: ptr_to_string((*dev).devName),
314                 devNum: (*dev).devNum as u32,
315                 bufSamp_SW: (*dev).bufSamp_SW as u32,
316                 bufSamp_HW: (*dev).bufSamp_HW as u32,
317                 nChannels: (*dev).nChannels as u32,
318                 sampleFormat: (*dev).sampleFormat as u32,
319                 sampleRate: (*dev).sampleRate as f32,
320             };
321             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
322                 .callbacks
323                 .play_open_cb
324                 .as_mut()
325             {
326                 return fun(&rtParams).to_i32() as c_int;
327             }
328             0
329         })
330         .unwrap()
331     }
332 
recOpenCallback( csound: *mut raw::CSOUND, dev: *const raw::csRtAudioParams, ) -> c_int333     pub extern "C" fn recOpenCallback(
334         csound: *mut raw::CSOUND,
335         dev: *const raw::csRtAudioParams,
336     ) -> c_int {
337         catch(|| unsafe {
338             let rtParams = RtAudioParams {
339                 devName: ptr_to_string((*dev).devName),
340                 devNum: (*dev).devNum as u32,
341                 bufSamp_SW: (*dev).bufSamp_SW as u32,
342                 bufSamp_HW: (*dev).bufSamp_HW as u32,
343                 nChannels: (*dev).nChannels as u32,
344                 sampleFormat: (*dev).sampleFormat as u32,
345                 sampleRate: (*dev).sampleRate as f32,
346             };
347             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
348                 .callbacks
349                 .rec_open_cb
350                 .as_mut()
351             {
352                 return fun(&rtParams).to_i32() as c_int;
353             }
354             -1
355         })
356         .unwrap()
357     }
358 
rtcloseCallback(csound: *mut raw::CSOUND)359     pub extern "C" fn rtcloseCallback(csound: *mut raw::CSOUND) {
360         catch(|| unsafe {
361             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
362                 .callbacks
363                 .rt_close_cb
364                 .as_mut()
365             {
366                 fun();
367             }
368         });
369     }
370 
rtplayCallback(csound: *mut raw::CSOUND, outBuf: *const f64, nbytes: c_int)371     pub extern "C" fn rtplayCallback(csound: *mut raw::CSOUND, outBuf: *const f64, nbytes: c_int) {
372         catch(|| unsafe {
373             let out = slice::from_raw_parts(outBuf, nbytes as usize);
374             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
375                 .callbacks
376                 .rt_play_cb
377                 .as_mut()
378             {
379                 fun(&out);
380             }
381         });
382     }
383 
rtrecordCallback( csound: *mut raw::CSOUND, outBuf: *mut f64, nbytes: c_int, ) -> c_int384     pub extern "C" fn rtrecordCallback(
385         csound: *mut raw::CSOUND,
386         outBuf: *mut f64,
387         nbytes: c_int,
388     ) -> c_int {
389         catch(|| unsafe {
390             let mut buff = slice::from_raw_parts_mut(outBuf, nbytes as usize);
391             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
392                 .callbacks
393                 .rt_rec_cb
394                 .as_mut()
395             {
396                 return fun(&mut buff) as c_int;
397             }
398             -1
399         })
400         .unwrap()
401     }
402 
audioDeviceListCallback( csound: *mut raw::CSOUND, dev: *mut raw::CS_AUDIODEVICE, isOutput: c_int, ) -> c_int403     pub extern "C" fn audioDeviceListCallback(
404         csound: *mut raw::CSOUND,
405         dev: *mut raw::CS_AUDIODEVICE,
406         isOutput: c_int,
407     ) -> c_int {
408         catch(|| unsafe {
409             let audioDevice = CsAudioDevice {
410                 device_name: ptr_to_string((*dev).device_name.as_ptr()),
411                 device_id: ptr_to_string((*dev).device_id.as_ptr()),
412                 rt_module: ptr_to_string((*dev).rt_module.as_ptr()),
413                 max_nchnls: (*dev).max_nchnls as u32,
414                 isOutput: isOutput as u32,
415             };
416             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
417                 .callbacks
418                 .devlist_cb
419                 .as_mut()
420             {
421                 fun(audioDevice);
422             }
423             0
424         })
425         .unwrap()
426     }
427 
428     /*pub extern "C" fn keyboard_callback(
429         userData: *mut c_void,
430         p: *mut c_void,
431         _type_: c_uint,
432     ) -> c_int {
433         unsafe {
434             match (*(userData as *mut CallbackHandler))
435                 .callbacks
436                 .keyboard_cb() {
437                 '\0' => {}
438                 value => {
439                     *(p as *mut c_int) = value as c_int;
440                 }
441             }
442             0
443         }
444     }*/
445 
446     /********* General Input/Output callbacks ********************************************************************/
fileOpenCallback( csound: *mut raw::CSOUND, filePath: *const c_char, fileType: c_int, operation: c_int, isTemp: c_int, )447     pub extern "C" fn fileOpenCallback(
448         csound: *mut raw::CSOUND,
449         filePath: *const c_char,
450         fileType: c_int,
451         operation: c_int,
452         isTemp: c_int,
453     ) {
454         catch(|| unsafe {
455             let name = ptr_to_string(filePath);
456             let file_info = FileInfo {
457                 name,
458                 file_type: FileTypes::from(fileType as u8),
459                 is_writing: operation != 0,
460                 is_temp: isTemp != 0,
461             };
462             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
463                 .callbacks
464                 .file_open_cb
465                 .as_mut()
466             {
467                 fun(&file_info);
468             }
469         });
470     }
471 
472     /* Score Handling callbacks ********************************************************* */
473 
474     // Sets an pub external callback for Cscore processing. Pass NULL to reset to the internal cscore() function (which does nothing).
475     // This callback is retained after a csoundReset() call.
476     /*pub extern "C" fn scoreCallback(csound: *mut raw::CSOUND) {
477         catch(|| unsafe {
478             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
479                 .callbacks
480                 .cscore_cb
481                 .as_mut()
482             {
483                 fun();
484             }
485         });
486     }*/
487 
488     /* Channels and events callbacks **************************************************** */
489 
inputChannelCallback( csound: *mut raw::CSOUND, channelName: *const c_char, channelValuePtr: *mut c_void, _channelType: *const c_void, )490     pub extern "C" fn inputChannelCallback(
491         csound: *mut raw::CSOUND,
492         channelName: *const c_char,
493         channelValuePtr: *mut c_void,
494         _channelType: *const c_void,
495     ) {
496         catch(|| unsafe {
497             let name = (CStr::from_ptr(channelName)).to_str();
498             if name.is_err() {
499                 return;
500             }
501             let name = name.unwrap();
502             let result = if let Some(fun) = (*(raw::csoundGetHostData(csound)
503                 as *mut CallbackHandler))
504                 .callbacks
505                 .input_channel_cb
506                 .as_mut()
507             {
508                 fun(name)
509             } else {
510                 return;
511             };
512 
513             match result {
514                 ChannelData::CS_CONTROL_CHANNEL(data) => {
515                     *(channelValuePtr as *mut f64) = data;
516                 }
517 
518                 ChannelData::CS_STRING_CHANNEL(s) => {
519                     let len = s.len();
520                     let c_str = CString::new(s);
521                     if raw::csoundGetChannelDatasize(csound, channelName) as usize <= len {
522                         if let Ok(ptr) = c_str {
523                             memcpy(channelValuePtr, ptr.as_ptr() as *mut c_void, len);
524                         }
525                     }
526                 }
527 
528                 _ => {}
529             }
530         });
531     }
532 
outputChannelCallback( csound: *mut raw::CSOUND, channelName: *const c_char, channelValuePtr: *mut c_void, _channelType: *const c_void, )533     pub extern "C" fn outputChannelCallback(
534         csound: *mut raw::CSOUND,
535         channelName: *const c_char,
536         channelValuePtr: *mut c_void,
537         _channelType: *const c_void,
538     ) {
539         catch(|| unsafe {
540             let name = (CStr::from_ptr(channelName)).to_str();
541             if name.is_err() {
542                 return;
543             }
544             let name = name.unwrap();
545             let mut ptr = ::std::ptr::null_mut();
546             let ptr: *mut *mut f64 = &mut ptr as *mut *mut _;
547             let channel_type = raw::csoundGetChannelPtr(csound, ptr, channelName, 0) as u32;
548             let channel_type = channel_type & raw::CSOUND_CHANNEL_TYPE_MASK as u32;
549 
550             let fun = if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
551                 .callbacks
552                 .output_channel_cb
553                 .as_mut()
554             {
555                 fun
556             } else {
557                 return;
558             };
559 
560             match channel_type {
561                 raw::CSOUND_CONTROL_CHANNEL => {
562                     let value = *(channelValuePtr as *mut f64);
563                     let data = ChannelData::CS_CONTROL_CHANNEL(value);
564                     fun(name, data);
565                 }
566 
567                 raw::CSOUND_STRING_CHANNEL => {
568                     let data = ChannelData::CS_STRING_CHANNEL(
569                         ptr_to_string(channelValuePtr as *const c_char)
570                             .unwrap_or_else(|| "".to_owned()),
571                     );
572                     fun(name, data);
573                 }
574 
575                 _ => {}
576             }
577         });
578     }
579 
580     /****** MIDI I/O callbacks functions *******************************************************************/
581 
582     // Sets callback for opening real time MIDI input.
midiInOpenCallback( csound: *mut raw::CSOUND, _userData: *mut *mut c_void, devName: *const c_char, ) -> c_int583     pub extern "C" fn midiInOpenCallback(
584         csound: *mut raw::CSOUND,
585         _userData: *mut *mut c_void,
586         devName: *const c_char,
587     ) -> c_int {
588         catch(|| unsafe {
589             let name = match CStr::from_ptr(devName).to_str() {
590                 Ok(s) => s,
591                 _ => return raw::CSOUND_ERROR,
592             };
593             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
594                 .callbacks
595                 .midi_in_open_cb
596                 .as_mut()
597             {
598                 fun(&name);
599             }
600             raw::CSOUND_SUCCESS
601         })
602         .unwrap()
603     }
604 
605     // Sets callback for opening real time MIDI output.
midiOutOpenCallback( csound: *mut raw::CSOUND, _userData: *mut *mut c_void, devName: *const c_char, ) -> c_int606     pub extern "C" fn midiOutOpenCallback(
607         csound: *mut raw::CSOUND,
608         _userData: *mut *mut c_void,
609         devName: *const c_char,
610     ) -> c_int {
611         catch(|| unsafe {
612             let name = match CStr::from_ptr(devName).to_str() {
613                 Ok(s) => s,
614                 _ => return raw::CSOUND_ERROR,
615             };
616             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
617                 .callbacks
618                 .midi_out_open_cb
619                 .as_mut()
620             {
621                 fun(&name);
622             }
623             raw::CSOUND_SUCCESS
624         })
625         .unwrap()
626     }
627 
628     // Sets callback for reading from real time MIDI input.
midiReadCallback( csound: *mut raw::CSOUND, _userData: *mut c_void, buf: *mut c_uchar, nbytes: c_int, ) -> c_int629     pub extern "C" fn midiReadCallback(
630         csound: *mut raw::CSOUND,
631         _userData: *mut c_void,
632         buf: *mut c_uchar,
633         nbytes: c_int,
634     ) -> c_int {
635         catch(|| unsafe {
636             let mut out = slice::from_raw_parts_mut(buf, nbytes as usize);
637             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
638                 .callbacks
639                 .midi_read_cb
640                 .as_mut()
641             {
642                 return fun(&mut out) as c_int;
643             }
644             -1
645         })
646         .unwrap()
647     }
648 
649     // Sets callback for writing to real time MIDI output.
650     #[allow(dead_code)]
midiWriteCallback( csound: *mut raw::CSOUND, _userData: *mut c_void, buf: *const u8, nbytes: c_int, ) -> c_int651     pub extern "C" fn midiWriteCallback(
652         csound: *mut raw::CSOUND,
653         _userData: *mut c_void,
654         buf: *const u8,
655         nbytes: c_int,
656     ) -> c_int {
657         catch(|| unsafe {
658             let buffer = slice::from_raw_parts(buf, nbytes as usize);
659             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
660                 .callbacks
661                 .midi_write_cb
662                 .as_mut()
663             {
664                 return fun(&buffer) as c_int;
665             }
666             -1
667         })
668         .unwrap()
669     }
670 
671     //Sets callback for closing real time MIDI input.
midiInCloseCallback( csound: *mut raw::CSOUND, _userData: *mut c_void, ) -> c_int672     pub extern "C" fn midiInCloseCallback(
673         csound: *mut raw::CSOUND,
674         _userData: *mut c_void,
675     ) -> c_int {
676         catch(|| unsafe {
677             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
678                 .callbacks
679                 .midi_in_close_cb
680                 .as_mut()
681             {
682                 fun();
683             }
684             raw::CSOUND_SUCCESS
685         })
686         .unwrap()
687     }
688 
689     // Sets callback for closing real time MIDI output.
midiOutCloseCallback( csound: *mut raw::CSOUND, _userData: *mut c_void, ) -> c_int690     pub extern "C" fn midiOutCloseCallback(
691         csound: *mut raw::CSOUND,
692         _userData: *mut c_void,
693     ) -> c_int {
694         catch(|| unsafe {
695             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
696                 .callbacks
697                 .midi_out_close_cb
698                 .as_mut()
699             {
700                 fun();
701             }
702             raw::CSOUND_SUCCESS
703         })
704         .unwrap()
705     }
706 
yieldCallback(csound: *mut raw::CSOUND) -> c_int707     pub extern "C" fn yieldCallback(csound: *mut raw::CSOUND) -> c_int {
708         catch(|| unsafe {
709             if let Some(fun) = (*(raw::csoundGetHostData(csound) as *mut CallbackHandler))
710                 .callbacks
711                 .yield_cb
712                 .as_mut()
713             {
714                 return fun() as c_int;
715             }
716             0
717         })
718         .unwrap()
719     }
720 }
721 
722 //Sets callback for converting MIDI error codes to strings.
723 /*pub extern fn pub externalMidiErrorStringCallback (midi_error_code : c_int) -> *const c_char {
724     unsafe{
725     }
726 }*/
727