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