-
Notifications
You must be signed in to change notification settings - Fork 1
/
xm.h
307 lines (255 loc) · 9.65 KB
/
xm.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/* Author: Romain "Artefact2" Dalmaso <artefact2@gmail.com> */
/* Contributor: Dan Spencer <dan@atomicpotato.net> */
/* This program is free software. It comes without any warranty, to the
* extent permitted by applicable law. You can redistribute it and/or
* modify it under the terms of the Do What The Fuck You Want To Public
* License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. */
#pragma once
#ifndef __has_xm_h
#define __has_xm_h
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
struct xm_context_s;
typedef struct xm_context_s xm_context_t;
/**
* Defines normally passed in as compiler flags, but included here instead.
**/
// Enable debug symbols and print debugging messages to stderr
//#define XM_DEBUG
// Defined for big endian systems. Teensy is little endian
//#define XM_BIG_ENDIAN
// Use teensy stdout func to write to serial. If this is not defined then
// the XM library will write to stdout instead.
#define XM_HAS_OWN_STDOUT
// Defensively check XM data for errors/inconsistencies
#define XM_DEFENSIVE
// Use linear interpolation (CPU hungry)
#define XM_LINEAR_INTERPOLATION
// Enable ramping (smooth volume/panning transitions, CPU hungry)
#define XM_RAMPING
// Store module, instrument and sample names in context
//#define XM_STRINGS
// Use delta-encoded samples in libxmize format. Important to leave this
// undefined for use with xm_player for teensy.
//#define XM_LIBXMIZE_DELTA_SAMPLES
/** Create a XM context.
*
* @param moddata the contents of the module
* @param rate play rate in Hz, recommended value of 48000
*
* @returns 0 on success
* @returns 1 if module data is not sane
* @returns 2 if memory allocation failed
*
* @deprecated This function is unsafe!
* @see xm_create_context_safe()
*/
int xm_create_context(xm_context_t**, const char* moddata, uint32_t rate);
/** Create a XM context.
*
* @param moddata the contents of the module
* @param moddata_length the length of the contents of the module, in bytes
* @param rate play rate in Hz, recommended value of 48000
*
* @returns 0 on success
* @returns 1 if module data is not sane
* @returns 2 if memory allocation failed
*/
int xm_create_context_safe(xm_context_t**, const char* moddata, size_t moddata_length, uint32_t rate);
/** Create a XM context.
*
* This function will produce smaller code size compared to
* xm_create_context(), but requires converting the .xm file to a
* non-portable format beforehand.
*
* This function doesn't do any kind of error checking.
*
* @see xm_create_context()
*/
void xm_create_context_from_libxmize(xm_context_t**, const char* libxmizeddata, uint32_t rate);
/** Create an XM context with some data remaining in libxmized.
*
* This function will produce smaller code size compared to
* xm_create_context(), but requires converting the .xm file to a
* non-portable format beforehand.
*
* This function doesn't do any kind of error checking. Ensure that the
* libxmized data was created WITHOUT delta encoding.
*
* @param libxmized: the data generated by libxmize, must be
* readadable as long as the context is active.
*
* @see xm_create_context()
*/
void xm_create_shared_context_from_libxmize(xm_context_t** ctxp, const char* libxmized, uint32_t rate);
/** Free a XM context created by xm_create_context(). */
void xm_free_context(xm_context_t*);
/** Convert xm module to libxmlized version
*
* Convert xm module to libxmlized version and output as a byte array to serial. This is an
* 'unwrapped' version of the module that can be stored in readonly memory.
**/
void xm_libxmize( const char* moddata, uint32_t moddata_size );
/** Play the module and put the sound samples in an output buffer.
*
* @param output buffer of 2*numsamples elements
* @param numsamples number of samples to generate
*/
void xm_generate_samples(xm_context_t*, float* output, size_t numsamples);
/** Set the maximum number of times a module can loop. After the
* specified number of loops, calls to xm_generate_samples will only
* generate silence. You can control the current number of loops with
* xm_get_loop_count().
*
* @param loopcnt maximum number of loops. Use 0 to loop
* indefinitely. */
void xm_set_max_loop_count(xm_context_t*, uint8_t loopcnt);
/** Get the loop count of the currently playing module. This value is
* 0 when the module is still playing, 1 when the module has looped
* once, etc. */
uint8_t xm_get_loop_count(xm_context_t*);
/** Seek to a specific position in a module.
*
* WARNING, WITH BIG LETTERS: seeking modules is broken by design,
* don't expect miracles.
*/
void xm_seek(xm_context_t*, uint8_t pot, uint8_t row, uint16_t tick);
/** Mute or unmute a channel.
*
* @note Channel numbers go from 1 to xm_get_number_of_channels(...).
*
* @return whether the channel was muted.
*/
bool xm_mute_channel(xm_context_t*, uint16_t, bool);
/** Mute or unmute an instrument.
*
* @note Instrument numbers go from 1 to
* xm_get_number_of_instruments(...).
*
* @return whether the instrument was muted.
*/
bool xm_mute_instrument(xm_context_t*, uint16_t, bool);
/** Get the module name as a NUL-terminated string. */
const char* xm_get_module_name(xm_context_t*);
/** Get the tracker name as a NUL-terminated string. */
const char* xm_get_tracker_name(xm_context_t*);
/** Get the number of channels. */
uint16_t xm_get_number_of_channels(xm_context_t*);
/** Get the module length (in patterns). */
uint16_t xm_get_module_length(xm_context_t*);
/** Get the number of patterns. */
uint16_t xm_get_number_of_patterns(xm_context_t*);
/** Get the number of rows of a pattern.
*
* @note Pattern numbers go from 0 to
* xm_get_number_of_patterns(...)-1.
*/
uint16_t xm_get_number_of_rows(xm_context_t*, uint16_t);
/** Get the number of instruments. */
uint16_t xm_get_number_of_instruments(xm_context_t*);
/** Get the number of samples of an instrument.
*
* @note Instrument numbers go from 1 to
* xm_get_number_of_instruments(...).
*/
uint16_t xm_get_number_of_samples(xm_context_t*, uint16_t);
/** Get the internal buffer for a given sample waveform.
*
* This buffer can be read from or written to, at any time, but the
* length cannot change. The buffer must be cast to (int8_t*) or
* (int16_t*) depending on the sample type.
*
* @note Instrument numbers go from 1 to
* xm_get_number_of_instruments(...).
*
* @note Sample numbers go from 0 to
* xm_get_nubmer_of_samples(...,instr)-1.
*/
void* xm_get_sample_waveform(xm_context_t*, uint16_t instr, uint16_t sample, size_t* length, uint8_t* bits);
/** Get the current module speed.
*
* @param bpm will receive the current BPM
* @param tempo will receive the current tempo (ticks per line)
*/
void xm_get_playing_speed(xm_context_t*, uint16_t* bpm, uint16_t* tempo);
/** Get the current position in the module being played.
*
* @param pattern_index if not NULL, will receive the current pattern
* index in the POT (pattern order table)
*
* @param pattern if not NULL, will receive the current pattern number
*
* @param row if not NULL, will receive the current row
*
* @param samples if not NULL, will receive the total number of
* generated samples (divide by sample rate to get seconds of
* generated audio)
*/
void xm_get_position(xm_context_t*, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples);
/** Get the latest time (in number of generated samples) when a
* particular instrument was triggered in any channel.
*
* @note Instrument numbers go from 1 to
* xm_get_number_of_instruments(...).
*/
uint64_t xm_get_latest_trigger_of_instrument(xm_context_t*, uint16_t);
/** Get the latest time (in number of generated samples) when a
* particular sample was triggered in any channel.
*
* @note Instrument numbers go from 1 to
* xm_get_number_of_instruments(...).
*
* @note Sample numbers go from 0 to
* xm_get_nubmer_of_samples(...,instr)-1.
*/
uint64_t xm_get_latest_trigger_of_sample(xm_context_t*, uint16_t instr, uint16_t sample);
/** Get the latest time (in number of generated samples) when any
* instrument was triggered in a given channel.
*
* @note Channel numbers go from 1 to xm_get_number_of_channels(...).
*/
uint64_t xm_get_latest_trigger_of_channel(xm_context_t*, uint16_t);
/** Checks whether a channel is active (ie: is playing something).
*
* @note Channel numbers go from 1 to xm_get_number_of_channels(...).
*/
bool xm_is_channel_active(xm_context_t*, uint16_t);
/** Get the instrument number currently playing in a channel.
*
* @returns instrument number, or 0 if channel is not active.
*
* @note Channel numbers go from 1 to xm_get_number_of_channels(...).
*
* @note Instrument numbers go from 1 to
* xm_get_number_of_instruments(...).
*/
uint16_t xm_get_instrument_of_channel(xm_context_t*, uint16_t);
/** Get the frequency of the sample currently playing in a channel.
*
* @returns a frequency in Hz. If the channel is not active, return
* value is undefined.
*
* @note Channel numbers go from 1 to xm_get_number_of_channels(...).
*/
float xm_get_frequency_of_channel(xm_context_t*, uint16_t);
/** Get the volume of the sample currently playing in a channel. This
* takes into account envelopes, etc.
*
* @returns a volume between 0 or 1. If the channel is not active,
* return value is undefined.
*
* @note Channel numbers go from 1 to xm_get_number_of_channels(...).
*/
float xm_get_volume_of_channel(xm_context_t*, uint16_t);
/** Get the panning of the sample currently playing in a channel. This
* takes into account envelopes, etc.
*
* @returns a panning between 0 (L) and 1 (R). If the channel is not
* active, return value is undefined.
*
* @note Channel numbers go from 1 to xm_get_number_of_channels(...).
*/
float xm_get_panning_of_channel(xm_context_t*, uint16_t);
#endif