1 #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
2 
3 use std::marker::PhantomData;
4 use std::mem;
5 
6 use std::cell::RefCell;
7 
8 use std::ops::{Deref, DerefMut};
9 use std::ptr;
10 use std::slice;
11 
12 use crate::callbacks::*;
13 use crate::channels::{
14     ChannelBehavior, ChannelHints, ChannelInfo, InputChannel, IsChannel, OutputChannel, PvsDataExt,
15 };
16 
17 use crate::enums::{ChannelData, ControlChannelType, Language, MessageType, Status};
18 use crate::rtaudio::{CsAudioDevice, CsMidiDevice, RtAudioParams};
19 use csound_sys::RTCLOCK;
20 
21 use std::ffi::{CStr, CString, NulError};
22 use std::str;
23 use std::str::Utf8Error;
24 
25 use libc::{c_char, c_double, c_int, c_long, c_void};
26 
27 // the length in bytes of the output type name in csound
28 const OUTPUT_TYPE_LENGTH: usize = 6;
29 
30 // The length in bytes of the output format name in csound
31 const OUTPUT_FORMAT_LENGTH: usize = 8;
32 
33 /// Struct with information about a csound opcode.
34 ///
35 /// Used to get the complete csound opcodes list, so the
36 /// [`Csound::get_opcode_list_entry`](struct.Csound.html#method.get_opcode_list_entry) method will return
37 /// a list of OpcodeListEntry, where each of this struct contain information relative
38 /// a specific csound opcode.
39 #[derive(Default, Debug)]
40 pub struct OpcodeListEntry {
41     /// The opcode name.
42     pub opname: Option<String>,
43     /// The opcode ouput type.
44     pub outypes: Option<String>,
45     /// The opcode input type.
46     pub intypes: Option<String>,
47     pub flags: i32,
48 }
49 
50 #[derive(Default)]
51 pub(crate) struct CallbackHandler<'c> {
52     pub callbacks: Callbacks<'c>,
53 }
54 
55 /// Opaque struct representing an csound object
56 ///
57 /// This is the main struct used to access the libcsound API functions.
58 /// The Engine element is the inner representation of the CSOUND opaque pointer and is
59 /// the object wich talk directly with the libcsound c library.
60 ///
61 #[derive(Debug)]
62 pub struct Csound {
63     /// Inner representation of the CSOUND opaque pointer
64     pub(crate) engine: Inner,
65 }
66 
67 /// Opaque struct representing a csound object
68 #[derive(Debug)]
69 pub(crate) struct Inner {
70     pub(crate) csound: *mut csound_sys::CSOUND,
71     use_msg_buffer: RefCell<bool>,
72 }
73 
74 unsafe impl Send for Inner {}
75 
76 impl Default for Csound {
default() -> Self77     fn default() -> Self {
78         unsafe {
79             // Csound must not handle signals
80             csound_sys::csoundInitialize(csound_sys::CSOUNDINIT_NO_SIGNAL_HANDLER as c_int);
81             csound_sys::csoundInitialize(csound_sys::CSOUNDINIT_NO_ATEXIT as c_int);
82 
83             // set default callback which does not nothing
84             csound_sys::csoundSetDefaultMessageCallback(Trampoline::default_message_callback);
85 
86             let callback_handler = Box::new(CallbackHandler {
87                 callbacks: Callbacks::default(),
88             });
89             let host_data_ptr = Box::into_raw(callback_handler) as *mut c_void;
90 
91             let csound_sys = csound_sys::csoundCreate(host_data_ptr);
92             assert!(!csound_sys.is_null());
93 
94             let engine = Inner {
95                 csound: csound_sys,
96                 use_msg_buffer: RefCell::new(false),
97             };
98             Csound { engine }
99         }
100     }
101 }
102 
103 impl Csound {
104     /// Create a new csound object.
105     ///
106     /// This is the core of almost all operations in the csound library.
107     /// A new instance of csound will created by this function, a custom callback handler will be used,
108     /// This custom callback handler will be active only if the user calls some of the
109     /// callbacks setting functions which receive a closure for a specific callback.
110     ///
111     /// # Example
112     ///
113     /// ```
114     ///  // Creates a Csound instance and use a custom callback handler
115     /// let csound = Csound::new();
116     /// // enable the message callback passing a closure to the custom callback handler
117     /// csound.message_string_callback( |mtype:u32, message:&str| {
118     ///     println!("message type: {} message content:  {}", mtype, message);
119     /// });
120     /// csound.compile_csd(csd_filename).unwrap();
121     /// csound.start();
122     /// ```
new() -> Csound123     pub fn new() -> Csound {
124         Csound::default()
125     }
126 
127     /// Initializes the csound library with specific flags(see: [anchor text]()).
128     /// This function is called internally by Csound::new(), so there is generally no need to use it explicitly unless
129     /// you need to avoid default initilization that sets signal handlers and atexit() callbacks.
130     /// Return value is Ok() on success or an error message in case of failure
initialize(flags: i32) -> Result<(), &'static str>131     pub fn initialize(flags: i32) -> Result<(), &'static str> {
132         unsafe {
133             match csound_sys::csoundInitialize(flags as c_int) as i32 {
134                 csound_sys::CSOUND_ERROR => Err("Can't to initialize csound "),
135                 csound_sys::CSOUND_SUCCESS => Ok(()),
136                 value => {
137                     if value > 0 {
138                         Err("Initialization was done already")
139                     } else {
140                         Err("Unknown error - can not to initialize")
141                     }
142                 }
143             }
144         }
145     }
146 
147     /// Sets a single csound option(flag).
148     ///
149     /// NB: blank spaces are not allowed.
150     /// # Returns
151     /// returns Ok on success or an error message in case the option is invalid.
set_option(&self, option: &str) -> Result<(), String>152     pub fn set_option(&self, option: &str) -> Result<(), String> {
153         let op =
154             CString::new(option).map_err(|e| format!("Error parsing the csound option: {}", e))?;
155         unsafe {
156             match csound_sys::csoundSetOption(self.engine.csound, op.as_ptr()) {
157                 csound_sys::CSOUND_SUCCESS => Ok(()),
158                 _ => Err(format!("Csound option {} not valid", option)),
159             }
160         }
161     }
162 
163     /// Prepares Csound for performance.
164     ///
165     /// Normally called after compiling a csd file or an orc file, in which case score preprocessing is performed and
166     /// performance terminates when the score terminates.
167     /// However, if called before compiling a csd file or an orc file,
168     /// score preprocessing is not performed and "i" statements are dispatched as real-time events,
169     /// the <CsOptions> tag is ignored, and performance continues indefinitely or until ended using the API.
170     /// # Example
171     ///
172     /// ```
173     /// let csound = Csound::new();
174     /// csound.compile_csd(csd_filename).unwrap();
175     /// csound.start();
176     /// ...
177     /// ```
178     ///
start(&self) -> Result<(), &'static str>179     pub fn start(&self) -> Result<(), &'static str> {
180         unsafe {
181             if csound_sys::csoundStart(self.engine.csound) == csound_sys::CSOUND_SUCCESS {
182                 Ok(())
183             } else {
184                 Err("Csound is already started, call reset() before starting again.")
185             }
186         }
187     }
188 
189     /// Returns the version number times 1000
190     /// for example, if the current csound version is 6.12.0
191     /// this function will return 6120.
version(&self) -> u32192     pub fn version(&self) -> u32 {
193         unsafe { csound_sys::csoundGetVersion() as u32 }
194     }
195 
196     /// Returns the API version number times 100
api_version(&self) -> u32197     pub fn api_version(&self) -> u32 {
198         unsafe { csound_sys::csoundGetAPIVersion() as u32 }
199     }
200 
201     /* Engine performance functions implementations ********************************************************* */
202 
203     /// Stops the performance of a csound's instance
204     /// *Note*: It is not guaranteed that [`Csound::perform`](struct.Csound.html#method.perform) has already stopped when this function returns.
stop(&self)205     pub fn stop(&self) {
206         unsafe {
207             csound_sys::csoundStop(self.engine.csound);
208         }
209     }
210 
211     /// Resets all internal memory and state in preparation for a new performance.
212     /// Enables external software to run successive Csound performances without reloading Csound.
reset(&self)213     pub fn reset(&self) {
214         unsafe {
215             csound_sys::csoundReset(self.engine.csound);
216         }
217     }
218 
219     /// Compiles Csound input files (such as an orchestra and score, or CSD) as directed by the supplied command-line arguments , but does not perform them.
220     /// This function cannot be called during performance, and before a repeated call, csoundReset() needs to be called.
221     /// # Arguments
222     /// * `args` A slice containing the arguments  to be passed to csound
223     /// # Returns
224     /// A error message in case of failure
compile<T>(&self, args: &[T]) -> Result<(), String> where T: AsRef<str> + std::fmt::Debug,225     pub fn compile<T>(&self, args: &[T]) -> Result<(), String>
226     where
227         T: AsRef<str> + std::fmt::Debug,
228     {
229         if args.is_empty() {
230             return Err("Not enough arguments".into());
231         }
232 
233         let arguments: Vec<CString> = args
234             .iter()
235             .map(|arg| CString::new(arg.as_ref()))
236             .filter_map(Result::ok)
237             .collect();
238         let args_raw: Vec<*const c_char> = arguments.iter().map(|arg| arg.as_ptr()).collect();
239         let argv: *const *const c_char = args_raw.as_ptr();
240         unsafe {
241             match csound_sys::csoundCompile(self.engine.csound, args_raw.len() as c_int, argv) {
242                 csound_sys::CSOUND_SUCCESS => Ok(()),
243                 _ => Err(format!("Can't compile csound arguments: {:?}", args)),
244             }
245         }
246     }
247 
248     /// Compiles a Csound input file (CSD, .csd file), but does not perform it.
249     /// If [`Csound::start`](struct.Csound.html#method.start) is called before `compile_csd`, the <CsOptions> element is ignored
250     /// (but set_option can be called any number of times),
251     /// the <CsScore> element is not pre-processed, but dispatched as real-time events;
252     /// and performance continues indefinitely, or until ended by calling [`Csound::stop`](struct.Csound.html#method.stop) or some other logic.
253     /// In this "real-time" mode, the sequence of calls should be:
254     /// ```
255     /// let csound  = Csound::new();
256     /// csound.set_option("-an_option");
257     /// csound.set_option("-another_option");
258     /// csound.start();
259     /// csound.compile_csd(csd_filename);
260     /// while true{
261     ///     // Send realtime events
262     ///     csound.send_score_event("i 1 0 5 4.5 6.2");
263     ///     //...
264     ///     // some logic to break the loop after a performance of realtime events
265     /// }
266     /// ```
267     /// *Note*: this function can be called repeatedly during performance to replace or add new instruments and events.
268     /// But if csoundCompileCsd is called before csoundStart, the <CsOptions> element is used,the <CsScore> section is pre-processed and dispatched normally,
269     /// and performance terminates when the score terminates, or [`Csound::stop`](struct.Csound.html#method.stop)  is called.
270     ///  In this "non-real-time" mode (which can still output real-time audio and handle real-time events), the sequence of calls should be:
271     ///  ```
272     ///  let csound  = Csound::new();
273     ///  csound.compile_csd(csd_filename);
274     ///  csound.start();
275     ///  while !csound.perform_ksmps() {
276     ///  }
277     ///  ```
278     /// # Arguments
279     /// * `csd` A reference to .csd file name
compile_csd<T>(&self, csd: T) -> Result<(), &'static str> where T: AsRef<str>,280     pub fn compile_csd<T>(&self, csd: T) -> Result<(), &'static str>
281     where
282         T: AsRef<str>,
283     {
284         let path = Trampoline::convert_str_to_c(csd)?;
285         unsafe {
286             match csound_sys::csoundCompileCsd(self.engine.csound, path.as_ptr()) {
287                 csound_sys::CSOUND_SUCCESS => Ok(()),
288                 _ => Err("Can't compile the csd file"),
289             }
290         }
291     }
292 
293     /// Behaves the same way as [`Csound::compile_csd`](struct.Csound.html#method.compile_csd),
294     /// except that the content of the CSD is read from a string rather than from a file.
295     /// This is convenient when it is desirable to package the csd as part of an application or a multi-language piece.
296     /// # Arguments
297     /// * `csd_text` A reference to the text to be compiled by csound
compile_csd_text<T>(&self, csdText: T) -> Result<(), &'static str> where T: AsRef<str>,298     pub fn compile_csd_text<T>(&self, csdText: T) -> Result<(), &'static str>
299     where
300         T: AsRef<str>,
301     {
302         let path = Trampoline::convert_str_to_c(csdText)?;
303         unsafe {
304             match csound_sys::csoundCompileCsdText(self.engine.csound, path.as_ptr()) {
305                 csound_sys::CSOUND_SUCCESS => Ok(()),
306                 _ => Err("Can't compile the csd file"),
307             }
308         }
309     }
310 
311     /// Parses and compiles the given orchestra from an ASCII string, also evaluating any global space code (i-time only)
312     /// this can be called during performance to compile a new orchestra.
313     /// ```
314     /// let csound  = Csound::new();
315     /// let orc_code = "instr 1
316     ///                 a1 rand 0dbfs/4
317     ///                 out a1";
318     /// csound.compile_orc(orc_code);
319     /// ```
320     /// # Arguments
321     /// * `orcPath` A reference to orchestra strings
compile_orc<T>(&self, orc: T) -> Result<(), &'static str> where T: AsRef<str>,322     pub fn compile_orc<T>(&self, orc: T) -> Result<(), &'static str>
323     where
324         T: AsRef<str>,
325     {
326         let path = Trampoline::convert_str_to_c(orc)?;
327         unsafe {
328             match csound_sys::csoundCompileOrc(self.engine.csound, path.as_ptr()) {
329                 csound_sys::CSOUND_SUCCESS => Ok(()),
330                 _ => Err("Can't to compile orc file"),
331             }
332         }
333     }
334 
335     /// Async version of [`Csound::compile_orc`](struct.Csound.html#method.compile_orc). The code is parsed and compiled,
336     /// then placed on a queue for asynchronous merge into the running engine, and evaluation.
337     /// The function returns following parsing and compilation.
338     /// # Arguments
339     /// * `orc` A reference to an csound's orchestra definitions
compile_orc_async<T>(&self, orc: T) -> Result<(), &'static str> where T: AsRef<str>,340     pub fn compile_orc_async<T>(&self, orc: T) -> Result<(), &'static str>
341     where
342         T: AsRef<str>,
343     {
344         let path = Trampoline::convert_str_to_c(orc)?;
345         unsafe {
346             match csound_sys::csoundCompileOrcAsync(self.engine.csound, path.as_ptr()) {
347                 csound_sys::CSOUND_SUCCESS => Ok(()),
348                 _ => Err("Can't to compile orc file"),
349             }
350         }
351     }
352 
353     ///   Parse and compile an orchestra given on a string,
354     ///   evaluating any global space code (i-time only).
355     /// # Returns
356     ///   On SUCCESS it returns a value passed to the
357     ///   'return' opcode in global space.
358     ///       code = "i1 = 2 + 2 \n return i1 \n"
359     ///       retval = csound.eval_code(code)
eval_code<T>(&self, code: T) -> Result<f64, &'static str> where T: AsRef<str>,360     pub fn eval_code<T>(&self, code: T) -> Result<f64, &'static str>
361     where
362         T: AsRef<str>,
363     {
364         let cd = Trampoline::convert_str_to_c(code)?;
365         unsafe {
366             Ok(csound_sys::csoundEvalCode(
367                 self.engine.csound,
368                 cd.as_ptr() as _,
369             ))
370         }
371     }
372 
373     // TODO Implement csoundCompileTree functions
374 
375     /// Senses input events and performs audio output.
376     ///
377     ///  perform until: 1. the end of score is reached (positive return value), 2. an error occurs (negative return value),
378     ///  or 3. performance is stopped by calling *stop()* from another thread (zero return value).
379     ///  Note that some csf file, text or score have to be compiled first and then *start()* must be called.
380     ///  In the case of zero return value, *perform()* can be called again to continue the stopped performance.
381     ///  Otherwise, [`Csound::reset`](struct.Csound.html#method.reset) should be called to clean up after the finished or failed performance.
perform(&self) -> i32382     pub fn perform(&self) -> i32 {
383         unsafe { csound_sys::csoundPerform(self.engine.csound) as i32 }
384     }
385 
386     /// Senses input events, and performs one control sample worth ```ksmps * number of channels * size_off::<f64> bytes``` of audio output.
387     ///
388     /// Note that some csd file, text or score have to be compiled first and then [`Csound::start`](struct.Csound.html#method.start).
389     /// Enables external software to control the execution of Csound, and to synchronize
390     /// performance with audio input and output(see: [`Csound::read_spin_buffer`](struct.Csound.html#method.read_spin_buffer), [`Csound::read_spout_buffer`](struct.Csound.html#method.read_spout_buffer))
391     /// # Returns
392     /// *false* during performance, and true when performance has finished. If called until it returns *true*, will perform an entire score.
perform_ksmps(&self) -> bool393     pub fn perform_ksmps(&self) -> bool {
394         unsafe { csound_sys::csoundPerformKsmps(self.engine.csound) != 0 }
395     }
396 
397     /// Performs Csound, sensing real-time and score events and processing one buffer's worth (-b frames) of interleaved audio.
398     /// Note that some csd file, text or score have to be compiled first and then [`Csound::start`](struct.Csound.html#method.start),
399     /// you could call [`Csound::read_output_buffer`](struct.Csound.html#method.start) or
400     /// [`Csound::write_input_buffer`](struct.Csound.html#method.write_input_buffer) to write/read the csound's I/O buffers content.
401     /// #Returns
402     /// *false* during performance or *true* when performance has finished.
perform_buffer(&self) -> bool403     pub fn perform_buffer(&self) -> bool {
404         unsafe { csound_sys::csoundPerformBuffer(self.engine.csound) != 0 }
405     }
406 
407     /*********************************** UDP ****************************************************/
408 
409     /// Starts the UDP server
410     ///
411     /// # Arguments
412     /// * `port` The server port number.
413     /// # Returns
414     /// *Ok* on success or an error code on failure.
udp_server_start(&self, port: u32) -> Result<(), Status>415     pub fn udp_server_start(&self, port: u32) -> Result<(), Status> {
416         unsafe {
417             match Status::from(
418                 csound_sys::csoundUDPServerStart(self.engine.csound, port as c_int) as i32,
419             ) {
420                 Status::CS_SUCCESS => Ok(()),
421                 e => Err(e),
422             }
423         }
424     }
425 
426     /// # Returns
427     /// The port number on which the server is running, or None if the server has not been started.
udp_server_status(&self) -> Option<u32>428     pub fn udp_server_status(&self) -> Option<u32> {
429         unsafe {
430             let status = csound_sys::csoundUDPServerStatus(self.engine.csound);
431             if status == csound_sys::CSOUND_ERROR {
432                 None
433             } else {
434                 Some(status as u32)
435             }
436         }
437     }
438 
439     /// Closes the UDP server
440     /// # Returns
441     /// *Ok* if the running server was successfully closed, Status code otherwise.
udp_server_close(&self) -> Result<(), Status>442     pub fn udp_server_close(&self) -> Result<(), Status> {
443         unsafe {
444             match Status::from(csound_sys::csoundUDPServerClose(self.engine.csound) as i32) {
445                 Status::CS_SUCCESS => Ok(()),
446                 status => Err(status),
447             }
448         }
449     }
450 
451     /// Turns on the transmission of console messages
452     ///
453     /// # Arguments
454     /// * `addr` The UDP server destination address.
455     /// * `port` The UDP server port number.
456     /// * `mirror` If it is true, the messages will continue to be sent to the usual destination
457     /// (see [`Csound::message_string_callback`](struct.Csound.html#method.message_string_callback) ) as well as to UDP.
458     /// # Returns
459     /// *Ok* on success or an Status code if the UDP transmission could not be set up.
udp_console(&self, addr: &str, port: u32, mirror: bool) -> Result<(), Status>460     pub fn udp_console(&self, addr: &str, port: u32, mirror: bool) -> Result<(), Status> {
461         unsafe {
462             let ip = CString::new(addr).map_err(|_e| Status::CS_ERROR)?;
463             if csound_sys::csoundUDPConsole(
464                 self.engine.csound,
465                 ip.as_ptr(),
466                 port as c_int,
467                 mirror as c_int,
468             ) == csound_sys::CSOUND_SUCCESS
469             {
470                 return Ok(());
471             }
472             Err(Status::CS_ERROR)
473         }
474     }
475 
476     /// Stop transmitting console messages via UDP
udp_stop_console(&self)477     pub fn udp_stop_console(&self) {
478         unsafe {
479             csound_sys::csoundStopUDPConsole(self.engine.csound);
480         }
481     }
482     /* Engine Attributes functions implmentations ********************************************************* */
483 
484     /// # Returns
485     /// The number of audio sample frames per second.
get_sample_rate(&self) -> f64486     pub fn get_sample_rate(&self) -> f64 {
487         unsafe { csound_sys::csoundGetSr(self.engine.csound) as f64 }
488     }
489 
490     /// # Returns
491     /// The number of control samples per second.
get_control_rate(&self) -> f64492     pub fn get_control_rate(&self) -> f64 {
493         unsafe { csound_sys::csoundGetKr(self.engine.csound) as f64 }
494     }
495 
496     /// # Returns
497     /// The number of audio sample frames per control sample.
get_ksmps(&self) -> u32498     pub fn get_ksmps(&self) -> u32 {
499         unsafe { csound_sys::csoundGetKsmps(self.engine.csound) }
500     }
501 
502     /// # Returns
503     /// The number of audio output channels. Set through the nchnls header variable in the csd file.
output_channels(&self) -> u32504     pub fn output_channels(&self) -> u32 {
505         unsafe { csound_sys::csoundGetNchnls(self.engine.csound) as u32 }
506     }
507 
508     /// # Returns
509     /// The number of audio input channels.
510     /// Set through the **nchnls_i** header variable in the csd file.
511     /// If this variable is not set, the value is taken from nchnls.
input_channels(&self) -> u32512     pub fn input_channels(&self) -> u32 {
513         unsafe { csound_sys::csoundGetNchnlsInput(self.engine.csound) as u32 }
514     }
515     /// # Returns
516     /// The 0dBFS level of the spin/spout buffers.
get_0dBFS(&self) -> f64517     pub fn get_0dBFS(&self) -> f64 {
518         unsafe { csound_sys::csoundGet0dBFS(self.engine.csound) as f64 }
519     }
520 
521     /// # Returns
522     /// The A4 frequency reference
get_freq(&self) -> f64523     pub fn get_freq(&self) -> f64 {
524         unsafe { csound_sys::csoundGetA4(self.engine.csound) as f64 }
525     }
526 
527     /// #Returns
528     /// The current performance time in samples
get_current_sample_time(&self) -> usize529     pub fn get_current_sample_time(&self) -> usize {
530         unsafe { csound_sys::csoundGetCurrentTimeSamples(self.engine.csound) as usize }
531     }
532 
533     /// # Returns
534     /// The size of MYFLT in bytes.
get_size_myflt(&self) -> u32535     pub fn get_size_myflt(&self) -> u32 {
536         unsafe { csound_sys::csoundGetSizeOfMYFLT() as u32 }
537     }
538 
539     /// # Returns
540     /// Whether Csound is set to print debug messages.
541     /// sents through the *DebugMsg()* csouns's internal API function.
542     /// Anything different to 0 means true.
get_debug_level(&self) -> u32543     pub fn get_debug_level(&self) -> u32 {
544         unsafe { csound_sys::csoundGetDebug(self.engine.csound) as u32 }
545     }
546 
547     /// Sets whether Csound prints debug messages from the *DebugMsg()* csouns's internal API function.
548     /// # Arguments
549     /// * `level` The debug level to assign, anything different to 0 means true.
set_debug_level(&self, level: i32)550     pub fn set_debug_level(&self, level: i32) {
551         unsafe {
552             csound_sys::csoundSetDebug(self.engine.csound, level as c_int);
553         }
554     }
555 
556     /* Engine general InputOutput functions implmentations ********************************************************* */
557 
558     /// Gets the csound's input source name if it has been defined
559     /// otherwise, None is returned
get_input_name(&self) -> Option<String>560     pub fn get_input_name(&self) -> Option<String> {
561         unsafe {
562             let ptr = csound_sys::csoundGetInputName(self.engine.csound);
563             Trampoline::ptr_to_string(ptr)
564         }
565     }
566 
567     /// Gets output device name if the realtime output has been defined,
568     /// Otherwise, None is returned
get_output_name(&self) -> Option<String>569     pub fn get_output_name(&self) -> Option<String> {
570         unsafe {
571             let ptr = csound_sys::csoundGetOutputName(self.engine.csound);
572             Trampoline::ptr_to_string(ptr)
573         }
574     }
575 
576     /// Set output destination, type and format
577     /// # Arguments
578     /// * `name` The destination/device name, for RT audio use the field [`CsAudioDevice::device_id`](struct.CsAudioDevice.html#field.device_id).
579     ///  (see: [`Csound::get_audio_devices`](struct.Csound.html#method.get_audio_devices))
580     /// * `out_type`  can be one of "wav","aiff", "au","raw", "paf", "svx", "nist", "voc", "ircam","w64","mat4", "mat5", "pvf","xi", "htk","sds","avr",
581     /// "wavex","sd2", "flac", "caf","wve","ogg","mpc2k","rf64", or NULL (use default or realtime IO).
582     /// * `format` can be one of "alaw", "schar", "uchar", "float", "double", "long", "short", "ulaw", "24bit", "vorbis", or NULL (use default or realtime IO).
set_output(&self, name: &str, out_type: &str, format: &str) -> Result<(), NulError>583     pub fn set_output(&self, name: &str, out_type: &str, format: &str) -> Result<(), NulError> {
584         unsafe {
585             let devName = CString::new(name)?;
586             let devType = CString::new(out_type)?;
587             let devFormat = CString::new(format)?;
588 
589             csound_sys::csoundSetOutput(
590                 self.engine.csound,
591                 devName.as_ptr(),
592                 devType.as_ptr(),
593                 devFormat.as_ptr(),
594             );
595             Ok(())
596         }
597     }
598 
599     /// Get output type and format.
600     /// # Example
601     /// ```
602     /// let csound = Csound::new();
603     /// let (output_type, output_format) = csound.get_output_format().unwrap();
604     /// ```
get_output_format(&self) -> Result<(String, String), Utf8Error>605     pub fn get_output_format(&self) -> Result<(String, String), Utf8Error> {
606         let otype = vec![b'\0'; OUTPUT_TYPE_LENGTH];
607         let format = vec![b'\0'; OUTPUT_FORMAT_LENGTH];
608         unsafe {
609             let otype = CString::from_vec_unchecked(otype).into_raw();
610             let format = CString::from_vec_unchecked(format).into_raw();
611 
612             csound_sys::csoundGetOutputFormat(self.engine.csound, otype, format);
613 
614             let otype = CString::from_raw(otype);
615             let otype = otype.to_str()?;
616             let format = CString::from_raw(format);
617             let format = format.to_str()?;
618 
619             Ok((otype.into(), format.into()))
620         }
621     }
622 
623     /// Sets input source
624     /// # Arguments
625     /// * `name` The source device name.
set_input(&self, name: &str) -> Result<(), NulError>626     pub fn set_input(&self, name: &str) -> Result<(), NulError> {
627         unsafe {
628             let devName = CString::new(name)?;
629             csound_sys::csoundSetInput(self.engine.csound, devName.as_ptr());
630             Ok(())
631         }
632     }
633 
634     /// Set MIDI file input name
set_midi_file_input(&self, name: &str) -> Result<(), NulError>635     pub fn set_midi_file_input(&self, name: &str) -> Result<(), NulError> {
636         unsafe {
637             let devName = CString::new(name)?;
638             csound_sys::csoundSetMIDIFileInput(self.engine.csound, devName.as_ptr());
639             Ok(())
640         }
641     }
642 
643     /// Set MIDI file output name
set_midi_file_output(&self, name: &str) -> Result<(), NulError>644     pub fn set_midi_file_output(&self, name: &str) -> Result<(), NulError> {
645         unsafe {
646             let devName = CString::new(name)?;
647             csound_sys::csoundSetMIDIFileOutput(self.engine.csound, devName.as_ptr());
648             Ok(())
649         }
650     }
651 
652     /// Set MIDI input device name/number
set_midi_input(&self, name: &str) -> Result<(), NulError>653     pub fn set_midi_input(&self, name: &str) -> Result<(), NulError> {
654         unsafe {
655             let devName = CString::new(name)?;
656             csound_sys::csoundSetMIDIInput(self.engine.csound, devName.as_ptr());
657             Ok(())
658         }
659     }
660 
661     /// Set MIDI output device name
set_midi_output(&self, name: &str) -> Result<(), NulError>662     pub fn set_midi_output(&self, name: &str) -> Result<(), NulError> {
663         unsafe {
664             let devName = CString::new(name)?;
665             csound_sys::csoundSetMIDIOutput(self.engine.csound, devName.as_ptr());
666             Ok(())
667         }
668     }
669 
670     /* Engine general Realtime Audio I/O functions implmentations ********************************************************* */
671 
672     /// Sets the current RT audio module
set_rt_audio_module(&self, name: &str) -> Result<(), NulError>673     pub fn set_rt_audio_module(&self, name: &str) -> Result<(), NulError> {
674         unsafe {
675             let devName = CString::new(name)?;
676             csound_sys::csoundSetRTAudioModule(self.engine.csound, devName.as_ptr());
677             Ok(())
678         }
679     }
680 
681     /// # Returns
682     /// The number of samples in Csound's input buffer.
get_input_buffer_size(&self) -> usize683     pub fn get_input_buffer_size(&self) -> usize {
684         unsafe { csound_sys::csoundGetInputBufferSize(self.engine.csound) as usize }
685     }
686 
687     /// # Returns
688     /// The number of samples in Csound's input buffer.
get_output_buffer_size(&self) -> usize689     pub fn get_output_buffer_size(&self) -> usize {
690         unsafe { csound_sys::csoundGetOutputBufferSize(self.engine.csound) as usize }
691     }
692 
693     /// Gets the csound's input buffer.
694     /// # Returns
695     /// An Option containing either the [`BufferPtr`](struct.BufferPtr.html) or None if the
696     /// csound's input buffer has not been initialized. The returned *BufferPtr* is Writable, it means that you can modify
697     /// the csound's buffer content in order to write external audio data into csound and process it.
698     /// # Example
699     /// ```
700     /// let csound = Csound::new();
701     /// csound.compile_csd("some_file_path");
702     /// csound.start();
703     /// let input_buffer_ptr = csound.get_input_buffer();
704     /// while !csound.perform_buffer() {
705     ///     // fills your buffer with audio samples that you want to pass into csound
706     ///     foo_fill_buffer(input_buffer_ptr.as_mut_slice());
707     ///     // ...
708     /// }
709     /// ```
get_input_buffer(&self) -> Option<BufferPtr<Writable>>710     pub fn get_input_buffer(&self) -> Option<BufferPtr<Writable>> {
711         unsafe {
712             let ptr = csound_sys::csoundGetInputBuffer(self.engine.csound) as *mut f64;
713             let len = self.get_input_buffer_size();
714             if !ptr.is_null() {
715                 return Some(BufferPtr {
716                     ptr,
717                     len,
718                     phantom: PhantomData,
719                 });
720             }
721             None
722         }
723     }
724 
725     /// Gets the csound's output buffer.
726     /// # Returns
727     /// An Option containing either the [`BufferPtr`](struct.BufferPtr.html) or None if the
728     /// csound's output buffer has not been initialized. The returned *BufferPtr* is only Readable.
729     /// # Example
730     /// ```
731     /// let csound = Csound::new();
732     /// csound.compile_csd("some_file_path");
733     /// csound.start();
734     /// let output_buffer_ptr = csound.get_output_buffer();
735     /// let mut data = vec![0f64; input_buffer_ptr.get_size()];
736     /// while !csound.perform_buffer() {
737     ///     // process the data from csound
738     ///     foo_process_buffer(output_buffer_ptr.as_slice());
739     /// }
740     /// ```
get_output_buffer(&self) -> Option<BufferPtr<Readable>>741     pub fn get_output_buffer(&self) -> Option<BufferPtr<Readable>> {
742         unsafe {
743             let ptr = csound_sys::csoundGetOutputBuffer(self.engine.csound) as *mut f64;
744             let len = self.get_output_buffer_size();
745             if !ptr.is_null() {
746                 return Some(BufferPtr {
747                     ptr,
748                     len,
749                     phantom: PhantomData,
750                 });
751             }
752             None
753         }
754     }
755 
756     /// Enables external software to write audio into Csound before calling perform_ksmps.
757     /// # Returns
758     /// An Option containing either the [`BufferPtr`](struct.BufferPtr.html) or None if the
759     /// csound's spin buffer has not been initialized. The returned *BufferPtr* is Writable.
760     /// # Example
761     /// ```
762     /// let csound = Csound::new();
763     /// csound.compile_csd("some_file_path");
764     /// csound.start();
765     /// let spin = csound.get_spin();
766     /// while !csound.perform_ksmps() {
767     ///     // fills the spin buffer with audio samples that you want to pass into csound
768     ///     foo_fill_buffer(spin.as_mut_slice());
769     ///     // ...
770     /// }
771     /// ```
get_spin(&self) -> Option<BufferPtr<Writable>>772     pub fn get_spin(&self) -> Option<BufferPtr<Writable>> {
773         unsafe {
774             let ptr = csound_sys::csoundGetSpin(self.engine.csound) as *mut f64;
775             let len = (self.get_ksmps() * self.input_channels()) as usize;
776             if !ptr.is_null() {
777                 return Some(BufferPtr {
778                     ptr,
779                     len,
780                     phantom: PhantomData,
781                 });
782             }
783             None
784         }
785     }
786 
787     /// Enables external software to read audio from  Csound before calling perform_ksmps.
788     /// # Returns
789     /// An Option containing either the [`BufferPtr`](struct.BufferPtr.html) or None if the
790     /// csound's spout buffer has not been initialized. The returned *BufferPtr* is only Readable.
791     /// # Example
792     /// ```
793     /// let csound = Csound::new();
794     /// csound.compile_csd("some_file_path");
795     /// csound.start();
796     /// let spout = csound.get_spout();
797     /// while !csound.perform_ksmps() {
798     ///     // Deref the spout pointer and read its content
799     ///     foo_read_buffer(&*spout);
800     ///     // ...
801     /// }
802     /// ```
get_spout(&self) -> Option<BufferPtr<Readable>>803     pub fn get_spout(&self) -> Option<BufferPtr<Readable>> {
804         unsafe {
805             let ptr = csound_sys::csoundGetSpout(self.engine.csound) as *mut f64;
806             let len = (self.get_ksmps() * self.output_channels()) as usize;
807             if !ptr.is_null() {
808                 return Some(BufferPtr {
809                     ptr,
810                     len,
811                     phantom: PhantomData,
812                 });
813             }
814             None
815         }
816     }
817 
818     /// Method used when you want to copy audio samples from the csound's output buffer.
819     /// # Arguments
820     /// * `out` a reference to a mutable slice where the Csound's output buffer content
821     /// will be copied.  This buffer have to has enough memory for at least
822     /// [`Csound::get_output_buffer_size`](struct.Csound.html#method.get_output_buffer_size), samples.
823     /// # Returns
824     /// The number of samples copied into the slice on success, or an
825     /// error message if the internal csound's buffer has not been initialized.
826     /// # Example
827     /// ```
828     /// let csound = Csound::new();
829     /// csound.compile_csd("some_file_path");
830     /// csound.start();
831     /// let output_buffer_length = csound.get_output_buffer_size();
832     /// let mut output_buffer = vec![0f64; output_buffer_length];
833     /// while !csound.perform_buffer() {
834     ///     csound.read_output_buffer(&mut output_buffer).unwrap();
835     ///     // ... do some stuff with the buffer
836     /// }
837     /// ```
838     /// # Deprecated
839     /// Use [`Csound::get_output_buffer`](struct.Csound.html#method.get_output_buffer) to get a [`BufferPtr`](struct.BufferPtr.html)
840     /// object.
841     #[deprecated(
842         since = "0.1.5",
843         note = "please use Csound::get_output_buffer object instead"
844     )]
read_output_buffer(&self, output: &mut [f64]) -> Result<usize, &'static str>845     pub fn read_output_buffer(&self, output: &mut [f64]) -> Result<usize, &'static str> {
846         let size = self.get_output_buffer_size();
847         let obuffer =
848             unsafe { csound_sys::csoundGetOutputBuffer(self.engine.csound) as *const f64 };
849         let mut len = output.len();
850         if size < len {
851             len = size;
852         }
853         if !obuffer.is_null() {
854             unsafe {
855                 std::ptr::copy(obuffer, output.as_ptr() as *mut f64, len);
856                 return Ok(len);
857             }
858         }
859         Err("The output buffer is not initialized, call the 'compile()' and 'start()' methods.")
860     }
861 
862     /// Method used when you want to copy custom audio samples into the csound buffer to be processed.
863     /// # Arguments
864     /// * `input` a reference to a slice with samples which will be copied to
865     /// the Csound's input buffer.
866     /// # Returns
867     /// The number of samples copied into the csound's input buffer or an
868     /// error message if the internal csound's buffer has not been initialized.
869     /// # Example
870     /// ```
871     /// let csound = Csound::new();
872     /// csound.compile_csd("some_file_path");
873     /// csound.start();
874     /// let input_buffer_length = csound.get_input_buffer_size();
875     /// let mut input_buffer = vec![0f64; output_buffer_length];
876     /// while !csound.perform_buffer() {
877     ///     // fills your buffer with audio samples you want to pass into csound
878     ///     foo_fill_buffer(&mut input_buffer);
879     ///     csound.write_input_buffer(&input_buffer);
880     ///     // ...
881     /// }
882     /// ```
883     /// # Deprecated
884     /// Use [`Csound::get_input_buffer`](struct.Csound.html#method.get_input_buffer) to get a [`BufferPtr`](struct.BufferPtr.html)
885     /// object.
886     #[deprecated(
887         since = "0.1.5",
888         note = "please use Csound::get_input_buffer object instead"
889     )]
write_input_buffer(&self, input: &[f64]) -> Result<usize, &'static str>890     pub fn write_input_buffer(&self, input: &[f64]) -> Result<usize, &'static str> {
891         let size = self.get_input_buffer_size();
892         let ibuffer = unsafe { csound_sys::csoundGetInputBuffer(self.engine.csound) as *mut f64 };
893         let mut len = input.len();
894         if size < len {
895             len = size;
896         }
897         if !ibuffer.is_null() {
898             unsafe {
899                 std::ptr::copy(input.as_ptr(), ibuffer, len);
900                 return Ok(len);
901             }
902         }
903         Err("The input buffer is not initialized, call the 'compile()' and 'start()' methods.")
904     }
905 
906     /// Enables external software to read audio from Csound after calling [`Csound::perform_ksmps`](struct.Csound.html#method.perform_ksmps)
907     /// # Returns
908     /// The number of samples copied  or an
909     /// error message if the internal csound's buffer has not been initialized.
910     /// # Example
911     /// ```
912     /// let csound = Csound::new();
913     /// csound.compile_csd("some_file_path");
914     /// csound.start();
915     /// let spout_length = csound.get_ksmps() * csound.output_channels();
916     /// let mut spout_buffer = vec![0f64; spout_length as usize];
917     /// while !csound.perform_ksmps() {
918     ///     // fills your buffer with audio samples you want to pass into csound
919     ///     foo_fill_buffer(&mut spout_buffer);
920     ///     csound.read_spout_buffer(&spout_buffer);
921     ///     // ...
922     /// }
923     /// ```
924     /// # Deprecated
925     /// Use [`Csound::get_spout`](struct.Csound.html#method.get_spout) to get a [`BufferPtr`](struct.BufferPtr.html)
926     /// object.
927     #[deprecated(since = "0.1.5", note = "please use Csound::get_spout object instead")]
read_spout_buffer(&self, output: &mut [f64]) -> Result<usize, &'static str>928     pub fn read_spout_buffer(&self, output: &mut [f64]) -> Result<usize, &'static str> {
929         let size = self.get_ksmps() as usize * self.output_channels() as usize;
930         let spout = unsafe { csound_sys::csoundGetSpout(self.engine.csound) as *const f64 };
931         let mut len = output.len();
932         if size < len {
933             len = size;
934         }
935         if !spout.is_null() {
936             unsafe {
937                 std::ptr::copy(spout, output.as_mut_ptr(), len);
938                 return Ok(len);
939             }
940         }
941         Err("The spout buffer is not initialized, call the 'compile()' and 'start()' methods.")
942     }
943 
944     /// Enables external software to write audio into Csound before calling [`Csound::perform_ksmps`](struct.Csound.html#method.perform_ksmps)
945     /// [`Csound::get_ksmps`](struct.Csound.html#method.get_ksmps) * [`Csound::input_channels`](struct.Csound.html#method.input_channels).
946     /// # Returns
947     /// The number of samples copied  or an
948     /// error message if the internal csound's buffer has not been initialized.
949     /// # Example
950     /// ```
951     /// let csound = Csound::new();
952     /// csound.compile_csd("some_file_path");
953     /// csound.start();
954     /// let spin_length = csound.get_ksmps() * csound.input_channels();
955     /// let mut spin_buffer = vec![0f64; spin_length as usize];
956     /// while !csound.perform_ksmps() {
957     ///     // fills your buffer with audio samples you want to pass into csound
958     ///     foo_fill_buffer(&mut spin_buffer);
959     ///     csound.write_spin_buffer(&spin_buffer);
960     ///     // ...
961     /// }
962     /// ```
963     /// # Deprecated
964     /// Use [`Csound::get_spin`](struct.Csound.html#method.get_spin) to get a [`BufferPtr`](struct.BufferPtr.html)
965     /// object.
966     #[deprecated(since = "0.1.5", note = "please use Csound::get_spin object instead")]
write_spin_buffer(&self, input: &[f64]) -> Result<usize, &'static str>967     pub fn write_spin_buffer(&self, input: &[f64]) -> Result<usize, &'static str> {
968         let size = self.get_ksmps() as usize * self.input_channels() as usize;
969         let spin = unsafe { csound_sys::csoundGetSpin(self.engine.csound) as *mut f64 };
970         let mut len = input.len();
971         if size < len {
972             len = size;
973         }
974         if !spin.is_null() {
975             unsafe {
976                 std::ptr::copy(input.as_ptr(), spin, len);
977                 return Ok(len);
978             }
979         }
980         Err("The spin buffer is not initialized, call the 'compile()' and 'start()' methods.")
981     }
982 
983     /// Clears the spin buffer.
clear_spin(&self)984     pub fn clear_spin(&self) {
985         unsafe {
986             csound_sys::csoundClearSpin(self.engine.csound);
987         }
988     }
989 
990     /// Adds the indicated sample into the audio input working buffer (spin);
991     ///  this only ever makes sense before calling [`Csound::perform_ksmps`](struct.Csound.html#method.perform_ksmps).
992     ///  The frame and channel must be in bounds relative to ksmps and nchnls.
993     /// *Note*:  the spin buffer needs to be cleared at every k-cycle by calling [`Csound::clear_spin`](struct.Csound.html#method.clear_spin).
add_spin_sample(&self, frame: u32, channel: u32, sample: f64)994     pub fn add_spin_sample(&self, frame: u32, channel: u32, sample: f64) {
995         unsafe {
996             csound_sys::csoundAddSpinSample(
997                 self.engine.csound,
998                 frame as i32,
999                 channel as i32,
1000                 sample as c_double,
1001             );
1002         }
1003     }
1004 
1005     /// Sets the audio input working buffer (spin) to the indicated sample.
1006     /// this only ever makes sense before calling [`Csound::perform_ksmps`](struct.Csound.html#method.perform_ksmps).
1007     /// The frame and channel must be in bounds relative to ksmps and nchnls.
set_spin_sample(&self, frame: u32, channel: u32, sample: f64)1008     pub fn set_spin_sample(&self, frame: u32, channel: u32, sample: f64) {
1009         unsafe {
1010             csound_sys::csoundSetSpinSample(
1011                 self.engine.csound,
1012                 frame as i32,
1013                 channel as i32,
1014                 sample as c_double,
1015             );
1016         }
1017     }
1018 
1019     /// Gets an audio sample from the spout buffer.
1020     /// only ever makes sense before calling [`Csound::perform_ksmps`](struct.Csound.html#method.perform_ksmps).
1021     /// The frame and channel must be in bounds relative to ksmps and nchnls.
1022     /// #Returns
1023     /// The indicated sample from the Csound audio output working buffer (spout).
get_spout_sample(&self, frame: u32, channel: u32) -> f641024     pub fn get_spout_sample(&self, frame: u32, channel: u32) -> f64 {
1025         unsafe {
1026             csound_sys::csoundGetSpoutSample(self.engine.csound, frame as i32, channel as i32)
1027                 as f64
1028         }
1029     }
1030 
1031     /// Enable to host to handle the audio implementation.
1032     /// Calling this function with a non-zero 'state' value between [`Csound::create`](struct.Csound.html#method.create) and the start of performance will disable
1033     /// all default handling of sound I/O by the Csound library,
1034     /// allowing the host application to use the *spin*,*spout*,*input*, *output* buffers directly.
1035     /// # Arguments
1036     /// * `state` An no zero value will diseable all default handling of sound I/O in csound.
1037     /// * `bufSize` For applications using *spin* / *spout*, this argument should be set to 0 but if *bufSize* is greater than zero, the buffer size (-b) in frames will be set to the integer
1038     /// multiple of ksmps that is nearest to the value specified.
set_host_implemented_audioIO(&self, state: u32, bufSize: u32)1039     pub fn set_host_implemented_audioIO(&self, state: u32, bufSize: u32) {
1040         unsafe {
1041             csound_sys::csoundSetHostImplementedAudioIO(
1042                 self.engine.csound,
1043                 state as c_int,
1044                 bufSize as c_int,
1045             );
1046         }
1047     }
1048 
1049     /// This function can be called to obtain a list of available input and output audio devices.
1050     /// # Returns
1051     /// A tuple, being input devices the first element in the returned tuple, output devices the
1052     /// second one.
get_audio_devices(&self) -> (Vec<CsAudioDevice>, Vec<CsAudioDevice>)1053     pub fn get_audio_devices(&self) -> (Vec<CsAudioDevice>, Vec<CsAudioDevice>) {
1054         let mut input_devices = Vec::new();
1055         let mut output_devices = Vec::new();
1056 
1057         unsafe {
1058             let num_of_idevices =
1059                 csound_sys::csoundGetAudioDevList(self.engine.csound, ptr::null_mut(), 0);
1060             let num_of_odevices =
1061                 csound_sys::csoundGetAudioDevList(self.engine.csound, ptr::null_mut(), 0);
1062 
1063             let mut in_vec = vec![csound_sys::CS_AUDIODEVICE::default(); num_of_idevices as usize];
1064             let mut out_vec = vec![csound_sys::CS_AUDIODEVICE::default(); num_of_odevices as usize];
1065 
1066             csound_sys::csoundGetAudioDevList(self.engine.csound, in_vec.as_mut_ptr(), 0);
1067             csound_sys::csoundGetAudioDevList(self.engine.csound, out_vec.as_mut_ptr(), 1);
1068 
1069             for dev in &in_vec {
1070                 input_devices.push(CsAudioDevice {
1071                     device_name: Trampoline::ptr_to_string(dev.device_name.as_ptr()),
1072                     device_id: Trampoline::ptr_to_string(dev.device_id.as_ptr()),
1073                     rt_module: Trampoline::ptr_to_string(dev.rt_module.as_ptr()),
1074                     max_nchnls: dev.max_nchnls as u32,
1075                     isOutput: 0,
1076                 });
1077             }
1078             for dev in &out_vec {
1079                 output_devices.push(CsAudioDevice {
1080                     device_name: Trampoline::ptr_to_string(dev.device_name.as_ptr()),
1081                     device_id: Trampoline::ptr_to_string(dev.device_id.as_ptr()),
1082                     rt_module: Trampoline::ptr_to_string(dev.rt_module.as_ptr()),
1083                     max_nchnls: dev.max_nchnls as u32,
1084                     isOutput: 1,
1085                 });
1086             }
1087         }
1088         (input_devices, output_devices)
1089     }
1090 
1091     /* Real time MIDI IO functions implementations *************************************************************** */
1092 
1093     /// Sets the current MIDI IO module
set_midi_module(&self, name: &str)1094     pub fn set_midi_module(&self, name: &str) {
1095         unsafe {
1096             let devName = CString::new(name);
1097             if let Ok(dev) = devName {
1098                 let dev_name = dev;
1099                 csound_sys::csoundSetMIDIModule(self.engine.csound, dev_name.as_ptr());
1100             }
1101         }
1102     }
1103 
1104     /// call this function with state 1 if the host is going to implement MIDI through the callbacks
set_host_implemented_midiIO(&self, state: u32)1105     pub fn set_host_implemented_midiIO(&self, state: u32) {
1106         unsafe {
1107             csound_sys::csoundSetHostImplementedMIDIIO(self.engine.csound, state as c_int);
1108         }
1109     }
1110 
1111     /// This function can be called to obtain a list of available input or output midi devices.
1112     /// # Returns
1113     /// A tuple with two vectors, beign the first one for input MIDI
1114     /// devices and the second one for output MIDI devices
get_midi_devices(&self) -> (Vec<CsMidiDevice>, Vec<CsMidiDevice>)1115     pub fn get_midi_devices(&self) -> (Vec<CsMidiDevice>, Vec<CsMidiDevice>) {
1116         let mut input_devices = Vec::new();
1117         let mut output_devices = Vec::new();
1118 
1119         unsafe {
1120             let num_of_idevices =
1121                 csound_sys::csoundGetMIDIDevList(self.engine.csound, ptr::null_mut(), 0);
1122             let num_of_odevices =
1123                 csound_sys::csoundGetMIDIDevList(self.engine.csound, ptr::null_mut(), 0);
1124 
1125             let mut in_vec = vec![csound_sys::CS_MIDIDEVICE::default(); num_of_idevices as usize];
1126             let mut out_vec = vec![csound_sys::CS_MIDIDEVICE::default(); num_of_odevices as usize];
1127 
1128             csound_sys::csoundGetMIDIDevList(self.engine.csound, in_vec.as_mut_ptr(), 0);
1129             csound_sys::csoundGetMIDIDevList(self.engine.csound, out_vec.as_mut_ptr(), 1);
1130 
1131             for dev in &in_vec {
1132                 input_devices.push(CsMidiDevice {
1133                     device_name: Trampoline::ptr_to_string(dev.device_name.as_ptr()),
1134                     device_id: Trampoline::ptr_to_string(dev.device_id.as_ptr()),
1135                     midi_module: Trampoline::ptr_to_string(dev.midi_module.as_ptr()),
1136                     interface_name: Trampoline::ptr_to_string(dev.interface_name.as_ptr()),
1137                     isOutput: 0,
1138                 });
1139             }
1140             for dev in &out_vec {
1141                 output_devices.push(CsMidiDevice {
1142                     device_name: Trampoline::ptr_to_string(dev.device_name.as_ptr()),
1143                     device_id: Trampoline::ptr_to_string(dev.device_id.as_ptr()),
1144                     midi_module: Trampoline::ptr_to_string(dev.midi_module.as_ptr()),
1145                     interface_name: Trampoline::ptr_to_string(dev.interface_name.as_ptr()),
1146                     isOutput: 1,
1147                 });
1148             }
1149         }
1150         (input_devices, output_devices)
1151     }
1152 
1153     /* Score Handling functions implmentations ********************************************************* */
1154 
1155     /// Reads, preprocesses, and loads a score from an ASCII string.
1156     /// It can be called repeatedly with the new score events being added to the currently scheduled ones.
read_score(&self, score: &str) -> Result<(), &'static str>1157     pub fn read_score(&self, score: &str) -> Result<(), &'static str> {
1158         unsafe {
1159             let s = Trampoline::convert_str_to_c(score)?;
1160             if csound_sys::csoundReadScore(self.engine.csound, s.as_ptr())
1161                 == csound_sys::CSOUND_SUCCESS
1162             {
1163                 return Ok(());
1164             }
1165             Err("Invalid score")
1166         }
1167     }
1168 
1169     /// Asynchronous version of [`Csound::read_score`](struct.Csound.html#method.read_score)
read_score_async(&self, score: &str) -> Result<(), &'static str>1170     pub fn read_score_async(&self, score: &str) -> Result<(), &'static str> {
1171         unsafe {
1172             let s = Trampoline::convert_str_to_c(score)?;
1173             csound_sys::csoundReadScoreAsync(self.engine.csound, s.as_ptr());
1174             Ok(())
1175         }
1176     }
1177 
1178     /// # Returns
1179     /// The current score time in seconds since the beginning of the performance.
get_score_time(&self) -> f641180     pub fn get_score_time(&self) -> f64 {
1181         unsafe { csound_sys::csoundGetScoreTime(self.engine.csound) as f64 }
1182     }
1183 
1184     /// Sets whether Csound score events are performed or not.
1185     /// Independently of real-time MIDI events (see [`Csound::set_score_pending`](struct.Csound.html#method.set_score_pending)).
is_score_pending(&self) -> i321186     pub fn is_score_pending(&self) -> i32 {
1187         unsafe { csound_sys::csoundIsScorePending(self.engine.csound) as i32 }
1188     }
1189 
1190     /// Sets whether Csound score events are performed or not (real-time events will continue to be performed).
1191     ///  Can be used by external software, such as a VST host, to turn off performance of score events (while continuing to perform real-time events),
1192     ///  for example to mute a Csound score while working on other tracks of a piece, or to play the Csound instruments live.
set_score_pending(&self, pending: i32)1193     pub fn set_score_pending(&self, pending: i32) {
1194         unsafe {
1195             csound_sys::csoundSetScorePending(self.engine.csound, pending as c_int);
1196         }
1197     }
1198 
1199     /// Gets the current score's time.
1200     /// # Returns
1201     /// The score time beginning at which score events will actually immediately be performed
1202     /// (see  [`Csound::set_score_offset_seconds`](struct.Csound.html#method.set_score_offset_seconds)).
get_score_offset_seconds(&self) -> f641203     pub fn get_score_offset_seconds(&self) -> f64 {
1204         unsafe { csound_sys::csoundGetScoreOffsetSeconds(self.engine.csound) as f64 }
1205     }
1206 
1207     /// Csound score events prior to the specified time are not performed.
1208     /// And performance begins immediately at the specified time
1209     /// (real-time events will continue to be performed as they are received).
1210     /// Can be used by external software, such as a VST host, to begin score performance midway through a Csound score,
1211     ///  for example to repeat a loop in a sequencer or to synchronize other events with the Csound score.
set_score_offset_seconds(&self, offset: f64)1212     pub fn set_score_offset_seconds(&self, offset: f64) {
1213         unsafe {
1214             csound_sys::csoundSetScoreOffsetSeconds(self.engine.csound, offset as c_double);
1215         }
1216     }
1217 
1218     /// Rewinds a compiled Csound score to the time specified with [`Csound::set_score_offset_seconds`](struct.Csound.html#method.set_score_offset_seconds)
rewind_score(&self)1219     pub fn rewind_score(&self) {
1220         unsafe {
1221             csound_sys::csoundRewindScore(self.engine.csound);
1222         }
1223     }
1224     // TODO SCORE SORT FUNCTIONS
1225 
1226     /* Engine general messages functions implmentations ********************************************************* */
1227 
1228     /// # Returns
1229     /// The Csound message level (from 0 to 231).
get_message_level(&self) -> u81230     pub fn get_message_level(&self) -> u8 {
1231         unsafe { csound_sys::csoundGetMessageLevel(self.engine.csound) as u8 }
1232     }
1233 
1234     /// Sets the Csound message level (from 0 to 231).
set_message_level(&self, level: u8)1235     pub fn set_message_level(&self, level: u8) {
1236         unsafe {
1237             csound_sys::csoundSetMessageLevel(self.engine.csound, level as c_int);
1238         }
1239     }
1240 
1241     /// Creates a buffer for storing messages printed by Csound. Should be called after creating a Csound instance and the buffer can be freed by
1242     /// calling [`Csound::destroy_message_buffer`](struct.Csound.html#method.destroy_message_buffer) or it will freed when the csound instance is dropped.
1243     /// You will generally want to call [`Csound::cleanup`](struct.Csound.html#method.cleanup) to make sure the last messages are flushed to the message buffer before destroying Csound.
1244     /// # Arguments
1245     /// * `stdout` If is non-zero, the messages are also printed to stdout and stderr (depending on the type of the message), in addition to being stored in the buffer.
1246     /// *Note*: Using the message buffer ties up the internal message callback,
1247     /// so [`Csound::message_string_callback`](struct.Csound.html#method.message_string_callback) should not be called after creating the message buffer.
create_message_buffer(&self, stdout: i32)1248     pub fn create_message_buffer(&self, stdout: i32) {
1249         unsafe {
1250             csound_sys::csoundCreateMessageBuffer(self.engine.csound, stdout as c_int);
1251             let mut msg_buff = self.engine.use_msg_buffer.borrow_mut();
1252             *msg_buff = true;
1253         }
1254     }
1255 
1256     /// Releases all memory used by the message buffer.
1257     /// If this buffer is created, the Drop method
1258     /// will call this function when the Csound instance were dropped.
destroy_message_buffer(&self)1259     pub fn destroy_message_buffer(&self) {
1260         unsafe {
1261             csound_sys::csoundDestroyMessageBuffer(self.engine.csound);
1262             let mut msg_buff = self.engine.use_msg_buffer.borrow_mut();
1263             *msg_buff = false;
1264         }
1265     }
1266 
1267     /// # Returns
1268     /// The first message from the buffer.
get_first_message(&self) -> Option<String>1269     pub fn get_first_message(&self) -> Option<String> {
1270         unsafe {
1271             match CStr::from_ptr(csound_sys::csoundGetFirstMessage(self.engine.csound)).to_str() {
1272                 Ok(m) => Some(m.to_owned()),
1273                 _ => None,
1274             }
1275         }
1276     }
1277 
1278     /// # Returns
1279     /// The attribute parameter ([`MessageType`](enum.MessageType.html)) of the first message in the buffer.
get_first_message_attr(&self) -> MessageType1280     pub fn get_first_message_attr(&self) -> MessageType {
1281         unsafe {
1282             MessageType::from(csound_sys::csoundGetFirstMessageAttr(self.engine.csound) as u32)
1283         }
1284     }
1285 
1286     /// Removes the first message from the buffer.
pop_first_message(&self)1287     pub fn pop_first_message(&self) {
1288         unsafe {
1289             csound_sys::csoundPopFirstMessage(self.engine.csound);
1290         }
1291     }
1292 
1293     /// # Returns
1294     /// The number of pending messages in the buffer.
get_message_count(&self) -> u321295     pub fn get_message_count(&self) -> u32 {
1296         unsafe { csound_sys::csoundGetMessageCnt(self.engine.csound) as u32 }
1297     }
1298 
1299     /* Engine general Channels, Control and Events implementations ********************************************** */
1300 
1301     /// Requests a list of all control channels.
1302     /// # Returns
1303     /// A vector with all control channels info or None if there are not control channels. see: [`ChannelInfo`](struct.ChannelInfo.html)
list_channels(&self) -> Option<Vec<ChannelInfo>>1304     pub fn list_channels(&self) -> Option<Vec<ChannelInfo>> {
1305         let mut ptr = ptr::null_mut() as *mut csound_sys::controlChannelInfo_t;
1306         let ptr2: *mut *mut csound_sys::controlChannelInfo_t = &mut ptr as *mut *mut _;
1307 
1308         unsafe {
1309             let count = csound_sys::csoundListChannels(self.engine.csound, ptr2) as i32;
1310             let mut ptr = *ptr2;
1311 
1312             if count > 0 {
1313                 let mut list = Vec::new();
1314                 for _ in 0..count {
1315                     let name = match Trampoline::ptr_to_string((*ptr).name) {
1316                         Some(string) => string,
1317                         None => "".into(),
1318                     };
1319 
1320                     let ctype = (*ptr).type_ as i32;
1321                     let hints = (*ptr).hints;
1322 
1323                     let attributes = match Trampoline::ptr_to_string(hints.attributes) {
1324                         Some(string) => string,
1325                         None => "".into(),
1326                     };
1327 
1328                     list.push(ChannelInfo {
1329                         name,
1330                         type_: ctype,
1331                         hints: ChannelHints {
1332                             behav: ChannelBehavior::from_u32(hints.behav as u32),
1333                             dflt: hints.dflt as f64,
1334                             min: hints.min as f64,
1335                             max: hints.max as f64,
1336                             x: hints.x as i32,
1337                             y: hints.y as i32,
1338                             width: hints.width as i32,
1339                             height: hints.height as i32,
1340                             attributes,
1341                         },
1342                     });
1343                     ptr = ptr.add(1);
1344                 }
1345                 csound_sys::csoundDeleteChannelList(self.engine.csound, *ptr2);
1346                 return Some(list);
1347             }
1348             None
1349         }
1350     }
1351 
1352     /// Return a [`InputChannel`](struct.InputChannel.html) which represent a csound's input channel ptr.
1353     /// creating the channel first if it does not exist yet.
1354     /// # Arguments
1355     /// * `name` The channel name.
1356     /// *
1357     /// The generic parameter `T` in this function can be one of the following types:
1358     ///  - ControlChannel
1359     ///     control data (one MYFLT value)
1360     ///  - AudioChannel
1361     ///     audio data (get_ksmps() f64 values)
1362     ///  - StrChannel:
1363     ///     string data (u8 values with enough space to store
1364     ///     get_channel_data_size() characters, including the
1365     ///     NULL character at the end of the string)
1366     /// If the channel already exists, it must match the data type
1367     /// (control, audio, or string)
1368     /// # Note
1369     ///  Audio and String channels
1370     /// can only be created after calling compile(), because the
1371     /// storage size is not known until then.
1372     /// # Returns
1373     /// A  Writable InputChannel on success or a Status code,
1374     ///   "Not enough memory for allocating the channel" (CS_MEMORY)
1375     ///   "The specified name or type is invalid" (CS_ERROR)
1376     /// or, if a channel with the same name but incompatible type
1377     /// already exists, the type of the existing channel.
1378     /// * Note: to find out the type of a channel without actually
1379     /// creating or changing it, set 'channel_type' argument  to CSOUND_UNKNOWN_CHANNEL, so that the error
1380     /// value will be either the type of the channel, or CSOUND_ERROR
1381     /// if it does not exist.
1382     /// Operations on the channel pointer are not thread-safe by default. The host is
1383     /// required to take care of threadsafety by
1384     ///   1) with control channels use __sync_fetch_and_add() or
1385     ///      __sync_fetch_and_or() gcc atomic builtins to get or set a channel,
1386     ///      if available.
1387     ///   2) For string and audio channels (and controls if option 1 is not
1388     ///      available), retrieve the channel lock with ChannelLock()
1389     ///      and use SpinLock() and SpinUnLock() to protect access
1390     ///      to the channel.
1391     /// See Top/threadsafe.c in the Csound library sources for
1392     /// examples. Optionally, use the channel get/set functions
1393     /// which are threadsafe by default.
1394     ///
1395     /// # Example
1396     /// ```text
1397     /// extern crate csound;
1398     /// use csound::{Csound, InputChannel, AudioChannel, StrChannel, ControlChannel};
1399     ///  // Creates a Csound instance
1400     /// let csound = Csound::new();
1401     /// csound.compile_csd(csd_filename).unwrap();
1402     /// csound.start();
1403     /// // Request a csound's input control channel
1404     /// let control_channel = csound.get_input_channel::<ControlChannel>("myChannel").unwrap();
1405     /// // Writes some data to the channel
1406     /// println!("channel value {}", control_channel.read());
1407     /// // Request a csound's input audio channel
1408     /// let audio_channel = csound.get_input_channel::<AudioChannle>("myAudioChannel").unwrap();
1409     /// println!("audio channel samples {:?}", audio_channel.read() );
1410     /// // Request a csound's input string channel
1411     /// let string_channel = csound.get_input_channel::<StrChannel>("myStringChannel").unwrap();
1412     ///
1413     /// ```
get_input_channel<T>(&self, name: &str) -> Result<InputChannel<T>, Status> where T: IsChannel,1414     pub fn get_input_channel<T>(&self, name: &str) -> Result<InputChannel<T>, Status>
1415     where
1416         T: IsChannel,
1417     {
1418         let mut ptr = ptr::null_mut() as *mut f64;
1419         let ptr = &mut ptr as *mut *mut _;
1420         let len;
1421         let bits;
1422 
1423         match T::c_type() {
1424             ControlChannelType::CSOUND_AUDIO_CHANNEL => {
1425                 len = self.get_ksmps() as usize;
1426                 bits =
1427                     (csound_sys::CSOUND_AUDIO_CHANNEL | csound_sys::CSOUND_INPUT_CHANNEL) as c_int;
1428             }
1429             ControlChannelType::CSOUND_CONTROL_CHANNEL => {
1430                 len = 1;
1431                 bits = (csound_sys::CSOUND_CONTROL_CHANNEL | csound_sys::CSOUND_INPUT_CHANNEL)
1432                     as c_int;
1433             }
1434             ControlChannelType::CSOUND_STRING_CHANNEL => {
1435                 len = self.get_channel_data_size(name) as usize;
1436                 bits =
1437                     (csound_sys::CSOUND_STRING_CHANNEL | csound_sys::CSOUND_INPUT_CHANNEL) as c_int;
1438             }
1439             _ => unimplemented!(),
1440         }
1441 
1442         unsafe {
1443             let result = Status::from(self.get_raw_channel_ptr(name, ptr, bits));
1444             match result {
1445                 Status::CS_SUCCESS => Ok(InputChannel {
1446                     ptr: *ptr,
1447                     len,
1448                     phantom: PhantomData,
1449                 }),
1450                 Status::CS_OK(channel) => Err(Status::CS_OK(channel)),
1451                 result => Err(result),
1452             }
1453         }
1454     }
1455 
1456     /// Return a [`OutputChannel`](struct.OutputChannel.html) which represent a csound's output channel ptr.
1457     /// creating the channel first if it does not exist yet.
1458     /// # Arguments
1459     /// * `name` The channel name.
1460     /// *
1461     /// The generic parameter `T` in this function can be one of the following types:
1462     ///  - ControlChannel
1463     ///     control data (one MYFLT value)
1464     ///  - AudioChannel
1465     ///     audio data (get_ksmps() f64 values)
1466     ///  - StrChannel:
1467     ///     string data (u8 values with enough space to store
1468     ///     get_channel_data_size() characters, including the
1469     ///     NULL character at the end of the string)
1470     /// If the channel already exists, it must match the data type
1471     /// (control, audio, or string)
1472     /// # Note
1473     ///  Audio and String channels
1474     /// can only be created after calling compile(), because the
1475     /// storage size is not known until then.
1476     /// # Returns
1477     /// A  Readable OutputChannel on success or a Status code,
1478     ///   "Not enough memory for allocating the channel" (CS_MEMORY)
1479     ///   "The specified name or type is invalid" (CS_ERROR)
1480     /// or, if a channel with the same name but incompatible type
1481     /// already exists, the type of the existing channel.
1482     /// * Note: to find out the type of a channel without actually
1483     /// creating or changing it, set 'channel_type' argument  to CSOUND_UNKNOWN_CHANNEL, so that the error
1484     /// value will be either the type of the channel, or CSOUND_ERROR
1485     /// if it does not exist.
1486     /// Operations on the channel pointer are not thread-safe by default. The host is
1487     /// required to take care of threadsafety by
1488     ///   1) with control channels use __sync_fetch_and_add() or
1489     ///      __sync_fetch_and_or() gcc atomic builtins to get or set a channel,
1490     ///      if available.
1491     ///   2) For string and audio channels (and controls if option 1 is not
1492     ///      available), retrieve the channel lock with ChannelLock()
1493     ///      and use SpinLock() and SpinUnLock() to protect access
1494     ///      to the channel.
1495     /// See Top/threadsafe.c in the Csound library sources for
1496     /// examples. Optionally, use the channel get/set functions
1497     /// which are threadsafe by default.
1498     /// # Example
1499     /// ```text
1500     /// extern crate csound;
1501     /// use csound::{Csound, OutputChannel, AudioChannel, StrChannel, ControlChannel};
1502     ///
1503     ///  // Creates a Csound instance
1504     /// let csound = Csound::new();
1505     /// csound.compile_csd(csd_filename).unwrap();
1506     /// csound.start();
1507     /// // Request a csound's output control channel
1508     /// let control_channel = csound.get_output_channel::<ControlChannel>("myChannel").unwrap();
1509     /// // Writes some data to the channel
1510     /// println!("channel value {}", control_channel.read());
1511     /// // Request a csound's output audio channel
1512     /// let audio_channel = csound.get_output_channel::<AudioChannle>("myAudioChannel").unwrap();
1513     /// println!("audio channel samples {:?}", audio_channel.read() );
1514     /// // Request a csound's output string channel
1515     /// let string_channel = csound.get_output_channel::<StrChannel>("myStringChannel").unwrap();
1516     ///
1517     /// ```
get_output_channel<T>(&self, name: &str) -> Result<OutputChannel<T>, Status> where T: IsChannel,1518     pub fn get_output_channel<T>(&self, name: &str) -> Result<OutputChannel<T>, Status>
1519     where
1520         T: IsChannel,
1521     {
1522         let mut ptr = ptr::null_mut() as *mut f64;
1523         let ptr = &mut ptr as *mut *mut _;
1524 
1525         let len;
1526         let bits;
1527 
1528         match T::c_type() {
1529             ControlChannelType::CSOUND_AUDIO_CHANNEL => {
1530                 len = self.get_ksmps() as usize;
1531                 bits =
1532                     (csound_sys::CSOUND_AUDIO_CHANNEL | csound_sys::CSOUND_OUTPUT_CHANNEL) as c_int;
1533             }
1534             ControlChannelType::CSOUND_CONTROL_CHANNEL => {
1535                 len = 1;
1536                 bits = (csound_sys::CSOUND_CONTROL_CHANNEL | csound_sys::CSOUND_OUTPUT_CHANNEL)
1537                     as c_int;
1538             }
1539             ControlChannelType::CSOUND_STRING_CHANNEL => {
1540                 len = self.get_channel_data_size(name) as usize;
1541                 bits = (csound_sys::CSOUND_STRING_CHANNEL | csound_sys::CSOUND_OUTPUT_CHANNEL)
1542                     as c_int;
1543             }
1544             _ => unimplemented!(),
1545         }
1546 
1547         unsafe {
1548             let result = Status::from(self.get_raw_channel_ptr(name, ptr, bits));
1549             match result {
1550                 Status::CS_SUCCESS => Ok(OutputChannel {
1551                     ptr: *ptr,
1552                     len,
1553                     phantom: PhantomData,
1554                 }),
1555                 Status::CS_OK(channel) => Err(Status::CS_OK(channel)),
1556                 result => Err(result),
1557             }
1558         }
1559     }
1560 
get_raw_channel_ptr( &self, name: &str, ptr: *mut *mut f64, channel_type: c_int, ) -> c_int1561     pub(crate) fn get_raw_channel_ptr(
1562         &self,
1563         name: &str,
1564         ptr: *mut *mut f64,
1565         channel_type: c_int,
1566     ) -> c_int {
1567         let cname = match CString::new(name) {
1568             Ok(c) => c,
1569             Err(_) => return -1,
1570         };
1571         unsafe {
1572             csound_sys::csoundGetChannelPtr(self.engine.csound, ptr, cname.as_ptr(), channel_type)
1573         }
1574     }
1575 
1576     /// Set parameters hints for a control channel.
1577     /// These hints have no internal function but can be used by front ends to construct GUIs or to constrain values.
1578     /// # Returns
1579     /// CS_SUCCESS on success, or CS_ERROR on failure: the channel does not exist, is not a control channel,
1580     /// or the specified parameters are invalid or CS_MEMORY: could not allocate memory for the
1581     /// channel. see: ([`Status`](enum.Status.html))
set_channel_hints(&self, name: &str, hint: &ChannelHints) -> Result<(), Status>1582     pub fn set_channel_hints(&self, name: &str, hint: &ChannelHints) -> Result<(), Status> {
1583         let attr = &hint.attributes[..];
1584         let attr = CString::new(attr).map_err(|_| Status::CS_ERROR)?;
1585         let cname = CString::new(name).map_err(|_| Status::CS_ERROR)?;
1586         let channel_hint = csound_sys::controlChannelHints_t {
1587             behav: ChannelBehavior::to_u32(&hint.behav),
1588             dflt: hint.dflt,
1589             min: hint.min,
1590             max: hint.max,
1591             x: hint.x,
1592             y: hint.y,
1593             width: hint.width as c_int,
1594             height: hint.height as c_int,
1595             attributes: attr.as_ptr() as *mut c_char,
1596         };
1597         unsafe {
1598             match Status::from(csound_sys::csoundSetControlChannelHints(
1599                 self.engine.csound,
1600                 cname.as_ptr(),
1601                 channel_hint,
1602             ) as i32)
1603             {
1604                 Status::CS_SUCCESS => Ok(()),
1605                 status => Err(status),
1606             }
1607         }
1608     }
1609 
1610     /// Returns special parameters (or None if there are not any) of a control channel.
1611     /// Previously set with csoundSetControlChannelHints() or the
1612     /// [chnparams](http://www.csounds.com/manualOLPC/chnparams.html) opcode.
get_channel_hints(&self, name: &str) -> Result<ChannelHints, Status>1613     pub fn get_channel_hints(&self, name: &str) -> Result<ChannelHints, Status> {
1614         let cname = CString::new(name).map_err(|_| Status::CS_ERROR)?;
1615         let mut hint = csound_sys::controlChannelHints_t::default();
1616         unsafe {
1617             match csound_sys::csoundGetControlChannelHints(
1618                 self.engine.csound,
1619                 cname.as_ptr() as *mut c_char,
1620                 &mut hint as *mut _,
1621             ) {
1622                 csound_sys::CSOUND_SUCCESS => {
1623                     let attributes = match Trampoline::ptr_to_string(hint.attributes) {
1624                         Some(name) => name,
1625                         None => "".into(),
1626                     };
1627 
1628                     let hints = ChannelHints {
1629                         behav: ChannelBehavior::from_u32(hint.behav as u32),
1630                         dflt: hint.dflt,
1631                         min: hint.min,
1632                         max: hint.max,
1633                         x: hint.x as i32,
1634                         y: hint.y as i32,
1635                         width: hint.width as i32,
1636                         height: hint.height as i32,
1637                         attributes,
1638                     };
1639                     Ok(hints)
1640                 }
1641 
1642                 status => Err(Status::from(status)),
1643             }
1644         }
1645     }
1646 
1647     /// Retrieves the value of a control channel.
1648     /// # Arguments
1649     /// * `name`  The channel name.
1650     /// An error message will be returned if the channel is not a control channel,
1651     /// the channel not exist or if the name is invalid.
get_control_channel(&self, name: &str) -> Result<f64, &'static str>1652     pub fn get_control_channel(&self, name: &str) -> Result<f64, &'static str> {
1653         let cname = CString::new(name).map_err(|_| "invalid channel name")?;
1654         let mut err: c_int = 0;
1655         unsafe {
1656             let ret = csound_sys::csoundGetControlChannel(
1657                 self.engine.csound,
1658                 cname.as_ptr(),
1659                 &mut err as *mut _,
1660             ) as f64;
1661             if (err) == csound_sys::CSOUND_SUCCESS {
1662                 Ok(ret)
1663             } else {
1664                 Err("channel not exist or is not a control channel")
1665             }
1666         }
1667     }
1668 
1669     /// Sets the value of a control channel.
1670     /// # Arguments
1671     /// * `name`  The channel name.
set_control_channel(&mut self, name: &str, value: f64)1672     pub fn set_control_channel(&mut self, name: &str, value: f64) {
1673         let cname = CString::new(name).unwrap();
1674         unsafe {
1675             csound_sys::csoundSetControlChannel(self.engine.csound, cname.as_ptr(), value);
1676         }
1677     }
1678 
1679     /// Copies samples from an audio channel.
1680     /// # Arguments
1681     /// * `name` The channel name.
1682     /// * `out` The slice where the date contained in the internal audio channel buffer
1683     /// will be copied. Should contain enough memory for ksmps f64 samples.
1684     /// # Panic
1685     /// If the buffer passed to this function doesn't have enough memory.
read_audio_channel(&self, name: &str, output: &mut [f64])1686     pub fn read_audio_channel(&self, name: &str, output: &mut [f64]) {
1687         let ksmps = self.get_ksmps() as usize;
1688         let size = output.len();
1689         let cname = CString::new(name).unwrap();
1690         assert!(
1691             ksmps <= size,
1692             "The audio channel's capacity is {} so, it isn't possible to copy {} samples",
1693             ksmps,
1694             size
1695         );
1696         unsafe {
1697             csound_sys::csoundGetAudioChannel(
1698                 self.engine.csound,
1699                 cname.as_ptr(),
1700                 output.as_ptr() as *mut c_double,
1701             );
1702         }
1703     }
1704 
1705     /// Writes data into an audio channel buffer. audio channel identified by *name* with data from slice *input* which should
1706     /// contain at least ksmps f64 samples, if not, this method will panic.
1707     /// # Arguments
1708     /// * `input` The slice with data to be copied into the audio channel buffer. Could contain up to ksmps samples.
1709     /// # panic
1710     /// This method will panic if input.len() > ksmps.
write_audio_channel(&mut self, name: &str, input: &[f64])1711     pub fn write_audio_channel(&mut self, name: &str, input: &[f64]) {
1712         let size = self.get_ksmps() as usize * self.input_channels() as usize;
1713         let len = input.len();
1714         let cname = CString::new(name).unwrap();
1715         assert!(
1716             size <= len,
1717             "The audio channel's capacity is {} so, it isn't possible to copy {} bytes",
1718             size,
1719             len
1720         );
1721         unsafe {
1722             csound_sys::csoundSetAudioChannel(
1723                 self.engine.csound,
1724                 cname.as_ptr(),
1725                 input.as_ptr() as *mut c_double,
1726             );
1727         }
1728     }
1729 
1730     /// Returns the content of the string channel identified by *name*
get_string_channel(&self, name: &str) -> String1731     pub fn get_string_channel(&self, name: &str) -> String {
1732         let cname = CString::new(name).unwrap();
1733         let mut data = String::with_capacity(self.get_channel_data_size(name));
1734         unsafe {
1735             let ptr = data.as_mut_vec();
1736             csound_sys::csoundGetStringChannel(
1737                 self.engine.csound,
1738                 cname.as_ptr(),
1739                 ptr.as_ptr() as *mut _,
1740             );
1741         }
1742         data
1743     }
1744 
1745     /// Sets the string channel identified by *name* with *content*
set_string_channel(&mut self, name: &str, content: &str)1746     pub fn set_string_channel(&mut self, name: &str, content: &str) {
1747         let cname = CString::new(name).unwrap();
1748         let content = CString::new(content).unwrap();
1749         unsafe {
1750             csound_sys::csoundSetStringChannel(
1751                 self.engine.csound,
1752                 cname.as_ptr(),
1753                 content.as_ptr() as *mut _,
1754             );
1755         }
1756     }
1757 
1758     /// returns the size of data stored in the channel identified by *name*
get_channel_data_size(&self, name: &str) -> usize1759     pub fn get_channel_data_size(&self, name: &str) -> usize {
1760         let cname = CString::new(name).unwrap();
1761         unsafe { csound_sys::csoundGetChannelDatasize(self.engine.csound, cname.as_ptr()) as usize }
1762     }
1763 
1764     /// Receives a PVSDAT fout from the [*pvsout*](http://www.csounds.com/manual/html/pvsout.html) opcode.
1765     /// This method will return Ok on success,
1766     /// [`Status::CS_ERROR`](enum.Status.html#member.CS_ERROR) if the channel name is not valid or the channel doesn't
1767     /// exist or [`Status::CS_MEMORY`](enum.Status.html#member.CS_MEMORY) if the frame buffer lengths haven't the same size
1768     /// as the requested table
1769     /// # Arguments
1770     /// * `name` The channel identifier.
1771     /// * `pvs_data` Reference to tha struct which will be filled with the pvs data.
1772     /// # Example
1773     /// ```
1774     /// let mut pvs = PvsDataExt::new(512);
1775     /// cs.get_pvs_channel("1", &mut pvs);
1776     /// ```
get_pvs_channel(&self, name: &str, pvs_data: &mut PvsDataExt) -> Result<(), Status>1777     pub fn get_pvs_channel(&self, name: &str, pvs_data: &mut PvsDataExt) -> Result<(), Status> {
1778         let cname = CString::new(name).map_err(|_| Status::CS_ERROR)?;
1779         let mut ptr = ptr::null_mut() as *mut f64;
1780         unsafe {
1781             if csound_sys::csoundGetChannelPtr(
1782                 self.engine.csound,
1783                 &mut ptr as *mut *mut _,
1784                 cname.as_ptr(),
1785                 (csound_sys::CSOUND_PVS_CHANNEL | csound_sys::CSOUND_INPUT_CHANNEL) as c_int,
1786             ) == csound_sys::CSOUND_SUCCESS
1787             {
1788                 // Same data buffer size?
1789                 if (*(ptr as *mut csound_sys::PVSDATEXT)).N == pvs_data.N as c_int {
1790                     let data = &mut csound_sys::PVSDATEXT::default();
1791                     data.frame = pvs_data.frame.as_mut_slice().as_ptr() as *mut f32;
1792                     let result = csound_sys::csoundGetPvsChannel(
1793                         self.engine.csound,
1794                         &mut *data,
1795                         cname.as_ptr(),
1796                     );
1797                     match result {
1798                         csound_sys::CSOUND_SUCCESS => {
1799                             pvs_data.N = data.N as u32;
1800                             pvs_data.sliding = data.sliding as u32;
1801                             pvs_data.NB = data.NB as i32;
1802                             pvs_data.overlap = data.overlap as u32;
1803                             pvs_data.winsize = data.winsize as u32;
1804                             pvs_data.wintype = data.wintype as u32;
1805                             pvs_data.format = data.format as u32;
1806                             pvs_data.framecount = data.framecount as u32;
1807                             Ok(())
1808                         }
1809                         err => Err(Status::from(err)),
1810                     }
1811                 } else {
1812                     Err(Status::CS_MEMORY)
1813                 }
1814             } else {
1815                 Err(Status::CS_ERROR)
1816             }
1817         }
1818     }
1819 
set_pvs_channel(&mut self, name: &str, pvs_data: &PvsDataExt)1820     pub fn set_pvs_channel(&mut self, name: &str, pvs_data: &PvsDataExt) {
1821         unsafe {
1822             let cname = CString::new(name);
1823             if let Ok(cname) = cname {
1824                 let cname = cname;
1825                 let data = &mut csound_sys::PVSDATEXT {
1826                     N: pvs_data.N as _,
1827                     sliding: pvs_data.sliding as _,
1828                     NB: pvs_data.NB as _,
1829                     overlap: pvs_data.overlap as _,
1830                     winsize: pvs_data.winsize as _,
1831                     wintype: pvs_data.wintype as _,
1832                     format: pvs_data.format as _,
1833                     framecount: pvs_data.framecount as _,
1834                     frame: pvs_data.frame.as_slice().as_ptr() as *mut f32,
1835                 };
1836                 csound_sys::csoundSetPvsChannel(self.engine.csound, &*data, cname.as_ptr());
1837             }
1838         }
1839     }
1840 
1841     /// Send a new score event.
1842     /// # Arguments
1843     /// * `event_type` is the score event type ('a', 'i', 'q', 'f', or 'e').
1844     /// * `pfields` is a slice of f64 values with all the pfields for this event.
1845     /// # Example
1846     /// ```
1847     /// let cs = Csound::new();
1848     /// let pFields = [1.0, 1.0, 5.0];
1849     /// while cs.perform_ksmps() == false {
1850     ///     cs.send_score_event('i', &pFields);
1851     /// }
1852     /// ```
send_score_event(&self, event_type: char, pfields: &[f64]) -> Status1853     pub fn send_score_event(&self, event_type: char, pfields: &[f64]) -> Status {
1854         unsafe {
1855             Status::from(csound_sys::csoundScoreEvent(
1856                 self.engine.csound,
1857                 event_type as c_char,
1858                 pfields.as_ptr() as *const c_double,
1859                 pfields.len() as c_long,
1860             ) as i32)
1861         }
1862     }
1863 
1864     /// Like [`Csound::send_score_event`](struct.Csound.html#method.send_score_event).
1865     /// This function inserts a score event,
1866     /// but at absolute time with respect to the start of performance,
1867     /// or from an offset set with *time_offset*
send_score_event_absolute( &self, event_type: char, pfields: &[f64], time_offset: f64, ) -> Status1868     pub fn send_score_event_absolute(
1869         &self,
1870         event_type: char,
1871         pfields: &[f64],
1872         time_offset: f64,
1873     ) -> Status {
1874         unsafe {
1875             Status::from(csound_sys::csoundScoreEventAbsolute(
1876                 self.engine.csound,
1877                 event_type as c_char,
1878                 pfields.as_ptr() as *const c_double,
1879                 pfields.len() as c_long,
1880                 time_offset as c_double,
1881             ) as i32)
1882         }
1883     }
1884 
1885     /// Asynchronous version of [`Csound::send_score_event`](struct.Csound.html#method.send_score_event)
send_score_event_async(&self, event_type: char, pfields: &[f64]) -> Status1886     pub fn send_score_event_async(&self, event_type: char, pfields: &[f64]) -> Status {
1887         unsafe {
1888             Status::from(csound_sys::csoundScoreEventAsync(
1889                 self.engine.csound,
1890                 event_type as c_char,
1891                 pfields.as_ptr() as *const c_double,
1892                 pfields.len() as c_long,
1893             ) as i32)
1894         }
1895     }
1896 
1897     /// Asynchronous version of [`Csound::send_score_event_absolute`](struct.Csound.html#method.send_score_event_absolute)
send_score_event_absolute_async( &self, event_type: char, pfields: &[f64], time_offset: f64, ) -> Status1898     pub fn send_score_event_absolute_async(
1899         &self,
1900         event_type: char,
1901         pfields: &[f64],
1902         time_offset: f64,
1903     ) -> Status {
1904         unsafe {
1905             Status::from(csound_sys::csoundScoreEventAbsoluteAsync(
1906                 self.engine.csound,
1907                 event_type as c_char,
1908                 pfields.as_ptr() as *const c_double,
1909                 pfields.len() as c_long,
1910                 time_offset as c_double,
1911             ) as i32)
1912         }
1913     }
1914 
1915     /// Input a string (as if from a console), used for line events.
1916     /// # Example
1917     /// ```
1918     /// let cs = Csound::new();
1919     /// let pFields = [1.0, 1.0, 5.0];
1920     /// while cs.perform_ksmps() == false {
1921     ///     cs.send_input_message("i 2 0 0.75  1");
1922     /// }
1923     /// ```
send_input_message(&self, message: &str) -> Result<(), NulError>1924     pub fn send_input_message(&self, message: &str) -> Result<(), NulError> {
1925         let cmessage = CString::new(message)?;
1926         unsafe {
1927             csound_sys::csoundInputMessage(self.engine.csound, cmessage.as_ptr() as *const c_char);
1928             Ok(())
1929         }
1930     }
1931 
1932     /// Asynchronous version of [`Csound::send_input_message`](struct.Csound.html#method.send_input_message)
send_input_message_async(&self, message: &str) -> Result<(), NulError>1933     pub fn send_input_message_async(&self, message: &str) -> Result<(), NulError> {
1934         let cmessage = CString::new(message)?;
1935         unsafe {
1936             csound_sys::csoundInputMessageAsync(
1937                 self.engine.csound,
1938                 cmessage.as_ptr() as *const c_char,
1939             );
1940             Ok(())
1941         }
1942     }
1943 
1944     /// Kills off one or more running instances of an instrument.
1945     /// # Arguments
1946     /// * `instr` The numeric identifier of the instrument.
1947     /// * `name` The string identifier of the instrument or name. If it is None, the instrument
1948     /// numeric identifier is used.
1949     /// * `mode` is a sum of the following values: 0,1,2: kill all instances (1), oldest only (1), or newest (2)
1950     /// 4: only turnoff notes with exactly matching (fractional) instr number
1951     /// 8: only turnoff notes with indefinite duration (p3 < 0 or MIDI).
1952     /// * `allow_release` if true, the killed instances are allowed to release.
kill_instrument( &self, instr: f64, name: Option<&str>, mode: u32, allow_release: bool, ) -> Status1953     pub fn kill_instrument(
1954         &self,
1955         instr: f64,
1956         name: Option<&str>,
1957         mode: u32,
1958         allow_release: bool,
1959     ) -> Status {
1960         let cname = CString::new(name.unwrap_or_else(|| "")).unwrap();
1961         unsafe {
1962             Status::from(csound_sys::csoundKillInstance(
1963                 self.engine.csound,
1964                 instr as c_double,
1965                 cname.as_ptr() as *const c_char,
1966                 mode as c_int,
1967                 allow_release as c_int,
1968             ) as i32)
1969         }
1970     }
1971 
1972     /// Set the ASCII code of the most recent key pressed.
1973     /// # Arguments
1974     /// * `key` The ASCII identifier for the key pressed.
key_press(&self, key: char)1975     pub fn key_press(&self, key: char) {
1976         unsafe {
1977             csound_sys::csoundKeyPress(self.engine.csound, key as c_char);
1978         }
1979     }
1980 
1981     /* Engine general Table function  implementations **************************************************************************************** */
1982 
1983     /// Returns the length of a function table (not including the guard point), or an error
1984     /// message if the table doens't exist.
1985     /// # Arguments
1986     /// * `table` The function table identifier.
table_length(&self, table: u32) -> Result<usize, &'static str>1987     pub fn table_length(&self, table: u32) -> Result<usize, &'static str> {
1988         unsafe {
1989             let value = csound_sys::csoundTableLength(self.engine.csound, table as c_int) as i32;
1990             if value > 0 {
1991                 Ok(value as usize)
1992             } else {
1993                 Err("Table doesn't exist")
1994             }
1995         }
1996     }
1997 
1998     /// Returns the value of a slot in a function table.
1999     /// If the Table or index are not valid, an error message will be returned.
2000     /// # Arguments
2001     /// * `table` The function table identifier.
2002     /// * `index` The value at table[index] which will be read.
table_get(&self, table: u32, index: u32) -> Result<f64, &'static str>2003     pub fn table_get(&self, table: u32, index: u32) -> Result<f64, &'static str> {
2004         unsafe {
2005             let size = self.table_length(table)?;
2006             if index < size as u32 {
2007                 Ok(
2008                     csound_sys::csoundTableGet(self.engine.csound, table as c_int, index as c_int)
2009                         as f64,
2010                 )
2011             } else {
2012                 Err("index out of range")
2013             }
2014         }
2015     }
2016 
2017     /// Sets the value of a slot in a function table.
2018     /// # Arguments
2019     /// * `table` The function table identifier.
2020     /// * `index` The slot at table[index] where value will be added.
2021     /// # Returns
2022     /// An error message if the index or table are no valid
table_set(&mut self, table: u32, index: u32, value: f64) -> Result<(), &'static str>2023     pub fn table_set(&mut self, table: u32, index: u32, value: f64) -> Result<(), &'static str> {
2024         unsafe {
2025             let size = self.table_length(table)?;
2026             if index < size as u32 {
2027                 csound_sys::csoundTableSet(
2028                     self.engine.csound,
2029                     table as c_int,
2030                     index as c_int,
2031                     value,
2032                 );
2033                 Ok(())
2034             } else {
2035                 Err("index out of range")
2036             }
2037         }
2038     }
2039 
2040     /// Copies the content of a function table into a slice.
2041     /// # Arguments
2042     /// * `table` The function table identifier.
2043     /// # Returns
2044     /// An error message if the table doesn't exist or the passed slice
2045     /// doesn't have enough memory to content the table values.
table_copy_out(&self, table: u32, output: &mut [f64]) -> Result<(), &'static str>2046     pub fn table_copy_out(&self, table: u32, output: &mut [f64]) -> Result<(), &'static str> {
2047         unsafe {
2048             let size = self.table_length(table)?;
2049             if output.len() < size {
2050                 Err("Not enough memory to copy the table")
2051             } else {
2052                 csound_sys::csoundTableCopyOut(
2053                     self.engine.csound,
2054                     table as c_int,
2055                     output.as_ptr() as *mut c_double,
2056                 );
2057                 Ok(())
2058             }
2059         }
2060     }
2061 
2062     /// Asynchronous version of [`Csound:: table_copy_out`](struct.Csound.html#method.table_copy_out)
table_copy_out_async(&self, table: u32, output: &mut [f64]) -> Result<(), &'static str>2063     pub fn table_copy_out_async(&self, table: u32, output: &mut [f64]) -> Result<(), &'static str> {
2064         unsafe {
2065             let size = self.table_length(table)?;
2066             if output.len() < size {
2067                 Err("Not enough memory to copy the table")
2068             } else {
2069                 csound_sys::csoundTableCopyOutAsync(
2070                     self.engine.csound,
2071                     table as c_int,
2072                     output.as_ptr() as *mut c_double,
2073                 );
2074                 Ok(())
2075             }
2076         }
2077     }
2078 
2079     /// Copy the contents of an array into a given function table.
2080     /// # Arguments
2081     /// * `table` The function table identifier.
2082     /// * `src` Slice with the values to be copied into the function table
2083     /// # Returns
2084     /// An error message if the table doesn't exist or doesn't have enough
2085     /// capacity.
table_copy_in(&mut self, table: u32, src: &[f64]) -> Result<(), &'static str>2086     pub fn table_copy_in(&mut self, table: u32, src: &[f64]) -> Result<(), &'static str> {
2087         let size = self.table_length(table)?;
2088         if size < src.len() {
2089             Err("Table doesn't have enough capacity")
2090         } else {
2091             unsafe {
2092                 csound_sys::csoundTableCopyIn(
2093                     self.engine.csound,
2094                     table as c_int,
2095                     src.as_ptr() as *const c_double,
2096                 );
2097                 Ok(())
2098             }
2099         }
2100     }
2101 
2102     /// Asynchronous version of [`Csound:: table_copy_in`](struct.Csound.html#method.table_copy_in)
table_copy_in_async(&mut self, table: u32, src: &[f64]) -> Result<(), &'static str>2103     pub fn table_copy_in_async(&mut self, table: u32, src: &[f64]) -> Result<(), &'static str> {
2104         let size = self.table_length(table)?;
2105         if size < src.len() {
2106             Err("Table doesn't have enough capacity")
2107         } else {
2108             unsafe {
2109                 csound_sys::csoundTableCopyInAsync(
2110                     self.engine.csound,
2111                     table as c_int,
2112                     src.as_ptr() as *const c_double,
2113                 );
2114                 Ok(())
2115             }
2116         }
2117     }
2118 
2119     /// Returns a [`Csound::Table`](struct.Table.html).
2120     /// which could be used to read/write the table content
2121     /// directly( not using [`Csound:: table_copy_in`](struct.Csound.html#method.table_copy_in) or [`Csound::table_copy_out`](struct.Csound.html#method.table_copy_out)).
2122     /// this table will be valid along the csound instance. Returns None if the table doesn't
2123     /// exist.
2124     /// # Arguments
2125     /// * `table` The function table identifier.
2126     /// # Example
2127     /// ```
2128     /// let cs = Csound::new();
2129     /// cs.compile_csd("some.csd");
2130     /// cs.start().unwrap();
2131     /// while cs.perform_ksmps() == false {
2132     ///     let mut table_buff = vec![0f64; cs.table_length(1).unwrap() as usize];
2133     ///     // Gets the function table 1
2134     ///     let mut table = cs.get_table(1).unwrap();
2135     ///     // Copies the table content into table_buff
2136     ///     table.read( table_buff.as_mut_slice() ).unwrap();
2137     ///     // Do some stuffs
2138     ///     table.write(&table_buff.into_iter().map(|x| x*2.5).collect::<Vec<f64>>().as_mut_slice());
2139     ///     // Do some stuffs
2140     /// }
2141     /// ```
2142     /// see [`Table::read`](struct.Table.html#method.read) or [`Table::write`](struct.Table.html#method.write).
get_table(&self, table: u32) -> Option<Table>2143     pub fn get_table(&self, table: u32) -> Option<Table> {
2144         let mut ptr = ptr::null_mut() as *mut c_double;
2145         let length;
2146         unsafe {
2147             length = csound_sys::csoundGetTable(
2148                 self.engine.csound,
2149                 &mut ptr as *mut *mut c_double,
2150                 table as c_int,
2151             ) as i32;
2152         }
2153         match length {
2154             -1 => None,
2155             _ => Some(Table {
2156                 ptr,
2157                 length: length as usize,
2158                 phantom: PhantomData,
2159             }),
2160         }
2161     }
2162 
2163     /// Gets the arguments used to construct or define a function table
2164     /// # Arguments
2165     /// * `table` The function table identifier.
2166     /// # Returns
2167     /// A vector containing the table's arguments.
2168     /// * Note:* the argument list starts with the GEN number and is followed by its parameters.
2169     /// eg. f 1 0 1024 10 1 0.5 yields the list {10.0,1.0,0.5}.
get_table_args(&self, table: u32) -> Option<Vec<f64>>2170     pub fn get_table_args(&self, table: u32) -> Option<Vec<f64>> {
2171         let mut ptr = ptr::null_mut() as *mut c_double;
2172         unsafe {
2173             let length = csound_sys::csoundGetTableArgs(
2174                 self.engine.csound,
2175                 &mut ptr as *mut *mut c_double,
2176                 table as c_int,
2177             );
2178             if length < 0 {
2179                 None
2180             } else {
2181                 let mut result = Vec::with_capacity(length as usize);
2182                 for pos in 0..length as isize {
2183                     result.push(*ptr.offset(pos));
2184                 }
2185                 Some(result)
2186             }
2187         }
2188     }
2189 
2190     /// Gets the arguments used to construct or define a function table
2191     /// Similar to [`Csound::get_table_args`](struct.Csound.html#method.get_table_args)
2192     /// but no memory will be allocated, instead a slice is returned.
get_table_args_slice(&self, table: u32) -> Option<&[f64]>2193     pub fn get_table_args_slice(&self, table: u32) -> Option<&[f64]> {
2194         let mut ptr = ptr::null_mut() as *mut c_double;
2195         unsafe {
2196             let length = csound_sys::csoundGetTableArgs(
2197                 self.engine.csound,
2198                 &mut ptr as *mut *mut c_double,
2199                 table as c_int,
2200             );
2201             if length < 0 {
2202                 None
2203             } else {
2204                 Some(slice::from_raw_parts(ptr as *const _, length as usize))
2205             }
2206         }
2207     }
2208 
2209     /// Checks if a given *gen* number is a named GEN
2210     /// # Arguments
2211     /// * `gen` The GEN number identifier.
2212     /// # Returns
2213     /// The GEN names's length
is_named_gen(&self, gen: u32) -> usize2214     pub fn is_named_gen(&self, gen: u32) -> usize {
2215         unsafe { csound_sys::csoundIsNamedGEN(self.engine.csound, gen as c_int) as usize }
2216     }
2217 
2218     /// Returns the GEN name if it exist ans is named, else, returns None
2219     /// # Arguments
2220     /// * `gen` The GEN number identifier.
2221     /// # Returns
2222     /// A option with the GEN name or None if the GEN is not a named one
2223     /// or not exist.
get_gen_name(&self, gen: u32) -> Option<String>2224     pub fn get_gen_name(&self, gen: u32) -> Option<String> {
2225         unsafe {
2226             let len = self.is_named_gen(gen);
2227             if len > 0 {
2228                 let name = vec![0u8; len];
2229                 let name_raw = CString::from_vec_unchecked(name).into_raw();
2230                 csound_sys::csoundGetNamedGEN(
2231                     self.engine.csound,
2232                     gen as c_int,
2233                     name_raw,
2234                     len as c_int,
2235                 );
2236                 let name = CString::from_raw(name_raw);
2237                 match name.to_str() {
2238                     Ok(str) => Some(str.to_owned()),
2239                     Err(_) => None,
2240                 }
2241             } else {
2242                 None
2243             }
2244         }
2245     }
2246 
2247     /* Engine general Opcode function  implementations **************************************************************************************** */
2248 
2249     /// Gets an alphabetically sorted list of all opcodes.
2250     /// Should be called after externals are loaded by csoundCompile().
2251     /// The opcode information is contained in a [`Csound::OpcodeListEntry`](struct.Csound.html#struct.OpcodeListEntry)
get_opcode_list_entry(&self) -> Option<Vec<OpcodeListEntry>>2252     pub fn get_opcode_list_entry(&self) -> Option<Vec<OpcodeListEntry>> {
2253         let mut ptr = ptr::null_mut() as *mut csound_sys::opcodeListEntry;
2254         let length;
2255         unsafe {
2256             length = csound_sys::csoundNewOpcodeList(
2257                 self.engine.csound,
2258                 &mut ptr as *mut *mut csound_sys::opcodeListEntry,
2259             );
2260         }
2261         if length < 0 {
2262             None
2263         } else {
2264             let mut result: Vec<OpcodeListEntry> = Vec::with_capacity(length as usize);
2265             for pos in 0..length as isize {
2266                 unsafe {
2267                     let opname = Trampoline::ptr_to_string((*ptr.offset(pos)).opname);
2268                     let outypes = Trampoline::ptr_to_string((*ptr.offset(pos)).outypes);
2269                     let intypes = Trampoline::ptr_to_string((*ptr.offset(pos)).intypes);
2270                     let flags = (*ptr.offset(pos)).flags as i32;
2271                     result.push(OpcodeListEntry {
2272                         opname,
2273                         outypes,
2274                         intypes,
2275                         flags,
2276                     });
2277                 }
2278             }
2279             unsafe {
2280                 csound_sys::csoundDisposeOpcodeList(self.engine.csound, ptr);
2281                 Some(result)
2282             }
2283         }
2284     }
2285 
2286     /**
2287     TODO genName and appendOpcode functions
2288     *****/
2289 
2290     /* Engine miscellaneous functions **************************************************************************************** */
2291 
2292     /// # Argument
2293     /// * `lang_code` can be for example any of [`Language`](enum.Language.html) variants.
2294     /// This affects all Csound instances running in the address
2295     /// space of the current process. The special language code
2296     /// *Language::CSLANGUAGE_DEFAULT* can be used to disable translation of messages and
2297     /// free all memory allocated by a previous call to this function.
2298     /// set_language() loads all files for the selected language from the directory specified by the **CSSTRNGS** environment
2299     /// variable.
set_language(lang_code: Language)2300     pub fn set_language(lang_code: Language) {
2301         unsafe {
2302             csound_sys::csoundSetLanguage(lang_code as u32);
2303         }
2304     }
2305 
2306     /// Generates a random seed from time
2307     /// # Returns
2308     /// A 32-bit unsigned integer to be used as random seed.
get_random_seed_from_time() -> u322309     pub fn get_random_seed_from_time() -> u32 {
2310         unsafe { csound_sys::csoundGetRandomSeedFromTime() as u32 }
2311     }
2312 
2313     /// Simple linear congruential random number generator: seed = seed * 742938285 % 2147483647
2314     /// # Returns
2315     /// The next number from the pseudo-random sequence, in the range 1 to 2147483646.
2316     /// if the value of seed is not in the range 1 to 2147483646 an error message will
2317     /// be returned.
get_rand31(seed: &mut u32) -> Result<u32, &'static str>2318     pub fn get_rand31(seed: &mut u32) -> Result<u32, &'static str> {
2319         unsafe {
2320             match seed {
2321                 1..=2_147_483_646 => {
2322                     let ptr: *mut u32 = &mut *seed;
2323                     let res = csound_sys::csoundRand31(ptr as *mut c_int) as u32;
2324                     Ok(res)
2325                 }
2326                 _ => Err("invalid seed value"),
2327             }
2328         }
2329     }
2330 
2331     /// Returns an initialised timer structure.
init_timer() -> RTCLOCK2332     pub fn init_timer() -> RTCLOCK {
2333         let mut timer = RTCLOCK::default();
2334         unsafe {
2335             let ptr: *mut RTCLOCK = &mut timer as *mut RTCLOCK;
2336             csound_sys::csoundInitTimerStruct(ptr);
2337         }
2338         timer
2339     }
2340 
2341     /// Calculates a time offset
2342     /// # Arguments
2343     /// * `timer` time struct since the elapsed time will be calculated.
2344     /// # Returns
2345     /// The elapsed real time (in seconds) since the specified timer
get_real_time(timer: &RTCLOCK) -> f642346     pub fn get_real_time(timer: &RTCLOCK) -> f64 {
2347         unsafe {
2348             let ptr: *mut csound_sys::RTCLOCK = &mut csound_sys::RTCLOCK {
2349                 starttime_real: timer.starttime_real as c_long,
2350                 starttime_CPU: timer.starttime_CPU as c_long,
2351             };
2352             csound_sys::csoundGetRealTime(ptr) as f64
2353         }
2354     }
2355 
2356     /// Return the elapsed CPU time (in seconds) since the specified *timer* structure was initialised.
2357     /// # Arguments
2358     /// * `gen` The GEN number identifier.
get_cpu_time(timer: &mut RTCLOCK) -> f642359     pub fn get_cpu_time(timer: &mut RTCLOCK) -> f64 {
2360         unsafe { csound_sys::csoundGetCPUTime(timer as *mut RTCLOCK) as f64 }
2361     }
2362 
2363     /// Creates a circular buffer.
2364     /// # Arguments
2365     /// * `len` The buffer length.
2366     /// # Returns
2367     /// A CircularBuffer
2368     /// # Example
2369     /// ```
2370     /// let csound = Csound::new();
2371     /// let circular_buffer = csound.create_circular_buffer::<f64>(1024);
2372     /// ```
create_circular_buffer<'a, T: 'a + Copy>(&'a self, len: u32) -> CircularBuffer<T>2373     pub fn create_circular_buffer<'a, T: 'a + Copy>(&'a self, len: u32) -> CircularBuffer<T> {
2374         unsafe {
2375             let ptr: *mut T = csound_sys::csoundCreateCircularBuffer(
2376                 self.engine.csound,
2377                 len as c_int,
2378                 mem::size_of::<T>() as c_int,
2379             ) as *mut T;
2380             CircularBuffer {
2381                 csound: self.engine.csound,
2382                 ptr,
2383                 phantom: PhantomData,
2384             }
2385         }
2386     }
2387 
2388     // Threading function
2389 
sleep(&self, milli_seconds: usize)2390     pub fn sleep(&self, milli_seconds: usize) {
2391         unsafe {
2392             csound_sys::csoundSleep(milli_seconds);
2393         }
2394     }
2395 
2396     // TODO global variables functions
2397 
2398     /********************************** Callback settings using the custom callback Handler implementation******/
2399 
2400     /// Sets a function that is called to obtain a list of audio devices.
2401     /// This should be set by rtaudio modules and should not be set by hosts.
audio_device_list_callback<'c, F>(&self, f: F) where F: FnMut(CsAudioDevice) + 'c,2402     pub fn audio_device_list_callback<'c, F>(&self, f: F)
2403     where
2404         F: FnMut(CsAudioDevice) + 'c,
2405     {
2406         unsafe {
2407             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2408                 .callbacks
2409                 .set_devlist_cb(self.engine.csound, f);
2410         }
2411     }
2412 
2413     /// Sets a function to be called by Csound for opening real-time audio playback.
2414     /// This callback is used to inform the user about the current audio device Which
2415     /// Csound will use to play the audio samples.
2416     /// # Arguments
2417     /// * `user_func` A function/closure which will receive a reference
2418     ///  to a RtAudioParams struct.
play_open_audio_callback<'c, F>(&self, f: F) where F: FnMut(&RtAudioParams) -> Status + 'c,2419     pub fn play_open_audio_callback<'c, F>(&self, f: F)
2420     where
2421         F: FnMut(&RtAudioParams) -> Status + 'c,
2422     {
2423         unsafe {
2424             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2425                 .callbacks
2426                 .set_play_open_cb(self.engine.csound, f);
2427         }
2428     }
2429 
2430     /// Sets a function to be called by Csound for opening real-time audio recording.
2431     /// This callback is used to inform the user about the current audio device Which
2432     /// Csound will use for opening realtime audio recording. You have to return Status::CS_SUCCESS
rec_open_audio_callback<'c, F>(&self, f: F) where F: FnMut(&RtAudioParams) -> Status + 'c,2433     pub fn rec_open_audio_callback<'c, F>(&self, f: F)
2434     where
2435         F: FnMut(&RtAudioParams) -> Status + 'c,
2436     {
2437         unsafe {
2438             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2439                 .callbacks
2440                 .set_rec_open_cb(self.engine.csound, f);
2441         }
2442     }
2443 
2444     /// Sets a function to be called by Csound for performing real-time audio playback.
2445     /// A reference to a buffer with audio samples is passed
2446     /// to the user function in the callback. These samples have to be processed and sent
2447     /// to a proper audio device.
rt_audio_play_callback<'c, F>(&self, f: F) where F: FnMut(&[f64]) + 'c,2448     pub fn rt_audio_play_callback<'c, F>(&self, f: F)
2449     where
2450         F: FnMut(&[f64]) + 'c,
2451     {
2452         unsafe {
2453             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2454                 .callbacks
2455                 .set_rt_play_cb(self.engine.csound, f);
2456         }
2457     }
2458 
2459     /// Sets a function to be called by Csound for performing real-time audio recording.
2460     /// With this callback the user can fill a buffer with samples from a custom
2461     /// audio module, and pass it into csound.
rt_audio_rec_callback<'c, F>(&self, f: F) where F: FnMut(&mut [f64]) -> usize + 'c,2462     pub fn rt_audio_rec_callback<'c, F>(&self, f: F)
2463     where
2464         F: FnMut(&mut [f64]) -> usize + 'c,
2465     {
2466         unsafe {
2467             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2468                 .callbacks
2469                 .set_rt_rec_cb(self.engine.csound, f);
2470         }
2471     }
2472 
2473     /// Indicates to the user when csound has closed the rtaudio device.
rt_close_callback<'c, F>(&self, f: F) where F: FnMut() + 'c,2474     pub fn rt_close_callback<'c, F>(&self, f: F)
2475     where
2476         F: FnMut() + 'c,
2477     {
2478         unsafe {
2479             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2480                 .callbacks
2481                 .set_rt_close_cb(self.engine.csound, f);
2482         }
2483     }
2484 
2485     /// Sets  callback to be called once in every control period.
2486     /// This facility can be used to ensure a function is called synchronously
2487     /// before every csound control buffer processing.
2488     /// It is important to make sure no blocking operations are performed in the callback.
sense_event_callback<'c, F>(&self, f: F) where F: FnMut() + 'c,2489     pub fn sense_event_callback<'c, F>(&self, f: F)
2490     where
2491         F: FnMut() + 'c,
2492     {
2493         unsafe {
2494             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2495                 .callbacks
2496                 .set_sense_event_cb(self.engine.csound, f);
2497         }
2498     }
2499 
2500     /*fn cscore_callback<'c, F>(&mut self, f:F)
2501         where F: FnMut() + 'c
2502     {
2503         self.engine.inner.handler.callbacks.cscore_cb = Some(Box::new(f));
2504         self.engine.enable_callback(CSCORE_CB);
2505     }*/
2506 
2507     /// Sets a callback which will be called by csound to print an informational message.
2508     /// # Arguments
2509     /// * ´f´ Function which implement the FnMut trait.
2510     /// The callback arguments are *u32* which indicates the message atributte,
2511     /// and a reference to the message content.
2512     /// # Example
2513     /// ```
2514     /// let mut cs = Csound::new();
2515     /// cs.message_string_callback(|att: MessageType, message: &str| print!("{}", message));
2516     /// ```
message_string_callback<'c, F>(&'c self, f: F) where F: FnMut(MessageType, &str) + 'c,2517     pub fn message_string_callback<'c, F>(&'c self, f: F)
2518     where
2519         F: FnMut(MessageType, &str) + 'c,
2520     {
2521         unsafe {
2522             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2523                 .callbacks
2524                 .set_message_cb(self.engine.csound, f);
2525         }
2526     }
2527 
2528     /*fn keyboard_callback<'c, F>(&self, f: F)
2529     where
2530         F: FnMut() -> char + 'c,
2531     {
2532         unsafe{(&mut *(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler)).callbacks.keyboard_cb = Some(Box::new(f));}
2533         self.enable_callback(KEYBOARD_CB);
2534     }*/
2535 
2536     /// Sets the function which will be called whenever the [*invalue*](http://www.csounds.com/manual/html/invalue.html) opcode is used.
2537     /// # Arguments
2538     /// * ´f´ Function which implement the FnMut trait. The invalue opcode will trigger this callback passing
2539     /// the channel name which requiere the data. This function/closure have to return the data which will be
2540     /// passed to that specific channel if not only return ChannelData::CS_UNKNOWN_CHANNEL. Only *String* and *control* Channels
2541     /// are supported.
2542     /// # Example
2543     /// ```
2544     /// let input_channel = |name: &str|->ChannelData {
2545     ///      if name == "myStringChannel"{
2546     ///          let myString = "my data".to_owned();
2547     ///          ChannelData::CS_STRING_CHANNEL(myString)
2548     ///      }
2549     ///      ChannelData::CS_UNKNOWN_CHANNEL
2550     /// };
2551     /// let mut cs = Csound::new();
2552     /// cs.input_channel_callback(input_channel);
2553     /// ```
input_channel_callback<'c, F>(&self, f: F) where F: FnMut(&str) -> ChannelData + 'c,2554     pub fn input_channel_callback<'c, F>(&self, f: F)
2555     where
2556         F: FnMut(&str) -> ChannelData + 'c,
2557     {
2558         unsafe {
2559             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2560                 .callbacks
2561                 .set_input_channel_cb(self.engine.csound, f);
2562         }
2563     }
2564 
2565     /// Sets the function which will be called whenever the [*outvalue*](http://www.csounds.com/manual/html/outvalue.html) opcode is used.
2566     /// # Arguments
2567     /// * ´f´ Function which implement the FnMut trait. The outvalue opcode will trigger this callback passing
2568     /// the channel ##name and the channel's output data encoded in the ChannelData. Only *String* and *control* Channels
2569     /// are supported.
2570     /// # Example
2571     /// ```
2572     /// let output_channel = |name: &str, data:ChannelData|{
2573     ///      print!("channel name:{}  data: {:?}", name, data);
2574     /// };
2575     /// let mut cs = Csound::new();
2576     /// cs.output_channel_callback(output_channel);
2577     /// ```
output_channel_callback<'c, F>(&self, f: F) where F: FnMut(&str, ChannelData) + 'c,2578     pub fn output_channel_callback<'c, F>(&self, f: F)
2579     where
2580         F: FnMut(&str, ChannelData) + 'c,
2581     {
2582         unsafe {
2583             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2584                 .callbacks
2585                 .set_output_channel_cb(self.engine.csound, f);
2586         }
2587     }
2588 
2589     /// Sets an external callback for receiving notices whenever Csound opens a file.
2590     /// The callback is made after the file is successfully opened.
2591     /// The following information is passed to the callback:
2592     /// ## `file_info`
2593     /// A [`FileInfo`](struct.FileInfo.html) struct containing the relevant file info.
file_open_callback<'c, F>(&self, f: F) where F: FnMut(&FileInfo) + 'c,2594     pub fn file_open_callback<'c, F>(&self, f: F)
2595     where
2596         F: FnMut(&FileInfo) + 'c,
2597     {
2598         unsafe {
2599             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2600                 .callbacks
2601                 .set_file_open_cb(self.engine.csound, f);
2602         }
2603     }
2604 
2605     /// Sets a function to be called by Csound for opening real-time MIDI input.
2606     /// This callback is used to inform to the user about the current MIDI input device.
2607     /// # Arguments
2608     /// * `user_func` A function/closure which will receive a reference
2609     ///  to a str with the device name.
midi_in_open_callback<'c, F>(&self, f: F) where F: FnMut(&str) + 'c,2610     pub fn midi_in_open_callback<'c, F>(&self, f: F)
2611     where
2612         F: FnMut(&str) + 'c,
2613     {
2614         unsafe {
2615             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2616                 .callbacks
2617                 .set_midi_in_open_cb(self.engine.csound, f);
2618         }
2619     }
2620 
2621     /// Sets a function to be called by Csound for opening real-time MIDI output.
2622     /// This callback is used to inform to the user about the current MIDI output device.
2623     /// # Arguments
2624     /// * `user_func` A function/closure which will receive a reference
2625     ///  to a str with the device name.
midi_out_open_callback<'c, F>(&self, f: F) where F: FnMut(&str) + 'c,2626     pub fn midi_out_open_callback<'c, F>(&self, f: F)
2627     where
2628         F: FnMut(&str) + 'c,
2629     {
2630         unsafe {
2631             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2632                 .callbacks
2633                 .set_midi_out_open_cb(self.engine.csound, f);
2634         }
2635     }
2636 
2637     /// Sets a function to be called by Csound for reading from real time MIDI input.
2638     /// A reference to a buffer with audio samples is passed
2639     /// to the user function in the callback.  The callback have to return the number of elements written to the buffer.
midi_read_callback<'c, F>(&self, f: F) where F: FnMut(&mut [u8]) -> usize + 'c,2640     pub fn midi_read_callback<'c, F>(&self, f: F)
2641     where
2642         F: FnMut(&mut [u8]) -> usize + 'c,
2643     {
2644         unsafe {
2645             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2646                 .callbacks
2647                 .set_midi_read_cb(self.engine.csound, f);
2648         }
2649     }
2650 
2651     /// Sets a function to be called by Csound for Writing to real time MIDI input.
2652     /// A reference to the device buffer is passed
2653     /// to the user function in the callback. The passed buffer have the max length that
2654     /// the user is able to use, and the callback have to return the number of element written into the buffer.
midi_write_callback<'c, F>(&self, f: F) where F: FnMut(&[u8]) -> usize + 'c,2655     pub fn midi_write_callback<'c, F>(&self, f: F)
2656     where
2657         F: FnMut(&[u8]) -> usize + 'c,
2658     {
2659         unsafe {
2660             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2661                 .callbacks
2662                 .set_midi_write_cb(self.engine.csound, f);
2663         }
2664     }
2665 
2666     /// Indicates to the user when csound has closed the midi input device.
midi_in_close_callback<'c, F>(&self, f: F) where F: FnMut() + 'c,2667     pub fn midi_in_close_callback<'c, F>(&self, f: F)
2668     where
2669         F: FnMut() + 'c,
2670     {
2671         unsafe {
2672             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2673                 .callbacks
2674                 .set_midi_in_close_cb(self.engine.csound, f);
2675         }
2676     }
2677 
2678     /// Indicates to the user when csound has closed the midi output device.
midi_out_close_callback<'c, F>(&self, f: F) where F: FnMut() + 'c,2679     pub fn midi_out_close_callback<'c, F>(&self, f: F)
2680     where
2681         F: FnMut() + 'c,
2682     {
2683         unsafe {
2684             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2685                 .callbacks
2686                 .set_midi_out_close_cb(self.engine.csound, f);
2687         }
2688     }
2689 
2690     /// Called by external software to set a function for checking system events, yielding cpu time for coopertative multitasking, etc
2691     /// This function is optional. It is often used as a way to 'turn off' Csound, allowing it to exit gracefully.
2692     /// In addition, some operations like utility analysis routines are not reentrant
2693     /// and you should use this function to do any kind of updating during the operation.
2694     /// # Returns
2695     /// If this callback returns *false* it wont be called anymore
yield_callback<'c, F>(&self, f: F) where F: FnMut() -> bool + 'c,2696     pub fn yield_callback<'c, F>(&self, f: F)
2697     where
2698         F: FnMut() -> bool + 'c,
2699     {
2700         unsafe {
2701             (*(csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler))
2702                 .callbacks
2703                 .set_yield_cb(self.engine.csound, f);
2704         }
2705     }
2706 } //End impl block
2707 
2708 // Drop method to free the memory using during the csound performance and instantiation
2709 impl Drop for Csound {
drop(&mut self)2710     fn drop(&mut self) {
2711         unsafe {
2712             csound_sys::csoundStop(self.engine.csound);
2713             csound_sys::csoundCleanup(self.engine.csound);
2714             let _ = Box::from_raw(
2715                 csound_sys::csoundGetHostData(self.engine.csound) as *mut CallbackHandler
2716             );
2717             // Checks if a message buffer exists and destroy it.
2718             let msg_buffer = self.engine.use_msg_buffer.borrow();
2719             if *msg_buffer {
2720                 csound_sys::csoundDestroyMessageBuffer(self.engine.csound);
2721             }
2722             csound_sys::csoundDestroy(self.engine.csound);
2723         }
2724     }
2725 }
2726 
2727 /// Csound's Circular Buffer object.
2728 /// This struct wraps a *mut T pointer to a circular buffer
2729 /// allocated by csound. This Circular buffer won't outlive
2730 /// the csound instance that allocated the buffer.
2731 pub struct CircularBuffer<'a, T: 'a + Copy> {
2732     csound: *mut csound_sys::CSOUND,
2733     ptr: *mut T,
2734     phantom: PhantomData<&'a T>,
2735 }
2736 
2737 impl<'a, T> CircularBuffer<'a, T>
2738 where
2739     T: Copy,
2740 {
2741     /// Read from circular buffer.
2742     /// # Arguments
2743     /// * `out` A mutable slice where the items will be copied.
2744     /// * `items` The number of elements to read and remove from the buffer.
2745     /// # Returns
2746     /// The number of items read **(0 <= n <= items)**.
2747     /// or an Error if the output buffer doesn't have enough capacity.
read(&self, out: &mut [T], items: u32) -> Result<usize, &'static str>2748     pub fn read(&self, out: &mut [T], items: u32) -> Result<usize, &'static str> {
2749         if items as usize <= out.len() {
2750             return Err("your buffer has not enough capacity");
2751         }
2752         unsafe {
2753             Ok(csound_sys::csoundReadCircularBuffer(
2754                 self.csound,
2755                 self.ptr as *mut c_void,
2756                 out.as_mut_ptr() as *mut c_void,
2757                 items as c_int,
2758             ) as usize)
2759         }
2760     }
2761 
2762     /// Read from circular buffer without removing them from the buffer.
2763     /// # Arguments
2764     /// * `out` A mutable slice where the items will be copied.
2765     /// * `items` The number of elements to peek from the buffer.
2766     /// # Returns
2767     /// The actual number of items read **(0 <= n <= items)**, or an error if the number of items
2768     /// to read/write exceeds the buffer's capacity.
peek(&self, out: &mut [T], items: u32) -> Result<usize, &'static str>2769     pub fn peek(&self, out: &mut [T], items: u32) -> Result<usize, &'static str> {
2770         if items as usize <= out.len() {
2771             return Err("your buffer has not enough capacity");
2772         }
2773         unsafe {
2774             Ok(csound_sys::csoundPeekCircularBuffer(
2775                 self.csound,
2776                 self.ptr as *mut c_void,
2777                 out.as_mut_ptr() as *mut c_void,
2778                 items as c_int,
2779             ) as usize)
2780         }
2781     }
2782 
2783     /// Write to the circular buffer.
2784     /// # Arguments
2785     /// * `input` A slice with the date which will be copied into the buffer.
2786     /// * `items` The number of elements to wrtie into the buffer.
2787     /// # Returns
2788     /// The actual number of items written *(0 <= n <= items)**, or an error if the number of items
2789     /// to read/write exceeds the buffer's capacity.
write(&self, input: &[T], items: u32) -> Result<usize, &'static str>2790     pub fn write(&self, input: &[T], items: u32) -> Result<usize, &'static str> {
2791         if items as usize <= input.len() {
2792             return Err("your buffer has not enough capacity");
2793         }
2794         unsafe {
2795             Ok(csound_sys::csoundWriteCircularBuffer(
2796                 self.csound,
2797                 self.ptr as *mut c_void,
2798                 input.as_ptr() as *const c_void,
2799                 items as c_int,
2800             ) as usize)
2801         }
2802     }
2803 
2804     /// Empty circular buffer of any remaining data.
2805     /// This function should only be used if there is no reader actively getting data from the buffer.
flush(&self)2806     pub fn flush(&self) {
2807         unsafe {
2808             csound_sys::csoundFlushCircularBuffer(self.csound, self.ptr as *mut c_void);
2809         }
2810     }
2811 }
2812 
2813 impl<'a, T> Drop for CircularBuffer<'a, T>
2814 where
2815     T: Copy,
2816 {
drop(&mut self)2817     fn drop(&mut self) {
2818         unsafe {
2819             csound_sys::csoundDestroyCircularBuffer(self.csound, self.ptr as *mut c_void);
2820         }
2821     }
2822 }
2823 
2824 /// Csound table representation.
2825 /// This struct is build up to manipulate directly a csound's table.
2826 #[derive(Debug)]
2827 pub struct Table<'a> {
2828     ptr: *mut f64,
2829     length: usize,
2830     phantom: PhantomData<&'a f64>,
2831 }
2832 
2833 impl<'a> Table<'a> {
2834     /// # Returns
2835     /// The table length
get_size(&self) -> usize2836     pub fn get_size(&self) -> usize {
2837         self.length
2838     }
2839 
2840     /// # Returns
2841     /// A slice representation with the table's internal data
as_slice(&self) -> &[f64]2842     pub fn as_slice(&self) -> &[f64] {
2843         unsafe { slice::from_raw_parts(self.ptr, self.length) }
2844     }
2845 
2846     /// # Returns
2847     /// A mutable slice representation with the table's internal data
as_mut_slice(&mut self) -> &mut [f64]2848     pub fn as_mut_slice(&mut self) -> &mut [f64] {
2849         unsafe { slice::from_raw_parts_mut(self.ptr, self.length) }
2850     }
2851 
2852     /// method used to copy data from the table internal buffer
2853     /// into an user buffer. A error message is returned if the Table is not longer valid.
2854     /// # Arguments
2855     /// * `slice` A slice where out.len() elements from the table will be copied.
2856     /// # Returns
2857     /// The number of elements copied into the output slice.
2858     /// # Example
2859     /// ```
2860     /// let cs = Csound::new();
2861     /// cs.compile_csd("some.csd");
2862     /// cs.start().unwrap();
2863     /// while cs.perform_ksmps() == false {
2864     ///     let mut table = cs.get_table(1).unwrap();
2865     ///     let mut table_buff = vec![0f64; table.length];
2866     ///     // copy Table::length elements from the table's internal buffer
2867     ///     table.copy_to_slice( table_buff.as_mut_slice() ).unwrap();
2868     ///     // Do some stuffs
2869     /// }
2870     /// ```
copy_to_slice(&self, slice: &mut [f64]) -> usize2871     pub fn copy_to_slice(&self, slice: &mut [f64]) -> usize {
2872         let mut len = slice.len();
2873         let size = self.get_size();
2874         if size < len {
2875             len = size;
2876         }
2877         unsafe {
2878             std::ptr::copy(self.ptr, slice.as_mut_ptr(), len);
2879             len
2880         }
2881     }
2882 
2883     /// method used to copy data into the table internal buffer
2884     /// from an user slice.
2885     /// # Arguments
2886     /// * `slice` A slice where input.len() elements will be copied.
2887     /// # Returns
2888     /// The number of elements copied into the table
2889     /// # Example
2890     /// ```
2891     /// let cs = Csound::new();
2892     /// cs.compile_csd("some.csd");
2893     /// cs.start().unwrap();
2894     /// while cs.perform_ksmps() == false {
2895     ///     let mut table = cs.get_table(1).unwrap();
2896     ///     let mut table_buff = vec![0f64; table.length];
2897     ///     // copy Table::length elements from the table's internal buffer
2898     ///     table.read( table_buff.as_mut_slice() ).unwrap();
2899     ///     // Do some stuffs
2900     ///     table.copy_from_slice(&table_buff.into_iter().map(|x| x*2.5).collect::<Vec<f64>>().as_mut_slice());
2901     ///     // Do some stuffs
2902     /// }
2903     /// ```
copy_from_slice(&self, slice: &[f64]) -> usize2904     pub fn copy_from_slice(&self, slice: &[f64]) -> usize {
2905         let mut len = slice.len();
2906         let size = self.get_size();
2907         if size < len {
2908             len = size;
2909         }
2910         unsafe {
2911             std::ptr::copy(slice.as_ptr(), self.ptr, len);
2912             len
2913         }
2914     }
2915 }
2916 
2917 impl<'a> AsRef<[f64]> for Table<'a> {
as_ref(&self) -> &[f64]2918     fn as_ref(&self) -> &[f64] {
2919         self.as_slice()
2920     }
2921 }
2922 
2923 impl<'a> AsMut<[f64]> for Table<'a> {
as_mut(&mut self) -> &mut [f64]2924     fn as_mut(&mut self) -> &mut [f64] {
2925         self.as_mut_slice()
2926     }
2927 }
2928 
2929 impl<'a> Deref for Table<'a> {
2930     type Target = [f64];
deref(&self) -> &[f64]2931     fn deref(&self) -> &[f64] {
2932         self.as_slice()
2933     }
2934 }
2935 
2936 impl<'a> DerefMut for Table<'a> {
deref_mut(&mut self) -> &mut [f64]2937     fn deref_mut(&mut self) -> &mut [f64] {
2938         self.as_mut_slice()
2939     }
2940 }
2941 
2942 pub enum Readable {}
2943 pub enum Writable {}
2944 
2945 /// Csound buffer pointer representation.
2946 /// This struct is build up to manipulate directly csound's buffers.
2947 pub struct BufferPtr<'a, T> {
2948     ptr: *mut f64,
2949     len: usize,
2950     phantom: PhantomData<&'a T>,
2951 }
2952 
2953 impl<'a, T> BufferPtr<'a, T> {
2954     /// # Returns
2955     /// The buffer length
get_size(&self) -> usize2956     pub fn get_size(&self) -> usize {
2957         self.len
2958     }
2959 
2960     /// This method is used to copy data from the csound's buffer
2961     /// into another slice.
2962     /// # Arguments
2963     /// * `slice` A mutable slice where the data will be copy
2964     /// # Returns
2965     /// The number of elements copied into the slice.
copy_to_slice(&self, slice: &mut [f64]) -> usize2966     pub fn copy_to_slice(&self, slice: &mut [f64]) -> usize {
2967         let mut len = slice.len();
2968         let size = self.get_size();
2969         if size < len {
2970             len = size;
2971         }
2972         unsafe {
2973             std::ptr::copy(self.ptr, slice.as_mut_ptr(), len);
2974             len
2975         }
2976     }
2977 
2978     /// # Returns
2979     /// A slice to the buffer internal data
as_slice(&self) -> &[f64]2980     pub fn as_slice(&self) -> &[f64] {
2981         unsafe { slice::from_raw_parts(self.ptr, self.len) }
2982     }
2983 }
2984 
2985 impl<'a> BufferPtr<'a, Writable> {
2986     /// # Returns
2987     /// This buffer pointer as a mutable slice.
as_mut_slice(&mut self) -> &mut [f64]2988     pub fn as_mut_slice(&mut self) -> &mut [f64] {
2989         unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
2990     }
2991 
2992     /// method used to copy data into this buffer
2993     /// # Arguments
2994     /// * `slice` A slice with samples to copy
2995     /// # Returns
2996     /// The number of elements copied into the csound's buffer.
copy_from_slice(&self, slice: &[f64]) -> usize2997     pub fn copy_from_slice(&self, slice: &[f64]) -> usize {
2998         let mut len = slice.len();
2999         let size = self.get_size();
3000         if size < len {
3001             len = size;
3002         }
3003         unsafe {
3004             std::ptr::copy(slice.as_ptr(), self.ptr, len);
3005             len
3006         }
3007     }
3008 
3009     /// method used to clear the buffer's data
clear(&mut self)3010     pub fn clear(&mut self) {
3011         for s in self.as_mut_slice() {
3012             *s = 0f64;
3013         }
3014     }
3015 }
3016 
3017 impl<'a, T> AsRef<[f64]> for BufferPtr<'a, T> {
as_ref(&self) -> &[f64]3018     fn as_ref(&self) -> &[f64] {
3019         self.as_slice()
3020     }
3021 }
3022 
3023 impl<'a> AsMut<[f64]> for BufferPtr<'a, Writable> {
as_mut(&mut self) -> &mut [f64]3024     fn as_mut(&mut self) -> &mut [f64] {
3025         self.as_mut_slice()
3026     }
3027 }
3028 
3029 impl<'a, T> Deref for BufferPtr<'a, T> {
3030     type Target = [f64];
deref(&self) -> &[f64]3031     fn deref(&self) -> &[f64] {
3032         self.as_slice()
3033     }
3034 }
3035 
3036 impl<'a> DerefMut for BufferPtr<'a, Writable> {
deref_mut(&mut self) -> &mut [f64]3037     fn deref_mut(&mut self) -> &mut [f64] {
3038         self.as_mut_slice()
3039     }
3040 }
3041