mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-28 03:10:24 -04:00
test_render_samples_api.c was added to test the api. bridge.go was modified to reflect that there is no need to check for row manually; su_render_samples already returns the information if a row has ended.
146 lines
4.8 KiB
C
146 lines
4.8 KiB
C
#ifndef _SOINTU_H
|
|
#define _SOINTU_H
|
|
|
|
#pragma pack(push,4) // this should be fine for both Go and assembly
|
|
typedef struct Unit {
|
|
float State[8];
|
|
float Ports[8];
|
|
} Unit;
|
|
|
|
typedef struct Voice {
|
|
int Note;
|
|
int Release;
|
|
float Inputs[8];
|
|
float Reserved[6];
|
|
struct Unit Units[63];
|
|
} Voice;
|
|
|
|
typedef struct Synth {
|
|
unsigned char Curvoices[32];
|
|
float Left;
|
|
float Right;
|
|
float Aux[6];
|
|
struct Voice Voices[32];
|
|
} Synth;
|
|
|
|
typedef struct DelayWorkspace {
|
|
float Buffer[65536];
|
|
float Dcin;
|
|
float Dcout;
|
|
float Filtstate;
|
|
} DelayWorkspace;
|
|
|
|
typedef struct SynthState {
|
|
struct Synth Synth;
|
|
struct DelayWorkspace Delaywrks[64]; // let's keep this as 64 for now, so the delays take 16 meg. If that's too little or too much, we can change this in future.
|
|
unsigned char Commands[32 * 64];
|
|
unsigned char Values[32 * 64 * 8];
|
|
unsigned int Polyphony;
|
|
unsigned int NumVoices;
|
|
unsigned int RandSeed;
|
|
unsigned int GlobalTick;
|
|
unsigned int RowTick;
|
|
unsigned int SamplesPerRow; // nominal value, actual rows could be more or less due to speed modulation
|
|
} SynthState;
|
|
#pragma pack(pop)
|
|
|
|
#if UINTPTR_MAX == 0xffffffff // are we 32-bit?
|
|
#if defined(__clang__) || defined(__GNUC__)
|
|
#define CALLCONV __attribute__ ((stdcall))
|
|
#elif defined(_WIN32)
|
|
#define CALLCONV __stdcall // on 32-bit platforms, we just use stdcall, as all know it
|
|
#endif
|
|
#else // 64-bit
|
|
#define CALLCONV // the asm will use honor honor correct x64 ABI on all 64-bit platforms
|
|
#endif
|
|
|
|
#ifdef INCLUDE_GMDLS
|
|
extern void CALLCONV su_load_gmdls(void);
|
|
#endif
|
|
|
|
// su_render_samples(SynthState* synthState, int maxSamples, float* buffer):
|
|
// Renders at most maxsamples to the buffer, using and modifying the
|
|
// synthesizer state in synthState.
|
|
//
|
|
// Parameters:
|
|
// synthState pointer to current synthState. RandSeed should be > 0 e.g. 1
|
|
// Also synthState->SamplesPerRow cannot be 0 or nothing will be
|
|
// rendered; either set it to INT32_MAX to always render full
|
|
// buffer, or something like SAMPLE_RATE * 60 / (BPM * 4) for
|
|
// having 4 rows per beat.
|
|
// maxSamples maximum number of samples to be rendered. buffer should
|
|
// have a length of 2 * maxsamples as the audio is stereo.
|
|
// buffer audio sample buffer, L R L R ...
|
|
//
|
|
// Returns:
|
|
// -1 end of row was not reached & buffer full
|
|
// 0 end of row was reached & buffer full (there is space for zero
|
|
// samples in the buffer)
|
|
// n>0 end of row was reached & there is space for n samples in the buffer
|
|
//
|
|
// Beware of infinite loops: with a rowlen of 0; or without resetting rowtick
|
|
// between rows; or with a problematic synth patch e.g. if the speed is
|
|
// modulated to be become infinite, this function might return maxsamples i.e.
|
|
// not render any samples. If you try to call this with your buffer until the
|
|
// whole buffer is filled, you will be stuck in an infinite loop.
|
|
//
|
|
// So a reasonable track player would be something like:
|
|
//
|
|
// function render_buffer(maxsamples,buffer) {
|
|
// remaining = maxsamples
|
|
// for i = 0..MAX_TRIES // limit retries to prevent infinite loop
|
|
// remaining = su_render_samples(synthState,
|
|
// remaining,
|
|
// &buffer[(maxsamples-remaining)*2])
|
|
// if remaining >= 0 // end of row reached
|
|
// song_row++ // advance row
|
|
// retrigger/release voices based on the new row
|
|
// if remaining <= 0 // buffer full
|
|
// return
|
|
// return // could not fill buffer despite MAX_TRIES, something is wrong
|
|
// // audio will come to sudden end
|
|
// }
|
|
extern int CALLCONV su_render_samples(SynthState* synthState, int maxSamples, float* buffer);
|
|
|
|
// Arithmetic opcode ids
|
|
extern const int su_add_id;
|
|
extern const int su_addp_id;
|
|
extern const int su_pop_id;
|
|
extern const int su_loadnote_id;
|
|
extern const int su_mul_id;
|
|
extern const int su_mulp_id;
|
|
extern const int su_push_id;
|
|
extern const int su_xch_id;
|
|
|
|
// Effect opcode ids
|
|
extern const int su_distort_id;
|
|
extern const int su_hold_id;
|
|
extern const int su_crush_id;
|
|
extern const int su_gain_id;
|
|
extern const int su_invgain_id;
|
|
extern const int su_filter_id;
|
|
extern const int su_clip_id;
|
|
extern const int su_pan_id;
|
|
extern const int su_delay_id;
|
|
extern const int su_compres_id;
|
|
|
|
// Flowcontrol opcode ids
|
|
extern const int su_advance_id;
|
|
extern const int su_speed_id;
|
|
|
|
// Sink opcode ids
|
|
extern const int su_out_id;
|
|
extern const int su_outaux_id;
|
|
extern const int su_aux_id;
|
|
extern const int su_send_id;
|
|
|
|
// Source opcode ids
|
|
extern const int su_envelope_id;
|
|
extern const int su_noise_id;
|
|
extern const int su_oscillat_id;
|
|
extern const int su_loadval_id;
|
|
extern const int su_receive_id;
|
|
extern const int su_in_id;
|
|
|
|
#endif // _SOINTU_H
|