/* Copyright (c) 2021 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ // See sfxr and bfxr source code license details in sfxrSynth.c #ifndef __sfxrSynth_H__ #define __sfxrSynth_H__ #ifdef __cplusplus extern "C" { #endif #include "gamemath/PCGRandom.h" #include "pcmaudio/PCMAudio.h" #include #include #include #define SFXR_WAVE_TYPE_SQUARE 0 #define SFXR_WAVE_TYPE_SAWTOOTH 1 #define SFXR_WAVE_TYPE_SINE 2 #define SFXR_WAVE_TYPE_NOISE 3 #define SFXR_WAVE_TYPE_TRIANGLE 4 #define SFXR_WAVE_TYPE_COUNT 5 #define BFXR_WAVE_TYPE_PINK 5 #define BFXR_WAVE_TYPE_TAN 6 #define BFXR_WAVE_TYPE_WHISTLE 7 #define BFXR_WAVE_TYPE_BREAKER 8 #define BFXR_WAVE_TYPE_BITNOISE 9 #define BFXR_WAVE_TYPE_HOLO 10 #define BFXR_WAVE_TYPE_BUZZ 11 #define BFXR_WAVE_TYPE_COUNT 11 #define SFXR_SAMPLE_RATE 44100 struct sfxrParams { int32_t wave_type; float p_base_freq; float p_freq_limit; float p_freq_ramp; float p_freq_dramp; float p_duty; float p_duty_ramp; float p_vib_strength; float p_vib_speed; float p_vib_delay; float p_env_attack; float p_env_sustain; float p_env_decay; float p_env_punch; float p_lpf_resonance; float p_lpf_freq; float p_lpf_ramp; float p_hpf_freq; float p_hpf_ramp; float p_pha_offset; float p_pha_ramp; float p_repeat_speed; float p_arp_speed; float p_arp_mod; float master_vol; float sound_vol; // bfxr only float p_compression; float p_harmonics; float p_harmonics_falloff; float p_arp_repeat; float p_arp_speed_2; float p_arp_mod_2; float p_bitcrush; float p_bitcrush_ramp; }; struct sfxrSynthState { bool playing_sample; int phase; double fperiod; double fmaxperiod; double fslide; double fdslide; int period; float square_duty; float square_slide; int env_stage; int env_time; int env_length[3]; float env_vol; float fphase; float fdphase; int iphase; float phaser_buffer[1024]; int ipp; float noise_buffer[32]; float fltp; float fltdp; float fltw; float fltw_d; float fltdmp; float fltphp; float flthp; float flthp_d; float vib_phase; float vib_speed; float vib_amp; int rep_time; int rep_limit; int arp_time; int arp_limit; double arp_mod; }; struct bfxrPinkNumberState { int max_key; int key; int white_values[5]; unsigned int range; pcg_state * pcgState; }; struct bfxrSynthState { bool finished; // If the sound has finished double masterVolume; // masterVolume * masterVolume (for quick calculations) unsigned int waveType; // The type of wave to generate double envelopeVolume; // Current volume of the envelope int envelopeStage; // Current stage of the envelope (attack, sustain, decay, end) double envelopeTime; // Current time through current enelope stage double envelopeLength; // Length of the current envelope stage double envelopeLength0; // Length of the attack stage double envelopeLength1; // Length of the sustain stage double envelopeLength2; // Length of the decay stage double envelopeOverLength0; // 1 / _envelopeLength0 (for quick calculations) double envelopeOverLength1; // 1 / _envelopeLength1 (for quick calculations) double envelopeOverLength2; // 1 / _envelopeLength2 (for quick calculations) double sustainPunch; // The punch factor (louder at begining of sustain) int phase; // Phase through the wave double pos; // Phase expresed as a float from 0-1, used for fast sin approx double period; // Period of the wave double periodTemp; // Period modified by vibrato double maxPeriod; // Maximum period before sound stops (from minFrequency) double slide; // Note slide double deltaSlide; // Change in slide double minFreqency; // Minimum frequency before stopping bool muted; // Whether or not min frequency has been attained int overtones; // Minimum frequency before stopping double overtoneFalloff; // Minimum frequency before stopping double vibratoPhase; // Phase through the vibrato sine wave double vibratoSpeed; // Speed at which the vibrato phase moves double vibratoAmplitude; // Amount to change the period of the wave by at the peak of the vibrato wave double changePeriod; int changePeriodTime; double changeAmount; // Amount to change the note by int changeTime; // Counter for the note change int changeLimit; // Once the time reaches this limit, the note changes bool changeReached; double changeAmount2; // Amount to change the note by int changeTime2; // Counter for the note change int changeLimit2; // Once the time reaches this limit, the note changes bool changeReached2; double squareDuty; // Offset of center switching point in the square wave double dutySweep; // Amount to change the duty by int repeatTime; // Counter for the repeats int repeatLimit; // Once the time reaches this limit, some of the variables are reset bool flanger; // If the flanger is active double flangerOffset; // Phase offset for flanger effect double flangerDeltaOffset; // Change in phase offset int flangerInt; // Integer flanger offset, for bit maths int flangerPos; // Position through the flanger buffer float flangerBuffer[1024]; // Buffer of wave values used to create the out of phase second wave bool filters; // If the filters are active double lpFilterPos; // Adjusted wave position after low-pass filter double lpFilterOldPos; // Previous low-pass wave position double lpFilterDeltaPos; // Change in low-pass wave position, as allowed by the cutoff and damping double lpFilterCutoff; // Cutoff multiplier which adjusts the amount the wave position can move double lpFilterDeltaCutoff; // Speed of the low-pass cutoff multiplier double lpFilterDamping; // Damping muliplier which restricts how fast the wave position can move bool lpFilterOn; // If the low pass filter is active double hpFilterPos; // Adjusted wave position after high-pass filter double hpFilterCutoff; // Cutoff multiplier which adjusts the amount the wave position can move double hpFilterDeltaCutoff; // Speed of the high-pass cutoff multiplier float noiseBuffer[32]; // Buffer of random values used to generate noise float pinkNoiseBuffer[32]; // Buffer of random values used to generate noise float loResNoiseBuffer[32]; // Buffer of random values used to generate noise int oneBitNoiseState; // Buffer containing one-bit periodic noise state. float oneBitNoise; // Current sample of one-bit noise. int buzzState; // Buffer containing 'buzz' periodic noise state. float buzz; // Current sample of 'buzz' noise. struct bfxrPinkNumberState pinkNumber; double bitcrush_freq; // inversely proportional to the number of samples to skip double bitcrush_freq_sweep; // change of the above double bitcrush_phase; // samples when this > 1 double bitcrush_last; // last sample value double compression_factor; pcg_state pcgState; }; struct bfxrMixerTrackData { int id; float onset; float volume; struct sfxrParams synthData; bool reverse; }; struct bfxrTrackList { int id; float volume; unsigned int trackCount; struct bfxrMixerTrackData * tracks; }; void sfxr_ResetParams(struct sfxrParams * params); void sfxr_ResetSample(struct sfxrSynthState * state, struct sfxrParams params, bool restart); void sfxr_SynthSample(struct sfxrSynthState * state, struct sfxrParams params, int length, float * buffer); void bfxr_reset(struct bfxrSynthState * ioState, struct sfxrParams params, bool totalReset); bool bfxr_synthWave(struct bfxrSynthState * state, struct sfxrParams params, unsigned int length, float * buffer); bool readBFXRSoundFile(const char * filePath, struct bfxrTrackList * outTrackList); bool writeBFXRSoundFile(const char * filePath, struct bfxrTrackList * trackList); bool readSfxrXSoundFile(const char * filePath, struct sfxrParams * outParams); bool writeSfxrXSoundFile(const char * filePath, struct sfxrParams * params); size_t getSFXRSoundFrameCount(struct sfxrParams * params); size_t getBFXRSoundFrameCount(struct sfxrParams * params); PCMAudio * createSFXRSoundOutputFromParams(struct sfxrParams * params); PCMAudio * createBFXRSoundOutputFromParams(struct sfxrParams * params); PCMAudio * createBFXRSoundOutputFromTrackList(struct bfxrTrackList * trackList); void freeBFXRTrackList(struct bfxrTrackList * trackList); static inline float sfxrBaseFreqToHertz(float base_freq) { return SFXR_SAMPLE_RATE / (100.0f / (base_freq * base_freq + 0.001f)) * 8.0f; } static inline float sfxrBaseFreqFromHertz(float hertz) { return sqrtf(100.0f / (SFXR_SAMPLE_RATE / hertz * 8.0f) - 0.001f); } static inline float sfxrBaseFreqToOctave(float base_freq) { return log2f(sfxrBaseFreqToHertz(base_freq) / 13.75f); } static inline float sfxrBaseFreqFromOctave(float octave) { return sfxrBaseFreqFromHertz(13.75f * powf(2.0f, octave)); } #ifdef __cplusplus } #endif #endif