1extern crate openmpt_sys;
2extern crate sfml;
3
4use crate::string::OpenMptString;
5use openmpt_sys::*;
6use sfml::audio::SoundStream;
7use sfml::system::Time;
8use std::fs::File;
9use std::io;
10use std::io::prelude::*;
11use std::path::Path;
12use std::ptr;
13
14mod string;
15
16pub struct ModStream {
17 module: *mut openmpt_module,
18 buffer: [i16; 2048],
19}
20
21impl ModStream {
22 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
23 let mut file = File::open(path)?;
24 let mut buf = Vec::new();
25 file.read_to_end(&mut buf)?;
26 Ok(Self::from_memory(&buf))
27 }
28 pub fn from_memory(data: &[u8]) -> Self {
29 unsafe {
30 let module = openmpt_module_create_from_memory(
31 data.as_ptr() as *const _,
32 data.len(),
33 None,
34 ptr::null_mut(),
35 ptr::null(),
36 );
37 if module.is_null() {
38 panic!("Failed load module");
39 }
40 Self {
41 module,
42 buffer: [0; 2048],
43 }
44 }
45 }
46 pub fn get_duration_seconds(&self) -> f64 {
47 unsafe { openmpt_module_get_duration_seconds(self.module) }
48 }
49 pub fn metadata<'a, K: Key<'a>>(&self, key: K) -> Option<OpenMptString> {
50 let key = std::ffi::CString::new(key.into_str()).unwrap();
51 let ret = unsafe { openmpt_module_get_metadata(self.module, key.as_ptr()) };
52 OpenMptString::new(ret)
53 }
54}
55
56pub trait Key<'a> {
57 fn into_str(self) -> &'a str;
58}
59
60impl<'a> Key<'a> for &'a str {
61 fn into_str(self) -> &'a str {
62 self
63 }
64}
65
66pub enum Metadata {
67 Tracker,
68 Artist,
69 Title,
70 Date,
71 Message,
72}
73
74impl Key<'static> for Metadata {
75 fn into_str(self) -> &'static str {
76 match self {
77 Self::Tracker => "tracker",
78 Self::Artist => "artist",
79 Self::Title => "title",
80 Self::Date => "date",
81 Self::Message => "message",
82 }
83 }
84}
85
86impl SoundStream for ModStream {
87 fn get_data(&mut self) -> (&mut [i16], bool) {
88 unsafe {
89 let keep_playing = openmpt_module_read_interleaved_stereo(
90 self.module,
91 44_100,
92 1024,
93 self.buffer.as_mut_ptr(),
94 ) != 0;
95 (&mut self.buffer[..], keep_playing)
96 }
97 }
98 fn seek(&mut self, offset: Time) {
99 unsafe {
100 openmpt_module_set_position_seconds(self.module, f64::from(offset.as_seconds()));
101 }
102 }
103 fn sample_rate(&self) -> u32 {
104 44_100
105 }
106 fn channel_count(&self) -> u32 {
107 2
108 }
109}
110
111impl Drop for ModStream {
112 fn drop(&mut self) {
113 unsafe {
114 openmpt_module_destroy(self.module);
115 }
116 }
117}