sunvox_sys/
lib.rs

1//! # sunvox-sys
2//!
3//! FFI bindings to the Sunvox library (http://warmplace.ru/soft/sunvox).
4
5
6// --- Crate attributes --- //
7#![allow(non_camel_case_types)]
8// --- ==== --- //
9
10
11// --- External crates --- //
12extern crate libc;
13// --- ==== --- //
14
15
16// --- Use --- //
17use libc::{c_void, c_int, c_uint, c_char, c_uchar, c_short, c_ushort};
18// --- ==== --- //
19
20
21/// Single note off.
22pub const NOTECMD_NOTE_OFF: c_int = 128;
23
24/// Notes of all synths off.
25pub const NOTECMD_ALL_NOTES_OFF: c_int = 129;
26
27/// Stop and clean all synths.
28pub const NOTECMD_CLEAN_SYNTHS: c_int = 130;
29
30pub const NOTECMD_STOP: c_int = 131;
31pub const NOTECMD_PLAY: c_int = 132;
32
33// I can't find these in the official header file, but they're defined in
34// https://github.com/metrasynth/sunvox-dll-python/blob/master/sunvox/types.py
35/// Change the pitch of a currently playing note.
36pub const NOTECMD_SET_PITCH: c_int = 133;
37
38/// Apply effect in this note cell to the corresponding one in the previous track.
39pub const NOTECMD_PREV_TRACK: c_int = 134;
40
41
42/// A single note cell in a pattern.
43#[repr(C)]
44#[derive(Clone, Debug)]
45pub struct sunvox_note {
46    /// The note column.
47    ///
48    /// - 0:  Nothing.
49    /// - 1 to 127 inclusive: A normal note.
50    /// - 128+: See the `NOTECMD` constants.
51    pub note: c_uchar,
52
53    /// The velocity column (note velocity).
54    ///
55    /// - 0: Empty (default).
56    /// - 1 to 129 inclusive: The specified velocity + 1.
57    pub vel: c_uchar,
58
59    /// The module column (module to affect).
60    ///
61    /// - 0: Empty (none).
62    /// - 1 to 255 inclusive: The specified module + 1.
63    pub module: c_uchar,
64
65    /// Padding.
66    pub nothing: c_uchar,
67
68    /// The value of the controller/effect column.
69    ///
70    /// Interpreted as a hexadecimal number, the first two digits are the
71    /// controller of the selected module to affect, and the last two digits
72    /// are the number of an effect. Set a pair of digits to zero to
73    /// ignore that part.
74    pub ctl: c_ushort,
75
76    /// The value of the controller/effect parameter column.
77    pub ctl_val: c_ushort,
78}
79
80
81/// Supresses debug output from the SunVox library.
82pub const SV_INIT_FLAG_NO_DEBUG_OUTPUT: c_uint = 1 << 0;
83
84/// Interaction with sound card is on the user side.
85///
86/// See `sv_audio_callback()`.
87pub const SV_INIT_FLAG_USER_AUDIO_CALLBACK: c_uint = 1 << 1;
88
89/// Audio is signed 16-bit (`c_short`).
90pub const SV_INIT_FLAG_AUDIO_INT16: c_uint = 1 << 2;
91
92/// Audio is float (`c_float`).
93pub const SV_INIT_FLAG_AUDIO_FLOAT32: c_uint = 1 << 3;
94
95/// Audio callback and song modification functions are in a single thread.
96pub const SV_INIT_FLAG_ONE_THREAD: c_uint = 1 << 4;
97
98
99pub const SV_MODULE_FLAG_EXISTS: c_int = 1;
100pub const SV_MODULE_FLAG_EFFECT: c_int = 2;
101pub const SV_MODULE_INPUTS_OFF: c_int = 16;
102pub const SV_MODULE_INPUTS_MASK: c_int = 255 << SV_MODULE_INPUTS_OFF;
103pub const SV_MODULE_OUTPUTS_OFF: c_int = 16 + 8;
104pub const SV_MODULE_OUTPUTS_MASK: c_int = 255 << SV_MODULE_OUTPUTS_OFF;
105
106
107pub const SV_STYPE_INT16: c_int = 0;
108pub const SV_STYPE_INT32: c_int = 1;
109pub const SV_STYPE_FLOAT32: c_int = 2;
110pub const SV_STYPE_FLOAT64: c_int = 3;
111
112
113#[link(name = "sunvox")]
114extern "C" {
115    /// Gets the next piece of SunVox audio.
116    ///
117    /// With `sv_audio_callback()` you can ignore the built-in SunVox sound
118    /// output mechanism and use some other sound system. Set the
119    /// `SV_INIT_FLAG_USER_AUDIO_CALLBACK` flag when calling `sv_init()` if
120    /// you want to use this function.
121    ///
122    /// # Parameters
123    ///
124    /// - buf: Destination buffer. If `SV_INIT_FLAG_AUDIO_INT16` was passed to
125    /// `sv_init()`, this is a buffer of `c_short`s. If `SV_INIT_FLAG_AUDIO_FLOAT32`
126    /// was passed, this is a buffer of `c_float`s. Stereo data will be interleaved
127    /// in this buffer: LRLR... ; where the LR is one frame (Left+Right channels).
128    /// - frames: Number of frames in destination buffer.
129    /// - latency: Audio latency (in frames).
130    /// - out_time: Output time (in ticks).
131    ///
132    /// The `out_time` parameter is elaborated on a little bit in this thread:
133    /// http://www.warmplace.ru/forum/viewtopic.php?f=12&t=4152
134    ///
135    /// For normal use, pass the value of `sv_get_ticks()`, as detailed in that
136    /// thread.
137    pub fn sv_audio_callback(buf: *mut c_void,
138                             frames: c_int,
139                             latency: c_int,
140                             out_time: c_uint)
141                             -> c_int;
142
143
144    /// Opens a slot.
145    ///
146    /// A slot is like an instance of the SunVox engine. Each slot can have a
147    /// single project loaded at a time. The library supports up to four slots,
148    /// 0 to 3 inclusive. This call appears to hang if called with a number
149    /// outside this range.
150    ///
151    /// Returns 0 on success, -1 on failure. Failure conditions include the
152    /// slot already being open.
153    ///
154    /// I say "like" an instance of the engine because I think all slots share
155    /// the same tick counter, which you can get by calling `sv_get_ticks()`.
156    pub fn sv_open_slot(slot: c_int) -> c_int;
157
158    /// Closes a slot. See `sv_open_slot()` for more details.
159    pub fn sv_close_slot(slot: c_int) -> c_int;
160
161    /// Locks a slot.
162    ///
163    /// There are a few functions that need to be called between a
164    /// `sv_lock_slot()`/`sv_unlock_slot()` pair. These are marked with
165    /// "USE LOCK/UNLOCK!".
166    pub fn sv_lock_slot(slot: c_int) -> c_int;
167
168    /// Unlocks a slot. See `sv_lock_slot()` for more details.
169    pub fn sv_unlock_slot(slot: c_int) -> c_int;
170
171
172    /// Initializes the library.
173    ///
174    /// The `flags` parameter takes either zero (for default options), or a
175    /// number of `SV_INIT_FLAG_xxx` constants ORed together.
176    pub fn sv_init(dev: *const c_char, freq: c_int, channels: c_int, flags: c_uint) -> c_int;
177
178    /// Deinitializes the library.
179    pub fn sv_deinit() -> c_int;
180
181
182    /// Gets the internal sample type of the SunVox engine.
183    ///
184    /// Returns one of the `SV_STYPE_xxx` constants.
185    ///
186    /// Use it to get the scope buffer type from `get_module_scope()` function.
187    pub fn sv_get_sample_type() -> c_int;
188
189
190    /// Loads a SunVox project file into the specified slot.
191    pub fn sv_load(slot: c_int, name: *const c_char) -> c_int;
192
193    /// Loads a SunVox project from file data in memory. TEST
194    pub fn sv_load_from_memory(slot: c_int, data: *mut c_void, data_size: c_uint) -> c_int;
195
196
197    /// Starts playing the project from the current play cursor position.
198    pub fn sv_play(slot: c_int) -> c_int;
199
200    /// Starts playing the project from the beginning.
201    pub fn sv_play_from_beginning(slot: c_int) -> c_int;
202
203    /// Stops playing the project. The play cursor stays where it is.
204    pub fn sv_stop(slot: c_int) -> c_int;
205
206    /// Enables or disables autostop.
207    ///
208    /// - 0: Disable autostop.
209    /// - 1: Enable autostop.
210    ///
211    /// When disabled, the project plays in a loop.
212    pub fn sv_set_autostop(slot: c_int, autostop: c_int) -> c_int;
213
214
215    /// Gets whether the project is stopped (ie. not playing).
216    ///
217    /// Returns 0 if it is playing, 1 if it is stopped.
218    pub fn sv_end_of_song(slot: c_int) -> c_int;
219
220
221    /// Rewinds the project to the beginning.
222    pub fn sv_rewind(slot: c_int, line_num: c_int) -> c_int;
223
224
225    /// Sets the volume of the project.
226    pub fn sv_volume(slot: c_int, vol: c_int) -> c_int;
227
228
229    /// Causes an event to occur as though it had been played in a pattern.
230    ///
231    /// `track_num` is in the range 0 to 15 inclusive, and refers to the track
232    /// number in a special hidden pattern.
233    pub fn sv_send_event(slot: c_int,
234                         track_num: c_int,
235                         note: c_int,
236                         vel: c_int,
237                         module: c_int,
238                         ctl: c_int,
239                         ctl_val: c_int)
240                         -> c_int;
241
242
243    /// Gets the line number of the play cursor.
244    pub fn sv_get_current_line(slot: c_int) -> c_int;
245
246    /// Gets the line number of the play in fixed point format: 27.5
247    ///
248    /// TODO: Figure out exactly what this means.
249    /// I'm guessing it means 27 bits for the integer part and 5 bits for the
250    /// fractional part.
251    pub fn sv_get_current_line2(slot: c_int) -> c_int;
252
253
254    /// Gets the current signal level/amplitude for a given audio channel
255    /// in the range 0 to 255 inclusive.
256    pub fn sv_get_current_signal_level(slot: c_int, channel: c_int) -> c_int;
257
258
259    /// Gets the name of the currently loaded project.
260    ///
261    /// Returns NULL if no project is loaded.
262    pub fn sv_get_song_name(slot: c_int) -> *const c_char;
263
264
265    /// Gets the Beats Per Minute of the currently loaded project.
266    ///
267    /// Returns zero if no project is loaded.
268    pub fn sv_get_song_bpm(slot: c_int) -> c_int;
269
270
271    /// Gets the Ticks Per Line of the currently loaded project.
272    ///
273    /// Returns zero if no project is loaded.
274    pub fn sv_get_song_tpl(slot: c_int) -> c_int;
275
276
277    /// Gets the currently loaded song's length in audio samples/frames.
278    pub fn sv_get_song_length_frames(slot: c_int) -> c_uint;
279
280    /// Gets the currently loaded song's length in pattern lines.
281    pub fn sv_get_song_length_lines(slot: c_int) -> c_uint;
282
283
284    /// Creates a new module. USE LOCK/UNLOCK!
285    pub fn sv_new_module(slot: c_int,
286                         _type: *const c_char,
287                         name: *const c_char,
288                         x: c_int,
289                         y: c_int,
290                         z: c_int)
291                         -> c_int;
292
293    /// Removes the specified module. USE LOCK/UNLOCK!
294    pub fn sv_remove_module(slot: c_int, mod_num: c_int) -> c_int;
295
296    /// Connects the source to the destination. USE LOCK/UNLOCK!
297    pub fn sv_connect_module(slot: c_int, source: c_int, destination: c_int) -> c_int;
298
299    /// Disconnects the source from the destination. USE LOCK/UNLOCK!
300    pub fn sv_disconnect_module(slot: c_int, source: c_int, destination: c_int) -> c_int;
301
302    /// Loads a module.
303    ///
304    /// Supported file formats: `sunsynth`, `xi`, `wav`, `aiff`
305    pub fn sv_load_module(slot: c_int,
306                          file_name: *const c_char,
307                          x: c_int,
308                          y: c_int,
309                          z: c_int)
310                          -> c_int;
311
312    /// Loads a sample to an existing Sampler.
313    ///
314    /// To replace the whole sampler, set `sample_slot` to -1.
315    pub fn sv_sampler_load(slot: c_int,
316                           sampler_module: c_int,
317                           file_name: *const c_char,
318                           sample_slot: c_int)
319                           -> c_int;
320
321
322    /// Gets the number of modules in the currently loaded project?
323    ///
324    /// Does not seem to directly correspond to that.
325    /// TODO: Investigate this.
326    ///
327    /// Returns zero if no project is loaded.
328    pub fn sv_get_number_of_modules(slot: c_int) -> c_int;
329
330
331    pub fn sv_get_module_flags(slot: c_int, mod_num: c_int) -> c_uint;
332    pub fn sv_get_module_inputs(slot: c_int, mod_num: c_int) -> *mut c_int;
333    pub fn sv_get_module_outputs(slot: c_int, mod_num: c_int) -> *mut c_int;
334    pub fn sv_get_module_name(slot: c_int, mod_num: c_int) -> *const c_char;
335    pub fn sv_get_module_xy(slot: c_int, mod_num: c_int) -> c_uint;
336    pub fn sv_get_module_color(slot: c_int, mod_num: c_int) -> c_int;
337    pub fn sv_get_module_scope(slot: c_int,
338                               mod_num: c_int,
339                               channel: c_int,
340                               buffer_offset: *mut c_int,
341                               buffer_size: *mut c_int)
342                               -> *mut c_void;
343
344    /// Return value: received number of samples (may be less or equal to `samples_to_read`).
345    pub fn sv_get_module_scope2(slot: c_int,
346                                mod_num: c_int,
347                                channel: c_int,
348                                read_buf: *mut c_short,
349                                samples_to_read: c_uint)
350                                -> c_uint;
351
352    pub fn sv_get_number_of_module_ctls(slot: c_int, mod_num: c_int) -> c_int;
353    pub fn sv_get_module_ctl_name(slot: c_int, mod_num: c_int, ctl_num: c_int) -> *const c_char;
354    pub fn sv_get_module_ctl_value(slot: c_int,
355                                   mod_num: c_int,
356                                   ctl_num: c_int,
357                                   scaled: c_int)
358                                   -> c_int;
359
360
361    pub fn sv_get_number_of_patterns(slot: c_int) -> c_int;
362    pub fn sv_get_pattern_x(slot: c_int, pat_num: c_int) -> c_int;
363    pub fn sv_get_pattern_y(slot: c_int, pat_num: c_int) -> c_int;
364    pub fn sv_get_pattern_tracks(slot: c_int, pat_num: c_int) -> c_int;
365    pub fn sv_get_pattern_lines(slot: c_int, pat_num: c_int) -> c_int;
366
367
368    /// How to use sv_get_pattern_data():
369    ///
370    /// - `int pat_tracks = sv_get_pattern_tracks(slot, pat_num);`
371    /// - `sunvox_note* data = sv_get_pattern_data(slot, pat_num);`
372    /// - `sunvox_note* n = &data[ line_number * pat_tracks + track_number ];`
373    /// - ... and then do someting with note n
374    pub fn sv_get_pattern_data(slot: c_int, pat_num: c_int) -> *mut sunvox_note;
375
376
377    /// USE LOCK/UNLOCK!
378    pub fn sv_pattern_mute(slot: c_int, pat_num: c_int, mute: c_int) -> c_int;
379
380
381    /// Gets the current tick counter (from 0 to 0xFFFFFFFF).
382    ///
383    /// SunVox engine uses its own time space, measured in ticks.
384    pub fn sv_get_ticks() -> c_uint;
385
386    /// Gets the number of SunVox ticks per second.
387    pub fn sv_get_ticks_per_second() -> c_uint;
388}