#include <xm.h>
#include <stdbool.h>
#include <math.h>
#include <string.h>
#include <inttypes.h>
#if XM_DEBUG
#include <stdio.h>
#define DEBUG(fmt, ...) do { \
fprintf(stderr, "%s(): " fmt "\n", __func__, __VA_ARGS__); \
fflush(stderr); \
} while(0)
#else
#define DEBUG(...)
#endif
#if XM_BIG_ENDIAN
#error "Big endian platforms are not yet supported, sorry"
extern int __fail[-1];
#endif
#define SAMPLE_NAME_LENGTH 22
#define INSTRUMENT_HEADER_LENGTH 263
#define INSTRUMENT_NAME_LENGTH 22
#define MODULE_NAME_LENGTH 20
#define TRACKER_NAME_LENGTH 20
#define PATTERN_ORDER_TABLE_LENGTH 256
#define NUM_NOTES 96
#define NUM_ENVELOPE_POINTS 12
#define MAX_NUM_ROWS 256
#define DEFAULT_PATTERN_LENGTH 64
#if XM_RAMPING
#define XM_SAMPLE_RAMPING_POINTS 0x20
#endif
enum xm_waveform_type_e {
XM_SINE_WAVEFORM = 0,
XM_RAMP_DOWN_WAVEFORM = 1,
XM_SQUARE_WAVEFORM = 2,
XM_RANDOM_WAVEFORM = 3,
XM_RAMP_UP_WAVEFORM = 4,
};
typedef enum xm_waveform_type_e xm_waveform_type_t;
enum xm_loop_type_e {
XM_NO_LOOP,
XM_FORWARD_LOOP,
XM_PING_PONG_LOOP,
};
typedef enum xm_loop_type_e xm_loop_type_t;
enum xm_frequency_type_e {
XM_LINEAR_FREQUENCIES,
XM_AMIGA_FREQUENCIES,
};
typedef enum xm_frequency_type_e xm_frequency_type_t;
struct xm_envelope_point_s {
uint16_t frame;
uint16_t value;
};
typedef struct xm_envelope_point_s xm_envelope_point_t;
struct xm_envelope_s {
xm_envelope_point_t points[NUM_ENVELOPE_POINTS];
uint8_t num_points;
uint8_t sustain_point;
uint8_t loop_start_point;
uint8_t loop_end_point;
bool enabled;
bool sustain_enabled;
bool loop_enabled;
};
typedef struct xm_envelope_s xm_envelope_t;
struct xm_sample_s {
#if XM_STRINGS
char name[SAMPLE_NAME_LENGTH + 1];
#endif
uint8_t bits;
uint32_t length;
uint32_t loop_start;
uint32_t loop_length;
uint32_t loop_end;
float volume;
int8_t finetune;
xm_loop_type_t loop_type;
float panning;
int8_t relative_note;
uint64_t latest_trigger;
union {
int8_t* data8;
int16_t* data16;
};
};
typedef struct xm_sample_s xm_sample_t;
struct xm_instrument_s {
#if XM_STRINGS
char name[INSTRUMENT_NAME_LENGTH + 1];
#endif
uint16_t num_samples;
uint8_t sample_of_notes[NUM_NOTES];
xm_envelope_t volume_envelope;
xm_envelope_t panning_envelope;
xm_waveform_type_t vibrato_type;
uint8_t vibrato_sweep;
uint8_t vibrato_depth;
uint8_t vibrato_rate;
uint16_t volume_fadeout;
uint64_t latest_trigger;
bool muted;
xm_sample_t* samples;
};
typedef struct xm_instrument_s xm_instrument_t;
struct xm_pattern_slot_s {
uint8_t note;
uint8_t instrument;
uint8_t volume_column;
uint8_t effect_type;
uint8_t effect_param;
};
typedef struct xm_pattern_slot_s xm_pattern_slot_t;
struct xm_pattern_s {
uint16_t num_rows;
xm_pattern_slot_t* slots;
};
typedef struct xm_pattern_s xm_pattern_t;
struct xm_module_s {
#if XM_STRINGS
char name[MODULE_NAME_LENGTH + 1];
char trackername[TRACKER_NAME_LENGTH + 1];
#endif
uint16_t length;
uint16_t restart_position;
uint16_t num_channels;
uint16_t num_patterns;
uint16_t num_instruments;
xm_frequency_type_t frequency_type;
uint8_t pattern_table[PATTERN_ORDER_TABLE_LENGTH];
xm_pattern_t* patterns;
xm_instrument_t* instruments;
};
typedef struct xm_module_s xm_module_t;
struct xm_channel_context_s {
float note;
float orig_note;
xm_instrument_t* instrument;
xm_sample_t* sample;
xm_pattern_slot_t* current;
float sample_position;
float period;
float frequency;
float step;
bool ping;
float volume;
float panning;
uint16_t autovibrato_ticks;
bool sustained;
float fadeout_volume;
float volume_envelope_volume;
float panning_envelope_panning;
uint16_t volume_envelope_frame_count;
uint16_t panning_envelope_frame_count;
float autovibrato_note_offset;
bool arp_in_progress;
uint8_t arp_note_offset;
uint8_t volume_slide_param;
uint8_t fine_volume_slide_param;
uint8_t global_volume_slide_param;
uint8_t panning_slide_param;
uint8_t portamento_up_param;
uint8_t portamento_down_param;
uint8_t fine_portamento_up_param;
uint8_t fine_portamento_down_param;
uint8_t extra_fine_portamento_up_param;
uint8_t extra_fine_portamento_down_param;
uint8_t tone_portamento_param;
float tone_portamento_target_period;
uint8_t multi_retrig_param;
uint8_t note_delay_param;
uint8_t pattern_loop_origin;
uint8_t pattern_loop_count;
bool vibrato_in_progress;
xm_waveform_type_t vibrato_waveform;
bool vibrato_waveform_retrigger;
uint8_t vibrato_param;
uint16_t vibrato_ticks;
float vibrato_note_offset;
xm_waveform_type_t tremolo_waveform;
bool tremolo_waveform_retrigger;
uint8_t tremolo_param;
uint8_t tremolo_ticks;
float tremolo_volume;
uint8_t tremor_param;
bool tremor_on;
uint64_t latest_trigger;
bool muted;
#if XM_RAMPING
float target_volume[2];
unsigned long frame_count;
float end_of_previous_sample[XM_SAMPLE_RAMPING_POINTS];
#endif
float actual_volume[2];
};
typedef struct xm_channel_context_s xm_channel_context_t;
struct xm_context_s {
size_t ctx_size;
xm_module_t module;
uint32_t rate;
uint16_t tempo;
uint16_t bpm;
float global_volume;
float amplification;
#if XM_RAMPING
float volume_ramp;
#endif
uint8_t current_table_index;
uint8_t current_row;
uint16_t current_tick;
float remaining_samples_in_tick;
uint64_t generated_samples;
bool position_jump;
bool pattern_break;
uint8_t jump_dest;
uint8_t jump_row;
uint16_t extra_ticks;
uint8_t* row_loop_count;
uint8_t loop_count;
uint8_t max_loop_count;
xm_channel_context_t* channels;
};
int xm_check_sanity_preload(const char*, size_t);
int xm_check_sanity_postload(xm_context_t*);
size_t xm_get_memory_needed_for_context(const char*, size_t);
char* xm_load_module(xm_context_t*, const char*, size_t, char*);