rfmod/
sound.rs

1/*
2* Rust-FMOD - Copyright (c) 2016 Gomez Guillaume.
3*
4* The Original software, FmodEx library, is provided by FIRELIGHT TECHNOLOGIES.
5*
6* This software is provided 'as-is', without any express or implied warranty.
7* In no event will the authors be held liable for any damages arising from
8* the use of this software.
9*
10* Permission is granted to anyone to use this software for any purpose,
11* including commercial applications, and to alter it and redistribute it
12* freely, subject to the following restrictions:
13*
14* 1. The origin of this software must not be misrepresented; you must not claim
15*    that you wrote the original software. If you use this software in a product,
16*    an acknowledgment in the product documentation would be appreciated but is
17*    not required.
18*
19* 2. Altered source versions must be plainly marked as such, and must not be
20*    misrepresented as being the original software.
21*
22* 3. This notice may not be removed or altered from any source distribution.
23*/
24
25use types::*;
26use libc::{c_int, c_uint, c_char, c_ushort, c_void};
27use ffi;
28use channel;
29use sound_group;
30use vector;
31use fmod_sys;
32use fmod_sys::{MemoryUsageDetails, Sys};
33use std::mem::transmute;
34use std::fs::File;
35use std::mem;
36use std::slice;
37use std::default::Default;
38use byteorder::{WriteBytesExt, LittleEndian};
39use std::io::Write;
40use std::ffi::CString;
41use std::time::Duration;
42
43struct RiffChunk {
44    id: [c_char; 4],
45    size: c_int
46}
47
48struct FmtChunk {
49    chunk: RiffChunk,
50    w_format_tag: c_ushort,     /* format type  */
51    n_channels: c_ushort,       /* number of channels (i.e. mono, stereo...)  */
52    n_samples_per_sec: c_uint,  /* sample rate  */
53    n_avg_bytes_per_sec: c_uint,/* for buffer estimation  */
54    n_block_align: c_ushort,    /* block size of data  */
55    w_bits_per_sample: c_ushort /* number of bits per sample of mono data */
56}
57
58struct DataChunk {
59    chunk: RiffChunk
60}
61
62struct WavHeader {
63    chunk: RiffChunk,
64    riff_type: [c_char; 4]
65}
66
67/// Wrapper for SyncPoint object
68pub struct FmodSyncPoint {
69    sync_point: *mut ffi::FMOD_SYNCPOINT
70}
71
72impl FmodSyncPoint {
73    fn from_ptr(pointer: *mut ffi::FMOD_SYNCPOINT) -> FmodSyncPoint {
74        FmodSyncPoint{sync_point: pointer}
75    }
76}
77
78/// Structure describing a piece of tag data.
79pub struct FmodTag {
80    /// [r] The type of this tag.
81    pub _type    : ::TagType,
82    /// [r] The type of data that this tag contains
83    pub data_type: ::TagDataType,
84    /// [r] The name of this tag i.e. "TITLE", "ARTIST" etc.
85    pub name     : String,
86    /// [r] Pointer to the tag data - its format is determined by the datatype member
87    data         : *mut c_void,
88    /// [r] Length of the data contained in this tag
89    data_len     : c_uint,
90    /// [r] True if this tag has been updated since last being accessed with
91    /// [`Sound::get_tag`](struct.Sound.html#method.get_tag)
92    pub updated  : bool,
93}
94
95impl Default for FmodTag {
96    fn default() -> FmodTag {
97        FmodTag {
98            _type: ::TagType::Unknown,
99            data_type: ::TagDataType::Binary,
100            name: String::new(),
101            data: ::std::ptr::null_mut(),
102            data_len: 0u32,
103            updated: false,
104        }
105    }
106}
107
108impl FmodTag {
109    fn from_ptr(pointer: ffi::FMOD_TAG) -> FmodTag {
110        FmodTag{
111            _type: pointer._type,
112            data_type: pointer.datatype,
113            name: {
114                if !pointer.name.is_null() {
115                    let l = ffi::strlen(pointer.name);
116
117                    unsafe { String::from_raw_parts(pointer.name as *mut u8, l, l) }
118                } else {
119                    String::new()
120                }
121            },
122            data: pointer.data,
123            data_len: pointer.datalen,
124            updated: {
125                if pointer.updated == 1 {
126                    true
127                } else {
128                    false
129                }
130            },
131        }
132    }
133
134    fn convert_to_c(&self) -> ffi::FMOD_TAG {
135        let tmp = CString::new(self.name.clone()).expect("CString failed");
136
137        ffi::FMOD_TAG {
138            _type: self._type,
139            datatype: self.data_type,
140            name: tmp.as_ptr() as *mut c_char,
141            data: self.data,
142            datalen: self.data_len,
143            updated: {
144                if self.updated == true {
145                    1
146                } else {
147                    0
148                }
149            },
150        }
151    }
152}
153
154/// Sound object
155pub struct Sound {
156    sound: *mut ffi::FMOD_SOUND,
157    can_be_deleted: bool,
158    user_data: ffi::SoundData,
159}
160
161impl ffi::FFI<ffi::FMOD_SOUND> for Sound {
162    fn wrap(s: *mut ffi::FMOD_SOUND) -> Sound {
163        Sound {sound: s, can_be_deleted: false, user_data: ffi::SoundData::new()}
164    }
165
166    fn unwrap(s: &Sound) -> *mut ffi::FMOD_SOUND {
167        s.sound
168    }
169}
170
171pub fn get_fffi<'r>(sound: &'r mut Sound) -> &'r mut *mut ffi::FMOD_SOUND {
172    &mut sound.sound
173}
174
175pub fn from_ptr_first(sound: *mut ffi::FMOD_SOUND) -> Sound {
176    Sound{sound: sound, can_be_deleted: true, user_data: ffi::SoundData::new()}
177}
178
179pub fn get_user_data<'r>(sound: &'r mut Sound) -> &'r mut ffi::SoundData {
180    &mut sound.user_data
181}
182
183impl Drop for Sound {
184    fn drop(&mut self) {
185        self.release();
186    }
187}
188
189impl Sound {
190    pub fn get_system_object(&self) -> Result<Sys, ::Status> {
191        let mut system = ::std::ptr::null_mut();
192
193        match unsafe { ffi::FMOD_Sound_GetSystemObject(self.sound, &mut system) } {
194            ::Status::Ok => Ok(ffi::FFI::wrap(system)),
195            e => Err(e),
196        }
197    }
198
199    pub fn release(&mut self) -> ::Status {
200        if self.can_be_deleted && !self.sound.is_null() {
201            match unsafe { ffi::FMOD_Sound_Release(self.sound) } {
202               ::Status::Ok => {
203                    self.sound = ::std::ptr::null_mut();
204                   ::Status::Ok
205                }
206                e => e,
207            }
208        } else {
209            ::Status::Ok
210        }
211    }
212
213    pub fn play(&self) -> Result<channel::Channel, ::Status> {
214        let mut channel = ::std::ptr::null_mut();
215
216        match match self.get_system_object() {
217            Ok(s) => { 
218                unsafe { ffi::FMOD_System_PlaySound(ffi::FFI::unwrap(&s), ::ChannelIndex::Free, self.sound, 0, &mut channel) }
219            }
220            Err(e) => e,
221        } {
222            ::Status::Ok => Ok(ffi::FFI::wrap(channel)),
223            e => Err(e),
224        }
225    }
226
227    pub fn play_with_parameters(&self, paused: bool, channel: &mut channel::Channel) -> ::Status {
228        let mut chan = ffi::FFI::unwrap(channel);
229        
230        match self.get_system_object() {
231            Ok(s) => { 
232                unsafe { ffi::FMOD_System_PlaySound(ffi::FFI::unwrap(&s), ::ChannelIndex::ReUse, self.sound, match paused {
233                    true => 1,
234                    false => 0,
235                }, &mut chan) }
236            }
237            Err(e) => e,
238        }
239    }
240
241    pub fn play_to_the_end(&self) -> ::Status {
242        match self.play() {
243            Ok(mut chan) => {
244                loop {
245                    match chan.is_playing() {
246                        Ok(b) => {
247                            if b == true {
248                                ::std::thread::sleep(Duration::from_millis(30))
249                            } else {
250                                break;
251                            }
252                        },
253                        Err(e) => return e,
254                    }
255                }
256                chan.release();
257                ::Status::Ok
258            }
259            Err(err) => err,
260        }
261    }
262
263    pub fn set_defaults(&self, frequency: f32, volume: f32, pan: f32, priority: i32) -> ::Status {
264        unsafe { ffi::FMOD_Sound_SetDefaults(self.sound, frequency, volume, pan, priority) }
265    }
266
267    pub fn get_defaults(&self) -> Result<(f32, f32, f32, i32), ::Status> {
268        let mut frequency = 0f32;
269        let mut volume = 0f32;
270        let mut pan = 0f32;
271        let mut priority = 0i32;
272
273        match unsafe { ffi::FMOD_Sound_GetDefaults(self.sound, &mut frequency, &mut volume,
274                                                   &mut pan, &mut priority) } {
275            ::Status::Ok => Ok((frequency, volume, pan, priority)),
276            e => Err(e),
277        }
278    }
279
280    pub fn set_variations(&self, frequency_var: f32, volume_var: f32, pan_var: f32) -> ::Status {
281        unsafe { ffi::FMOD_Sound_SetVariations(self.sound, frequency_var, volume_var, pan_var) }
282    }
283
284    /// Returns:
285    ///
286    /// Ok(frequency_var, volume_var, pan_var)
287    pub fn get_variations(&self) -> Result<(f32, f32, f32), ::Status> {
288        let mut frequency_var = 0f32;
289        let mut volume_var = 0f32;
290        let mut pan_var = 0f32;
291
292        match unsafe { ffi::FMOD_Sound_GetVariations(self.sound, &mut frequency_var,
293                                                     &mut volume_var, &mut pan_var) } {
294            ::Status::Ok => Ok((frequency_var, volume_var, pan_var)),
295            e => Err(e),
296        }
297    }
298
299    pub fn set_3D_min_max_distance(&self, min: f32, max: f32) -> ::Status {
300        unsafe { ffi::FMOD_Sound_Set3DMinMaxDistance(self.sound, min, max) }
301    }
302
303    /// Returns:
304    ///
305    /// Ok(min, max)
306    pub fn get_3D_min_max_distance(&self) -> Result<(f32, f32), ::Status> {
307        let mut max = 0f32;
308        let mut min = 0f32;
309
310        match unsafe { ffi::FMOD_Sound_Get3DMinMaxDistance(self.sound, &mut min, &mut max) } {
311            ::Status::Ok => Ok((min, max)),
312            e => Err(e),
313        }
314    }
315
316    pub fn set_3D_cone_settings(&self, inside_cone_angle: f32, outside_cone_angle: f32,
317                                outside_volume: f32) -> ::Status {
318        unsafe { ffi::FMOD_Sound_Set3DConeSettings(self.sound, inside_cone_angle,
319                                                   outside_cone_angle, outside_volume) }
320    }
321
322    /// Returns:
323    ///
324    /// Ok(inside_cone_angle, outside_cone_angle, outside_volume)
325    pub fn get_3D_cone_settings(&self) -> Result<(f32, f32, f32), ::Status> {
326        let mut inside_cone_angle = 0f32;
327        let mut outside_cone_angle = 0f32;
328        let mut outside_volume = 0f32;
329
330        match unsafe { ffi::FMOD_Sound_Get3DConeSettings(self.sound, &mut inside_cone_angle,
331                                                         &mut outside_cone_angle,
332                                                         &mut outside_volume) } {
333            ::Status::Ok => Ok((inside_cone_angle, outside_cone_angle, outside_volume)),
334            e => Err(e),
335        }
336    }
337
338    pub fn set_3D_custom_rolloff(&self, points: Vec<vector::Vector>) -> ::Status {
339        let mut points_vec = Vec::with_capacity(points.len());
340
341        for tmp in points.into_iter() {
342            points_vec.push(vector::get_ffi(&tmp));
343        }
344        unsafe { ffi::FMOD_Sound_Set3DCustomRolloff(self.sound, points_vec.as_mut_ptr(),
345                                                    points_vec.len() as i32) }
346    }
347
348    // to test
349    pub fn get_3D_custom_rolloff(&self, num_points: u32) -> Result<Vec<vector::Vector>, ::Status> {
350        let mut points_vec = Vec::with_capacity(num_points as usize);
351        let mut pointer = points_vec.as_mut_ptr();
352
353        match unsafe { ffi::FMOD_Sound_Get3DCustomRolloff(self.sound, &mut pointer,
354                                                          num_points as i32) } {
355            ::Status::Ok => {
356                let mut points = Vec::with_capacity(points_vec.len());
357
358                for tmp in points_vec.into_iter() {
359                    points.push(vector::from_ptr(tmp));
360                }
361                Ok(points)
362            }
363            e => Err(e),
364        }
365    }
366
367    pub fn set_sub_sound(&self, index: i32, sub_sound: Sound) -> ::Status {
368        unsafe { ffi::FMOD_Sound_SetSubSound(self.sound, index, sub_sound.sound) }
369    }
370
371    pub fn get_sub_sound(&self, index: i32) -> Result<Sound, ::Status> {
372        let mut sub_sound = ::std::ptr::null_mut();
373
374        match unsafe { ffi::FMOD_Sound_GetSubSound(self.sound, index, &mut sub_sound) } {
375            ::Status::Ok => Ok(ffi::FFI::wrap(sub_sound)),
376            e => Err(e),
377        }
378    }
379
380    pub fn get_name(&self, name_len: usize) -> Result<String, ::RStatus> {
381        let mut c = Vec::with_capacity(name_len + 1);
382
383        for _ in 0..(name_len + 1) {
384            c.push(0);
385        }
386
387        match unsafe { ffi::FMOD_Sound_GetName(self.sound, c.as_mut_ptr() as *mut c_char,
388                                               name_len as i32) } {
389            ::Status::Ok => Ok(from_utf8!(c)),
390            e => Err(::RStatus::FMOD(e)),
391        }
392    }
393
394    pub fn get_length(&self, TimeUnit(length_type): TimeUnit) -> Result<u32, ::Status> {
395        let mut length = 0u32;
396
397        match unsafe { ffi::FMOD_Sound_GetLength(self.sound, &mut length, length_type) } {
398            ::Status::Ok => Ok(length),
399            e => Err(e),
400        }
401    }
402
403    /// Returns:
404    ///
405    /// Ok(type, format, channels, bits)
406    pub fn get_format(&self) -> Result<(::SoundType, ::SoundFormat, i32, i32), ::Status> {
407        let mut _type = ::SoundType::Unknown;
408        let mut format = ::SoundFormat::None;
409        let mut channels = 0i32;
410        let mut bits = 0i32;
411
412        match unsafe { ffi::FMOD_Sound_GetFormat(self.sound, &mut _type, &mut format, &mut channels,
413                                                 &mut bits) } {
414            ::Status::Ok => Ok((_type, format, channels, bits)),
415            e => Err(e),
416        }
417    }
418
419    pub fn get_num_sub_sounds(&self) -> Result<i32, ::Status> {
420        let mut num_sub_sound = 0i32;
421
422        match unsafe { ffi::FMOD_Sound_GetNumSubSounds(self.sound, &mut num_sub_sound) } {
423            ::Status::Ok => Ok(num_sub_sound),
424            e => Err(e),
425        }
426    }
427
428    /// Returns:
429    ///
430    /// Ok(num_tags, num_tags_updated)
431    pub fn get_num_tags(&self) -> Result<(i32, i32), ::Status> {
432        let mut num_tags = 0i32;
433        let mut num_tags_updated = 0i32;
434
435        match unsafe { ffi::FMOD_Sound_GetNumTags(self.sound, &mut num_tags, &mut num_tags_updated) } {
436            ::Status::Ok => Ok((num_tags, num_tags_updated)),
437            e => Err(e),
438        }
439    }
440
441    //to test if tag's data needs to be filled by user
442    pub fn get_tag(&self, name: &str, index: i32) -> Result<FmodTag, ::Status> {
443        let mut tag = ffi::FMOD_TAG {
444            _type: ::TagType::Unknown,
445            datatype: ::TagDataType::Binary,
446            name: ::std::ptr::null_mut(),
447            data: ::std::ptr::null_mut(),
448            datalen: 0,
449            updated: 0,
450        };
451
452        match unsafe { ffi::FMOD_Sound_GetTag(self.sound, name.as_ptr() as *const c_char, index,
453                                              &mut tag) } {
454            ::Status::Ok => Ok(FmodTag::from_ptr(tag)),
455            e => Err(e),
456        }
457    }
458
459    pub fn get_open_state(&self) -> Result<(::OpenState, u32, bool, bool), ::Status> {
460        let mut open_state = ::OpenState::Ready;
461        let mut percent_buffered = 0u32;
462        let mut starving = 0;
463        let mut disk_busy = 0;
464
465        match unsafe { ffi::FMOD_Sound_GetOpenState(self.sound, &mut open_state,
466                                                    &mut percent_buffered, &mut starving,
467                                                    &mut disk_busy) } {
468            ::Status::Ok => Ok((open_state, percent_buffered,
469                if starving == 1 {
470                    true
471                } else {
472                    false
473                },
474                if disk_busy == 1 {
475                    true
476                } else {
477                    false
478                })),
479            e => Err(e),
480        }
481    }
482
483    pub fn set_sound_group(&self, sound_group: sound_group::SoundGroup) -> ::Status {
484        unsafe { ffi::FMOD_Sound_SetSoundGroup(self.sound, ffi::FFI::unwrap(&sound_group)) }
485    }
486
487    pub fn get_sound_group(&self) -> Result<sound_group::SoundGroup, ::Status> {
488        let mut sound_group = ::std::ptr::null_mut();
489
490        match unsafe { ffi::FMOD_Sound_GetSoundGroup(self.sound, &mut sound_group) } {
491            ::Status::Ok => Ok(ffi::FFI::wrap(sound_group)),
492            e => Err(e),
493        }
494    }
495
496    pub fn get_num_sync_points(&self) -> Result<i32, ::Status> {
497        let mut num_sync_points = 0i32;
498
499        match unsafe { ffi::FMOD_Sound_GetNumSyncPoints(self.sound, &mut num_sync_points) } {
500            ::Status::Ok => Ok(num_sync_points),
501            e => Err(e),
502        }
503    }
504
505    pub fn get_sync_point(&self, index: i32) -> Result<FmodSyncPoint, ::Status> {
506        let mut sync_point = ::std::ptr::null_mut();
507
508        match unsafe { ffi::FMOD_Sound_GetSyncPoint(self.sound, index, &mut sync_point) } {
509            ::Status::Ok => Ok(FmodSyncPoint::from_ptr(sync_point)),
510            e => Err(e),
511        }
512    }
513
514    pub fn get_sync_point_info(&self, sync_point: FmodSyncPoint, name_len: usize,
515                               TimeUnit(offset_type): TimeUnit) -> Result<(String, u32), ::RStatus> {
516        let mut offset = 0u32;
517        let mut c = Vec::with_capacity(name_len + 1);
518
519        for _ in 0..(name_len + 1) {
520            c.push(0);
521        }
522
523        match unsafe { ffi::FMOD_Sound_GetSyncPointInfo(self.sound, sync_point.sync_point,
524                                                        c.as_mut_ptr() as *mut c_char,
525                                                        name_len as i32, &mut offset,
526                                                        offset_type) } {
527            ::Status::Ok => Ok((from_utf8!(c), offset)),
528            e => Err(::RStatus::FMOD(e)),
529        }
530    }
531
532    pub fn add_sync_point(&self, offset: u32, TimeUnit(offset_type): TimeUnit,
533                          name: String) -> Result<FmodSyncPoint, ::Status> {
534        let mut sync_point = ::std::ptr::null_mut();
535
536        match unsafe { ffi::FMOD_Sound_AddSyncPoint(self.sound, offset, offset_type,
537                                                    name.as_ptr() as *const c_char,
538                                                    &mut sync_point) } {
539            ::Status::Ok => Ok(FmodSyncPoint::from_ptr(sync_point)),
540            e => Err(e),
541        }
542    }
543
544    pub fn delete_sync_point(&self, sync_point: FmodSyncPoint) -> ::Status {
545        unsafe { ffi::FMOD_Sound_DeleteSyncPoint(self.sound, sync_point.sync_point) }
546    }
547
548    pub fn set_mode(&self, Mode(mode): Mode) -> ::Status {
549        unsafe { ffi::FMOD_Sound_SetMode(self.sound, mode) }
550    }
551
552    pub fn get_mode(&self) -> Result<Mode, ::Status> {
553        let mut mode = 0u32;
554
555        match unsafe { ffi::FMOD_Sound_GetMode(self.sound, &mut mode) } {
556            ::Status::Ok => Ok(Mode(mode)),
557            e => Err(e),
558        }
559    }
560
561    pub fn set_loop_count(&self, loop_count: i32) -> ::Status {
562        unsafe { ffi::FMOD_Sound_SetLoopCount(self.sound, loop_count) }
563    }
564
565    pub fn get_loop_count(&self) -> Result<i32, ::Status> {
566        let mut loop_count = 0i32;
567
568        match unsafe { ffi::FMOD_Sound_GetLoopCount(self.sound, &mut loop_count) } {
569            ::Status::Ok => Ok(loop_count),
570            e => Err(e),
571        }
572    }
573
574    pub fn set_loop_points(&self, loop_start: u32, TimeUnit(loop_start_type): TimeUnit,
575                           loop_end: u32, TimeUnit(loop_end_type): TimeUnit) -> ::Status {
576        unsafe { ffi::FMOD_Sound_SetLoopPoints(self.sound, loop_start, loop_start_type, loop_end,
577                                               loop_end_type) }
578    }
579
580    /// Returns:
581    ///
582    /// Ok(loop_start, loop_end)
583    pub fn get_loop_points(&self, TimeUnit(loop_start_type): TimeUnit,
584                           TimeUnit(loop_end_type): TimeUnit) -> Result<(u32, u32), ::Status> {
585        let mut loop_start = 0u32;
586        let mut loop_end = 0u32;
587
588        match unsafe { ffi::FMOD_Sound_GetLoopPoints(self.sound, &mut loop_start, loop_start_type,
589                                                     &mut loop_end, loop_end_type) } {
590            ::Status::Ok => Ok((loop_start, loop_end)),
591            e => Err(e)
592        }
593    }
594
595    pub fn get_num_channels(&self) -> Result<i32, ::Status> {
596        let mut num_channels = 0i32;
597
598        match unsafe { ffi::FMOD_Sound_GetMusicNumChannels(self.sound, &mut num_channels) } {
599            ::Status::Ok => Ok(num_channels),
600            e => Err(e)
601        }
602    }
603
604    // TODO: see how to replace i32 channel by Channel struct
605    pub fn set_music_channel_volume(&self, channel: i32, volume: f32) -> ::Status {
606        unsafe { ffi::FMOD_Sound_SetMusicChannelVolume(self.sound, channel, volume) }
607    }
608
609    // TODO: see how to replace i32 channel by Channel struct
610    pub fn get_music_channel_volume(&self, channel: i32) -> Result<f32, ::Status> {
611        let mut volume = 0f32;
612
613        match unsafe { ffi::FMOD_Sound_GetMusicChannelVolume(self.sound, channel, &mut volume) } {
614            ::Status::Ok => Ok(volume),
615            e => Err(e)
616        }
617    }
618
619    pub fn set_music_speed(&self, speed: f32) -> ::Status {
620        unsafe { ffi::FMOD_Sound_SetMusicSpeed(self.sound, speed) }
621    }
622
623    pub fn get_music_speed(&self) -> Result<f32, ::Status> {
624        let mut speed = 0f32;
625
626        match unsafe { ffi::FMOD_Sound_GetMusicSpeed(self.sound, &mut speed) } {
627            ::Status::Ok => Ok(speed),
628            e => Err(e),
629        }
630    }
631
632    pub fn set_sub_sound_sentence(&self, sub_sounds: &mut Vec<i32>) -> ::Status {
633        unsafe { ffi::FMOD_Sound_SetSubSoundSentence(self.sound, sub_sounds.as_mut_ptr(),
634                                                     sub_sounds.len() as c_int) }
635    }
636
637    pub fn seek_data(&self, pcm: u32) -> ::Status {
638        unsafe { ffi::FMOD_Sound_SeekData(self.sound, pcm) }
639    }
640
641    /// Returns:
642    ///
643    /// Ok(memory_used, details)
644    pub fn get_memory_info(&self, MemoryBits(memory_bits): MemoryBits,
645                           EventMemoryBits(event_memory_bits): EventMemoryBits)
646                           -> Result<(u32, MemoryUsageDetails), ::Status> {
647        let mut details = fmod_sys::get_memory_usage_details_ffi(Default::default());
648        let mut memory_used = 0u32;
649
650        match unsafe { ffi::FMOD_Sound_GetMemoryInfo(self.sound, memory_bits, event_memory_bits,
651                                                     &mut memory_used, &mut details) } {
652            ::Status::Ok => Ok((memory_used, fmod_sys::from_memory_usage_details_ptr(details))),
653            e => Err(e),
654        }
655    }
656
657    /// Returns:
658    ///
659    /// Ok(ptr1, ptr2)
660    ///
661    /// ptr1: Address of a pointer that will point to the first part of the locked data.
662    ///
663    /// ptr2: Address of a pointer that will point to the second part of the locked data. This will
664    /// be null if the data locked hasn't wrapped at the end of the buffer.
665    pub fn lock(&self, offset: u32, length: u32) -> Result<(Vec<u8>, Vec<u8>), ::Status> {
666        let mut len1 = 0u32;
667        let mut len2 = 0u32;
668        let mut ptr1 = ::std::ptr::null_mut();
669        let mut ptr2 = ::std::ptr::null_mut();
670
671        match unsafe { ffi::FMOD_Sound_Lock(self.sound, offset, length, &mut ptr1, &mut ptr2,
672                                            &mut len1, &mut len2) } {
673            ::Status::Ok => {
674                unsafe {
675                    Ok((slice::from_raw_parts(ptr1 as *const u8, len1 as usize).clone().to_vec(),
676                        slice::from_raw_parts(ptr2 as *const u8, len2 as usize).clone().to_vec()))
677                }
678            }
679            e => Err(e),
680        }
681    }
682
683    pub fn unlock(&self, v_ptr1: Vec<u8>, v_ptr2: Vec<u8>) -> ::Status {
684        unsafe { ffi::FMOD_Sound_Unlock(self.sound, v_ptr1.as_ptr() as *mut c_void,
685                                        v_ptr2.as_ptr() as *mut c_void, v_ptr1.len() as c_uint,
686                                        v_ptr2.len() as c_uint) }
687    }
688
689    pub fn set_user_data<'r, T>(&'r mut self, user_data: &'r mut T) -> ::Status {
690        let mut data : *mut c_void = ::std::ptr::null_mut();
691
692        unsafe {
693            match ffi::FMOD_Sound_GetUserData(self.sound, &mut data) {
694               ::Status::Ok => {
695                    if data.is_null() {
696                        self.user_data.user_data = ::std::ptr::null_mut();
697
698                        ffi::FMOD_Sound_SetUserData(self.sound, transmute(&mut self.user_data))
699                    } else {
700                        let tmp: &mut ffi::SoundData =
701                            transmute::<*mut c_void, &mut ffi::SoundData>(data);
702
703                        tmp.user_data = transmute::<&mut T, *mut c_void>(user_data);
704                        ffi::FMOD_Sound_SetUserData(self.sound, transmute(tmp))
705                    }
706                }
707                _ => {
708                    self.user_data.user_data = transmute::<&mut T, *mut c_void>(user_data);
709
710                    ffi::FMOD_Sound_SetUserData(self.sound, transmute(&mut self.user_data))
711                }
712            }
713        }
714    }
715
716    pub fn get_user_data<'r, T>(&'r self) -> Result<&'r mut T, ::Status> {
717        unsafe {
718            let mut user_data : *mut c_void = ::std::ptr::null_mut();
719
720            match ffi::FMOD_Sound_GetUserData(self.sound, &mut user_data) {
721               ::Status::Ok => {
722                    if !user_data.is_null() {
723                        let tmp: &mut ffi::SoundData =
724                            transmute::<*mut c_void, &mut ffi::SoundData>(user_data);
725                        let tmp2: &mut T = transmute::<*mut c_void, &mut T>(tmp.user_data);
726                        
727                        Ok(tmp2)
728                    } else {
729                        // ?
730                        Err(::Status::Ok)
731                    }
732                },
733                e => Err(e)
734            }
735        }
736    }
737
738    pub fn save_to_wav(&self, file_name: &str) -> Result<bool, String> {
739        unsafe {
740            let mut channels = 0i32;
741            let mut bits = 0i32;
742            let mut rate = 0f32;
743            let len_bytes = match self.get_length(::TIMEUNIT_PCMBYTES) {
744                Ok(l) => l,
745                Err(e) => return Err(format!("{:?}", e))
746            };
747            let mut len1 = 0u32;
748            let mut len2 = 0u32;
749            let mut ptr1: *mut c_void =::std::ptr::null_mut();
750            let mut ptr2: *mut c_void =::std::ptr::null_mut();
751
752            match ffi::FMOD_Sound_GetFormat(self.sound, ::std::ptr::null_mut(),
753                                            ::std::ptr::null_mut(), &mut channels, &mut bits) {
754               ::Status::Ok => match ffi::FMOD_Sound_GetDefaults(self.sound, &mut rate,
755                                                                 ::std::ptr::null_mut(),
756                                                                 ::std::ptr::null_mut(),
757                                                                 ::std::ptr::null_mut()) {
758                   ::Status::Ok => {}
759                    e => return Err(format!("{:?}", e))
760                },
761                e => return Err(format!("{:?}", e))
762            };
763            let fmt_chunk = FmtChunk {
764                chunk: RiffChunk {
765                    id: ['f' as i8, 'm' as i8, 't' as i8, ' ' as i8],
766                    size: mem::size_of::<FmtChunk>() as i32 - mem::size_of::<RiffChunk>() as i32
767                },
768                w_format_tag: 1,
769                n_channels: channels as u16,
770                n_samples_per_sec: rate as u32,
771                n_avg_bytes_per_sec: rate as u32 * channels as u32 * bits as u32 / 8u32,
772                n_block_align: 1u16 * channels as u16 * bits as u16 / 8u16,
773                w_bits_per_sample: bits as u16
774            };
775            let data_chunk = DataChunk {
776                chunk: RiffChunk {
777                    id: ['d' as i8, 'a' as i8, 't' as i8, 'a' as i8],
778                    size: len_bytes as i32
779                }
780            };
781            let wav_header = WavHeader {
782                chunk: RiffChunk {
783                    id: ['R' as i8, 'I' as i8, 'F' as i8, 'F' as i8],
784                    size: mem::size_of::<FmtChunk>() as i32 + mem::size_of::<RiffChunk>() as i32 + len_bytes as i32
785                },
786                riff_type: ['W' as i8, 'A' as i8, 'V' as i8, 'E' as i8]
787            };
788
789            let mut file = match File::create(file_name) {
790                Ok(f) => f,
791                Err(e) => return Err(format!("{}", e))
792            };
793            let mut wtr = vec![];
794
795            /* wav header */
796            for it in 0usize..4usize {
797                if let Err(e) = wtr.write_i8(wav_header.chunk.id[it]) {
798                    return Err(format!("write_i8 failed: {}", e));
799                }
800            }
801            if let Err(e) = wtr.write_i32::<LittleEndian>(wav_header.chunk.size) {
802                return Err(format!("write_i32 failed: {}", e));
803            }
804            for it in 0usize..4usize {
805                if let Err(e) = wtr.write_i8(wav_header.riff_type[it]) {
806                    return Err(format!("write_i8 failed: {}", e));
807                }
808            }
809
810            /* wav chunk */
811            for it in 0usize..4usize {
812                if let Err(e) = wtr.write_i8(fmt_chunk.chunk.id[it]) {
813                    return Err(format!("write_i8 failed: {}", e));
814                }
815            }
816            if let Err(e) = wtr.write_i32::<LittleEndian>(fmt_chunk.chunk.size) {
817                return Err(format!("write_i32 failed: {}", e));
818            }
819            if let Err(e) = wtr.write_u16::<LittleEndian>(fmt_chunk.w_format_tag) {
820                return Err(format!("write_u16 failed: {}", e));
821            }
822            if let Err(e) = wtr.write_u16::<LittleEndian>(fmt_chunk.n_channels) {
823                return Err(format!("write_u16 failed: {}", e));
824            }
825            if let Err(e) = wtr.write_u32::<LittleEndian>(fmt_chunk.n_samples_per_sec) {
826                return Err(format!("write_u32 failed: {}", e));
827            }
828            if let Err(e) = wtr.write_u32::<LittleEndian>(fmt_chunk.n_avg_bytes_per_sec) {
829                return Err(format!("write_u32 failed: {}", e));
830            }
831            if let Err(e) = wtr.write_u16::<LittleEndian>(fmt_chunk.n_block_align) {
832                return Err(format!("write_u16 failed: {}", e));
833            }
834            if let Err(e) = wtr.write_u16::<LittleEndian>(fmt_chunk.w_bits_per_sample) {
835                return Err(format!("write_u16 failed: {}", e));
836            }
837
838            /* wav data chunk */
839            for it in 0usize..4usize {
840                if let Err(e) = wtr.write_i8(data_chunk.chunk.id[it]) {
841                    return Err(format!("write_i8 failed: {}", e));
842                }
843            }
844            if let Err(e) = wtr.write_i32::<LittleEndian>(data_chunk.chunk.size) {
845                return Err(format!("write_i32 failed: {}", e));
846            }
847
848            ffi::FMOD_Sound_Lock(self.sound, 0, len_bytes, &mut ptr1, &mut ptr2, &mut len1, &mut len2);
849
850            if let Err(e) = file.write_all(&wtr) {
851                return Err(format!("write_all failed: {}", e));
852            }
853
854            ffi::FMOD_Sound_Unlock(self.sound, ptr1, ptr2, len1, len2);
855        }
856        Ok(true)
857    }
858}