// // pdext_sound.h // Playdate Simulator // // Created by Dave Hayden on 10/6/17. // Copyright © 2017 Panic, Inc. All rights reserved. // #ifndef pdext_sound_h #define pdext_sound_h #if TARGET_EXTENSION #define AUDIO_FRAMES_PER_CYCLE 512 typedef enum { kSound8bitMono = 0, kSound8bitStereo = 1, kSound16bitMono = 2, kSound16bitStereo = 3, kSoundADPCMMono = 4, kSoundADPCMStereo = 5 } SoundFormat; #define SoundFormatIsStereo(f) ((f)&1) #define SoundFormatIs16bit(f) ((f)>=kSound16bitMono) static inline uint32_t SoundFormat_bytesPerFrame(SoundFormat fmt) { return (SoundFormatIsStereo(fmt) ? 2 : 1) * (SoundFormatIs16bit(fmt) ? 2 : 1); } #endif typedef float MIDINote; #define NOTE_C4 60 #include static inline float pd_noteToFrequency(MIDINote n) { return 440 * powf(2.0, (n-69)/12.0f); } static inline MIDINote pd_frequencyToNote(float f) { return 12*log2f(f) - 36.376316562f; } // SOUND SOURCES typedef struct SoundSource SoundSource; typedef void sndCallbackProc(SoundSource* c, void* userdata); // SoundSource is the parent class for FilePlayer, SamplePlayer, PDSynth, and DelayLineTap. You can safely cast those objects to a SoundSource* and use these functions: struct playdate_sound_source { void (*setVolume)(SoundSource* c, float lvol, float rvol); void (*getVolume)(SoundSource* c, float* outl, float* outr); int (*isPlaying)(SoundSource* c); void (*setFinishCallback)(SoundSource* c, sndCallbackProc callback, void* userdata); }; typedef struct FilePlayer FilePlayer; // extends SoundSource struct playdate_sound_fileplayer { FilePlayer* (*newPlayer)(void); void (*freePlayer)(FilePlayer* player); int (*loadIntoPlayer)(FilePlayer* player, const char* path); void (*setBufferLength)(FilePlayer* player, float bufferLen); int (*play)(FilePlayer* player, int repeat); int (*isPlaying)(FilePlayer* player); void (*pause)(FilePlayer* player); void (*stop)(FilePlayer* player); void (*setVolume)(FilePlayer* player, float left, float right); void (*getVolume)(FilePlayer* player, float* left, float* right); float (*getLength)(FilePlayer* player); void (*setOffset)(FilePlayer* player, float offset); void (*setRate)(FilePlayer* player, float rate); void (*setLoopRange)(FilePlayer* player, float start, float end); int (*didUnderrun)(FilePlayer* player); void (*setFinishCallback)(FilePlayer* player, sndCallbackProc callback, void* userdata); void (*setLoopCallback)(FilePlayer* player, sndCallbackProc callback, void* userdata); float (*getOffset)(FilePlayer* player); float (*getRate)(FilePlayer* player); void (*setStopOnUnderrun)(FilePlayer* player, int flag); void (*fadeVolume)(FilePlayer* player, float left, float right, int32_t len, sndCallbackProc finishCallback, void* userdata); void (*setMP3StreamSource)(FilePlayer* player, int (*dataSource)(uint8_t* data, int bytes, void* userdata), void* userdata, float bufferLen); }; typedef struct AudioSample AudioSample; typedef struct SamplePlayer SamplePlayer; struct playdate_sound_sample { AudioSample* (*newSampleBuffer)(int byteCount); int (*loadIntoSample)(AudioSample* sample, const char* path); AudioSample* (*load)(const char* path); AudioSample* (*newSampleFromData)(uint8_t* data, SoundFormat format, uint32_t sampleRate, int byteCount, int shouldFreeData); void (*getData)(AudioSample* sample, uint8_t** data, SoundFormat* format, uint32_t* sampleRate, uint32_t* bytelength); void (*freeSample)(AudioSample* sample); float (*getLength)(AudioSample* sample); // 2.4 int (*decompress)(AudioSample* sample); }; struct playdate_sound_sampleplayer // SamplePlayer extends SoundSource { SamplePlayer* (*newPlayer)(void); void (*freePlayer)(SamplePlayer* player); void (*setSample)(SamplePlayer* player, AudioSample* sample); int (*play)(SamplePlayer* player, int repeat, float rate); int (*isPlaying)(SamplePlayer* player); void (*stop)(SamplePlayer* player); void (*setVolume)(SamplePlayer* player, float left, float right); void (*getVolume)(SamplePlayer* player, float* left, float* right); float (*getLength)(SamplePlayer* player); void (*setOffset)(SamplePlayer* player, float offset); void (*setRate)(SamplePlayer* player, float rate); void (*setPlayRange)(SamplePlayer* player, int start, int end); void (*setFinishCallback)(SamplePlayer* player, sndCallbackProc callback, void* userdata); void (*setLoopCallback)(SamplePlayer* player, sndCallbackProc callback, void* userdata); float (*getOffset)(SamplePlayer* player); float (*getRate)(SamplePlayer* player); void (*setPaused)(SamplePlayer* player, int flag); }; // SIGNALS // a PDSynthSignalValue represents a signal that can be used as an input to a modulator. // its PDSynthSignal subclass is used for "active" signals that change their values automatically. PDSynthLFO and PDSynthEnvelope are subclasses of PDSynthSignal. typedef struct PDSynthSignalValue PDSynthSignalValue; typedef struct PDSynthSignal PDSynthSignal; typedef float (*signalStepFunc)(void* userdata, int* ioframes, float* ifval); typedef void (*signalNoteOnFunc)(void* userdata, MIDINote note, float vel, float len); // len = -1 for indefinite typedef void (*signalNoteOffFunc)(void* userdata, int stopped, int offset); // stopped = 0 on note release, = 1 when note actually stops playing; offset is # of frames into the current cycle typedef void (*signalDeallocFunc)(void* userdata); struct playdate_sound_signal { PDSynthSignal* (*newSignal)(signalStepFunc step, signalNoteOnFunc noteOn, signalNoteOffFunc noteOff, signalDeallocFunc dealloc, void* userdata); void (*freeSignal)(PDSynthSignal* signal); float (*getValue)(PDSynthSignal* signal); void (*setValueScale)(PDSynthSignal* signal, float scale); void (*setValueOffset)(PDSynthSignal* signal, float offset); // 2.6 PDSynthSignal* (*newSignalForValue)(PDSynthSignalValue* value); }; #if TARGET_EXTENSION typedef enum { kLFOTypeSquare, kLFOTypeTriangle, kLFOTypeSine, kLFOTypeSampleAndHold, kLFOTypeSawtoothUp, kLFOTypeSawtoothDown, kLFOTypeArpeggiator, kLFOTypeFunction } LFOType; #endif typedef struct PDSynthLFO PDSynthLFO; // inherits from SynthSignal struct playdate_sound_lfo { PDSynthLFO* (*newLFO)(LFOType type); void (*freeLFO)(PDSynthLFO* lfo); void (*setType)(PDSynthLFO* lfo, LFOType type); void (*setRate)(PDSynthLFO* lfo, float rate); void (*setPhase)(PDSynthLFO* lfo, float phase); void (*setCenter)(PDSynthLFO* lfo, float center); void (*setDepth)(PDSynthLFO* lfo, float depth); void (*setArpeggiation)(PDSynthLFO* lfo, int nSteps, float* steps); void (*setFunction)(PDSynthLFO* lfo, float (*lfoFunc)(PDSynthLFO* lfo, void* userdata), void* userdata, int interpolate); void (*setDelay)(PDSynthLFO* lfo, float holdoff, float ramptime); void (*setRetrigger)(PDSynthLFO* lfo, int flag); float (*getValue)(PDSynthLFO* lfo); // 1.10 void (*setGlobal)(PDSynthLFO* lfo, int global); // 2.2 void (*setStartPhase)(PDSynthLFO* lfo, float phase); }; typedef struct PDSynthEnvelope PDSynthEnvelope; // inherits from SynthSignal struct playdate_sound_envelope { PDSynthEnvelope* (*newEnvelope)(float attack, float decay, float sustain, float release); void (*freeEnvelope)(PDSynthEnvelope* env); void (*setAttack)(PDSynthEnvelope* env, float attack); void (*setDecay)(PDSynthEnvelope* env, float decay); void (*setSustain)(PDSynthEnvelope* env, float sustain); void (*setRelease)(PDSynthEnvelope* env, float release); void (*setLegato)(PDSynthEnvelope* env, int flag); void (*setRetrigger)(PDSynthEnvelope* lfo, int flag); float (*getValue)(PDSynthEnvelope* env); // 1.13 void (*setCurvature)(PDSynthEnvelope* env, float amount); void (*setVelocitySensitivity)(PDSynthEnvelope* env, float velsens); void (*setRateScaling)(PDSynthEnvelope* env, float scaling, MIDINote start, MIDINote end); }; // SYNTHS #if TARGET_EXTENSION typedef enum { kWaveformSquare, kWaveformTriangle, kWaveformSine, kWaveformNoise, kWaveformSawtooth, kWaveformPOPhase, kWaveformPODigital, kWaveformPOVosim } SoundWaveform; #endif // generator render callback // samples are in Q8.24 format. left is either the left channel or the single mono channel, // right is non-NULL only if the stereo flag was set in the setGenerator() call. // nsamples is at most 256 but may be shorter // rate is Q0.32 per-frame phase step, drate is per-frame rate step (i.e., do rate += drate every frame) // return value is the number of sample frames rendered typedef int (*synthRenderFunc)(void* userdata, int32_t* left, int32_t* right, int nsamples, uint32_t rate, int32_t drate); // generator event callbacks typedef void (*synthNoteOnFunc)(void* userdata, MIDINote note, float velocity, float len); // len == -1 if indefinite typedef void (*synthReleaseFunc)(void* userdata, int stop); typedef int (*synthSetParameterFunc)(void* userdata, int parameter, float value); typedef void (*synthDeallocFunc)(void* userdata); typedef void* (*synthCopyUserdata)(void* userdata); typedef struct PDSynth PDSynth; struct playdate_sound_synth // PDSynth extends SoundSource { PDSynth* (*newSynth)(void); void (*freeSynth)(PDSynth* synth); void (*setWaveform)(PDSynth* synth, SoundWaveform wave); void (*setGenerator_deprecated)(PDSynth* synth, int stereo, synthRenderFunc render, synthNoteOnFunc noteOn, synthReleaseFunc release, synthSetParameterFunc setparam, synthDeallocFunc dealloc, void* userdata); void (*setSample)(PDSynth* synth, AudioSample* sample, uint32_t sustainStart, uint32_t sustainEnd); void (*setAttackTime)(PDSynth* synth, float attack); void (*setDecayTime)(PDSynth* synth, float decay); void (*setSustainLevel)(PDSynth* synth, float sustain); void (*setReleaseTime)(PDSynth* synth, float release); void (*setTranspose)(PDSynth* synth, float halfSteps); void (*setFrequencyModulator)(PDSynth* synth, PDSynthSignalValue* mod); PDSynthSignalValue* (*getFrequencyModulator)(PDSynth* synth); void (*setAmplitudeModulator)(PDSynth* synth, PDSynthSignalValue* mod); PDSynthSignalValue* (*getAmplitudeModulator)(PDSynth* synth); int (*getParameterCount)(PDSynth* synth); int (*setParameter)(PDSynth* synth, int parameter, float value); void (*setParameterModulator)(PDSynth* synth, int parameter, PDSynthSignalValue* mod); PDSynthSignalValue* (*getParameterModulator)(PDSynth* synth, int parameter); void (*playNote)(PDSynth* synth, float freq, float vel, float len, uint32_t when); // len == -1 for indefinite void (*playMIDINote)(PDSynth* synth, MIDINote note, float vel, float len, uint32_t when); // len == -1 for indefinite void (*noteOff)(PDSynth* synth, uint32_t when); // move to release part of envelope void (*stop)(PDSynth* synth); // stop immediately void (*setVolume)(PDSynth* synth, float left, float right); void (*getVolume)(PDSynth* synth, float* left, float* right); int (*isPlaying)(PDSynth* synth); // 1.13 PDSynthEnvelope* (*getEnvelope)(PDSynth* synth); // synth keeps ownership--don't free this! // 2.2 int (*setWavetable)(PDSynth* synth, AudioSample* sample, int log2size, int columns, int rows); // 2.4 void (*setGenerator)(PDSynth* synth, int stereo, synthRenderFunc render, synthNoteOnFunc noteOn, synthReleaseFunc release, synthSetParameterFunc setparam, synthDeallocFunc dealloc, synthCopyUserdata copyUserdata, void* userdata); PDSynth* (*copy)(PDSynth* synth); // 2.6 void (*clearEnvelope)(PDSynth* synth); }; // SEQUENCES // a ControlSignal is a PDSynthSignal with values specified on a timeline typedef struct ControlSignal ControlSignal; struct playdate_control_signal { ControlSignal* (*newSignal)(void); void (*freeSignal)(ControlSignal* signal); void (*clearEvents)(ControlSignal* control); void (*addEvent)(ControlSignal* control, int step, float value, int interpolate); void (*removeEvent)(ControlSignal* control, int step); int (*getMIDIControllerNumber)(ControlSignal* control); }; // a PDSynthInstrument is a bank of voices for playing a sequence track typedef struct PDSynthInstrument PDSynthInstrument; struct playdate_sound_instrument { PDSynthInstrument* (*newInstrument)(void); void (*freeInstrument)(PDSynthInstrument* inst); int (*addVoice)(PDSynthInstrument* inst, PDSynth* synth, MIDINote rangeStart, MIDINote rangeEnd, float transpose); PDSynth* (*playNote)(PDSynthInstrument* inst, float frequency, float vel, float len, uint32_t when); PDSynth* (*playMIDINote)(PDSynthInstrument* inst, MIDINote note, float vel, float len, uint32_t when); void (*setPitchBend)(PDSynthInstrument* inst, float bend); void (*setPitchBendRange)(PDSynthInstrument* inst, float halfSteps); void (*setTranspose)(PDSynthInstrument* inst, float halfSteps); void (*noteOff)(PDSynthInstrument* inst, MIDINote note, uint32_t when); void (*allNotesOff)(PDSynthInstrument* inst, uint32_t when); void (*setVolume)(PDSynthInstrument* inst, float left, float right); void (*getVolume)(PDSynthInstrument* inst, float* left, float* right); int (*activeVoiceCount)(PDSynthInstrument* inst); }; // a SequenceTrack contains notes for an instrument to play typedef struct SequenceTrack SequenceTrack; struct playdate_sound_track { SequenceTrack* (*newTrack)(void); void (*freeTrack)(SequenceTrack* track); void (*setInstrument)(SequenceTrack* track, PDSynthInstrument* inst); PDSynthInstrument* (*getInstrument)(SequenceTrack* track); void (*addNoteEvent)(SequenceTrack* track, uint32_t step, uint32_t len, MIDINote note, float velocity); void (*removeNoteEvent)(SequenceTrack* track, uint32_t step, MIDINote note); void (*clearNotes)(SequenceTrack* track); int (*getControlSignalCount)(SequenceTrack* track); ControlSignal* (*getControlSignal)(SequenceTrack* track, int idx); void (*clearControlEvents)(SequenceTrack* track); int (*getPolyphony)(SequenceTrack* track); int (*activeVoiceCount)(SequenceTrack* track); void (*setMuted)(SequenceTrack* track, int mute); // 1.1 uint32_t (*getLength)(SequenceTrack* track); // in steps, includes full last note int (*getIndexForStep)(SequenceTrack* track, uint32_t step); int (*getNoteAtIndex)(SequenceTrack* track, int index, uint32_t* outStep, uint32_t* outLen, MIDINote* outNote, float* outVelocity); // 1.10 ControlSignal* (*getSignalForController)(SequenceTrack* track, int controller, int create); }; // and a SoundSequence is a collection of tracks, along with control info like tempo and loops typedef struct SoundSequence SoundSequence; typedef void (*SequenceFinishedCallback)(SoundSequence* seq, void* userdata); struct playdate_sound_sequence { SoundSequence* (*newSequence)(void); void (*freeSequence)(SoundSequence* sequence); int (*loadMIDIFile)(SoundSequence* seq, const char* path); uint32_t (*getTime)(SoundSequence* seq); void (*setTime)(SoundSequence* seq, uint32_t time); void (*setLoops)(SoundSequence* seq, int loopstart, int loopend, int loops); int (*getTempo_deprecated)(SoundSequence* seq); void (*setTempo)(SoundSequence* seq, float stepsPerSecond); int (*getTrackCount)(SoundSequence* seq); SequenceTrack* (*addTrack)(SoundSequence* seq); SequenceTrack* (*getTrackAtIndex)(SoundSequence* seq, unsigned int track); void (*setTrackAtIndex)(SoundSequence* seq, SequenceTrack* track, unsigned int idx); void (*allNotesOff)(SoundSequence* seq); // 1.1 int (*isPlaying)(SoundSequence* seq); uint32_t (*getLength)(SoundSequence* seq); // in steps, includes full last note void (*play)(SoundSequence* seq, SequenceFinishedCallback finishCallback, void* userdata); void (*stop)(SoundSequence* seq); int (*getCurrentStep)(SoundSequence* seq, int* timeOffset); void (*setCurrentStep)(SoundSequence* seq, int step, int timeOffset, int playNotes); // 2.5 float (*getTempo)(SoundSequence* seq); }; // EFFECTS // A SoundEffect processes the output of a channel's SoundSources typedef struct TwoPoleFilter TwoPoleFilter; #if TARGET_EXTENSION typedef enum { kFilterTypeLowPass, kFilterTypeHighPass, kFilterTypeBandPass, kFilterTypeNotch, kFilterTypePEQ, kFilterTypeLowShelf, kFilterTypeHighShelf } TwoPoleFilterType; #endif struct playdate_sound_effect_twopolefilter { TwoPoleFilter* (*newFilter)(void); void (*freeFilter)(TwoPoleFilter* filter); void (*setType)(TwoPoleFilter* filter, TwoPoleFilterType type); void (*setFrequency)(TwoPoleFilter* filter, float frequency); void (*setFrequencyModulator)(TwoPoleFilter* filter, PDSynthSignalValue* signal); PDSynthSignalValue* (*getFrequencyModulator)(TwoPoleFilter* filter); void (*setGain)(TwoPoleFilter* filter, float gain); void (*setResonance)(TwoPoleFilter* filter, float resonance); void (*setResonanceModulator)(TwoPoleFilter* filter, PDSynthSignalValue* signal); PDSynthSignalValue* (*getResonanceModulator)(TwoPoleFilter* filter); }; typedef struct OnePoleFilter OnePoleFilter; struct playdate_sound_effect_onepolefilter { OnePoleFilter* (*newFilter)(void); void (*freeFilter)(OnePoleFilter* filter); void (*setParameter)(OnePoleFilter* filter, float parameter); void (*setParameterModulator)(OnePoleFilter* filter, PDSynthSignalValue* signal); PDSynthSignalValue* (*getParameterModulator)(OnePoleFilter* filter); }; typedef struct BitCrusher BitCrusher; struct playdate_sound_effect_bitcrusher { BitCrusher* (*newBitCrusher)(void); void (*freeBitCrusher)(BitCrusher* filter); void (*setAmount)(BitCrusher* filter, float amount); void (*setAmountModulator)(BitCrusher* filter, PDSynthSignalValue* signal); PDSynthSignalValue* (*getAmountModulator)(BitCrusher* filter); void (*setUndersampling)(BitCrusher* filter, float undersampling); void (*setUndersampleModulator)(BitCrusher* filter, PDSynthSignalValue* signal); PDSynthSignalValue* (*getUndersampleModulator)(BitCrusher* filter); }; typedef struct RingModulator RingModulator; struct playdate_sound_effect_ringmodulator { RingModulator* (*newRingmod)(void); void (*freeRingmod)(RingModulator* filter); void (*setFrequency)(RingModulator* filter, float frequency); void (*setFrequencyModulator)(RingModulator* filter, PDSynthSignalValue* signal); PDSynthSignalValue* (*getFrequencyModulator)(RingModulator* filter); }; typedef struct DelayLine DelayLine; typedef struct DelayLineTap DelayLineTap; struct playdate_sound_effect_delayline { DelayLine* (*newDelayLine)(int length, int stereo); void (*freeDelayLine)(DelayLine* filter); void (*setLength)(DelayLine* d, int frames); void (*setFeedback)(DelayLine* d, float fb); DelayLineTap* (*addTap)(DelayLine* d, int delay); // note that DelayLineTap is a SoundSource, not a SoundEffect void (*freeTap)(DelayLineTap* tap); void (*setTapDelay)(DelayLineTap* t, int frames); void (*setTapDelayModulator)(DelayLineTap* t, PDSynthSignalValue* mod); PDSynthSignalValue* (*getTapDelayModulator)(DelayLineTap* t); void (*setTapChannelsFlipped)(DelayLineTap* t, int flip); }; typedef struct Overdrive Overdrive; struct playdate_sound_effect_overdrive { Overdrive* (*newOverdrive)(void); void (*freeOverdrive)(Overdrive* filter); void (*setGain)(Overdrive* o, float gain); void (*setLimit)(Overdrive* o, float limit); void (*setLimitModulator)(Overdrive* o, PDSynthSignalValue* mod); PDSynthSignalValue* (*getLimitModulator)(Overdrive* o); void (*setOffset)(Overdrive* o, float offset); void (*setOffsetModulator)(Overdrive* o, PDSynthSignalValue* mod); PDSynthSignalValue* (*getOffsetModulator)(Overdrive* o); }; typedef struct SoundEffect SoundEffect; typedef int effectProc(SoundEffect* e, int32_t* left, int32_t* right, int nsamples, int bufactive); // samples are in signed q8.24 format struct playdate_sound_effect { SoundEffect* (*newEffect)(effectProc* proc, void* userdata); void (*freeEffect)(SoundEffect* effect); void (*setMix)(SoundEffect* effect, float level); void (*setMixModulator)(SoundEffect* effect, PDSynthSignalValue* signal); PDSynthSignalValue* (*getMixModulator)(SoundEffect* effect); void (*setUserdata)(SoundEffect* effect, void* userdata); void* (*getUserdata)(SoundEffect* effect); const struct playdate_sound_effect_twopolefilter* twopolefilter; const struct playdate_sound_effect_onepolefilter* onepolefilter; const struct playdate_sound_effect_bitcrusher* bitcrusher; const struct playdate_sound_effect_ringmodulator* ringmodulator; const struct playdate_sound_effect_delayline* delayline; const struct playdate_sound_effect_overdrive* overdrive; }; // A SoundChannel contains SoundSources and SoundEffects typedef struct SoundChannel SoundChannel; typedef int AudioSourceFunction(void* context, int16_t* left, int16_t* right, int len); // len is # of samples in each buffer, function should return 1 if it produced output struct playdate_sound_channel { SoundChannel* (*newChannel)(void); void (*freeChannel)(SoundChannel* channel); int (*addSource)(SoundChannel* channel, SoundSource* source); int (*removeSource)(SoundChannel* channel, SoundSource* source); SoundSource* (*addCallbackSource)(SoundChannel* channel, AudioSourceFunction* callback, void* context, int stereo); int (*addEffect)(SoundChannel* channel, SoundEffect* effect); int (*removeEffect)(SoundChannel* channel, SoundEffect* effect); void (*setVolume)(SoundChannel* channel, float volume); float (*getVolume)(SoundChannel* channel); void (*setVolumeModulator)(SoundChannel* channel, PDSynthSignalValue* mod); PDSynthSignalValue* (*getVolumeModulator)(SoundChannel* channel); void (*setPan)(SoundChannel* channel, float pan); void (*setPanModulator)(SoundChannel* channel, PDSynthSignalValue* mod); PDSynthSignalValue* (*getPanModulator)(SoundChannel* channel); PDSynthSignalValue* (*getDryLevelSignal)(SoundChannel* channel); PDSynthSignalValue* (*getWetLevelSignal)(SoundChannel* channel); }; typedef int RecordCallback(void *context, int16_t* buffer, int length); // data is mono enum MicSource { kMicInputAutodetect = 0, kMicInputInternal = 1, kMicInputHeadset = 2 }; struct playdate_sound { const struct playdate_sound_channel* channel; const struct playdate_sound_fileplayer* fileplayer; const struct playdate_sound_sample* sample; const struct playdate_sound_sampleplayer* sampleplayer; const struct playdate_sound_synth* synth; const struct playdate_sound_sequence* sequence; const struct playdate_sound_effect* effect; const struct playdate_sound_lfo* lfo; const struct playdate_sound_envelope* envelope; const struct playdate_sound_source* source; const struct playdate_control_signal* controlsignal; const struct playdate_sound_track* track; const struct playdate_sound_instrument* instrument; uint32_t (*getCurrentTime)(void); SoundSource* (*addSource)(AudioSourceFunction* callback, void* context, int stereo); SoundChannel* (*getDefaultChannel)(void); int (*addChannel)(SoundChannel* channel); int (*removeChannel)(SoundChannel* channel); int (*setMicCallback)(RecordCallback* callback, void* context, enum MicSource source); void (*getHeadphoneState)(int* headphone, int* headsetmic, void (*changeCallback)(int headphone, int mic)); void (*setOutputsActive)(int headphone, int speaker); // 1.5 int (*removeSource)(SoundSource* source); // 1.12 const struct playdate_sound_signal* signal; // 2.2 const char* (*getError)(void); }; #endif /* pdext_sound_h */