// The MIT License (MIT) // // Copyright (C) 2026 Scott Duensing // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // audio.h -- sound library (audio.lib) // // Sound for DVX programs through whatever sound hardware the computer // has. Every program opens its own audio context; any number of // programs play at the same time through one mixer, and everything a // program opened is stopped and released when it ends, however it ends. // // Samples a sound loaded from a WAV or VOC file (or memory, or raw // PCM) and played on voices: volume, pan, pitch, looping, // an end notification. // Tones square, triangle and noise tones of a frequency and length, // made by the mixer (on the PC speaker by its tone generator). // Streams a program's own sound (music, speech) at any rate: it // writes samples, or the library asks for them. // Notes a queue of tones and rests played back to back, each to the // exact sample (melodies; QBasic's PLAY and SOUND). // Volume one master volume for the whole system and one per // context. // FM the FM synthesizer chip (OPL2 / OPL3), when there is one: // two-operator voices shared by every program (tones use // them too), or the whole chip for one program at a time. // MIDI the MIDI port (MPU-401), for one program at a time. // Desktop the sounds DVX plays for its own events (starting, message // sounds boxes, ...), chosen in DVX.INI [sounds]. // // The mixer works in 16-bit integers at the rate the sound device // achieved (22,050 Hz unless DVX.INI [audio] rate says otherwise), // resamples every source with linear interpolation and clips the sum. // It mixes from the device's own interrupt (or the timer service for // devices without one), so sound keeps playing however busy the // programs are. At most the configured voice limit plays at once; // starting one more drops the quietest. // // Square and triangle tones play on a free FM voice when the computer // has an FM chip (DVX.INI [audio] fmTones), else - or when every FM voice // is taken - the mixer makes them. // // Devices come from driver modules (audioDrv.h) found at start-up: // the one named by DVX.INI [audio] driver, else the Sound Blaster // family, the PC speaker and finally the silent null driver, which // keeps programs working on a computer without sound. // // Functions returning int32_t return AUDIO_OK or a voice id (> 0) on // success and a negative AUDIO_ERR_* code on failure (audioErrorText // says what it means). Nothing here may be called from an interrupt. #ifndef AUDIO_LIB_H #define AUDIO_LIB_H #include "dvxApp.h" #include "dvxPrefs.h" #include "dvxTypes.h" #include #include // Volume of a voice, a context or the master: 0 (silent) .. AUDIO_VOLUME_MAX #define AUDIO_VOLUME_MAX 256 // Pan of a voice: AUDIO_PAN_LEFT .. AUDIO_PAN_RIGHT (centre plays at full // volume on both sides; panning turns the other side down) #define AUDIO_PAN_LEFT (-256) #define AUDIO_PAN_CENTER 0 #define AUDIO_PAN_RIGHT 256 // Pitch of a voice as a speed ratio in 1/256ths: AUDIO_PITCH_NORMAL plays // at the recorded speed, twice that an octave higher. #define AUDIO_PITCH_NORMAL 256 #define AUDIO_PITCH_MIN 64 #define AUDIO_PITCH_MAX 1024 // Sample rates a sound, a stream or the device may have (Hz) #define AUDIO_RATE_MIN 4000 #define AUDIO_RATE_MAX 48000 #define AUDIO_RATE_DEFAULT 22050 // Tone frequencies (Hz) #define AUDIO_TONE_MIN_HZ 20 #define AUDIO_TONE_MAX_HZ 20000 // Voices: the most that can exist, and the default limit of voices mixed // at once (DVX.INI [audio] voices, 1..AUDIO_VOICES_MAX) #define AUDIO_VOICES_MAX 32 #define AUDIO_VOICES_DEFAULT 16 // Note queues: the most entries (tones and rests) waiting to start, and // the unit of their frequencies (1/1000 Hz; 0 is a rest) #define AUDIO_NOTES_MAX 256 #define AUDIO_MILLIHZ_PER_HZ 1000 // Stream buffer length (milliseconds of sound) #define AUDIO_STREAM_MS_MIN 20 #define AUDIO_STREAM_MS_DEFAULT 250 #define AUDIO_STREAM_MS_MAX 2000 // Text sizes in AudioInfoT (with the terminating zero) #define AUDIO_NAME_MAX 16 #define AUDIO_DESC_MAX 64 // Results #define AUDIO_OK 0 #define AUDIO_ERR_ARG (-1) // a bad argument #define AUDIO_ERR_NO_MEMORY (-2) // out of memory #define AUDIO_ERR_OPEN (-3) // the file could not be read #define AUDIO_ERR_FORMAT (-4) // not a WAV or VOC file #define AUDIO_ERR_UNSUPPORTED (-5) // compressed or unusual sound data #define AUDIO_ERR_CORRUPT (-6) // damaged or incomplete file #define AUDIO_ERR_NO_VOICE (-7) // voice limit reached, and this sound is the quietest #define AUDIO_ERR_NO_DEVICE (-8) // no sound driver could be started #define AUDIO_ERR_VOICE (-9) // no such voice in this context (ended, or never was) #define AUDIO_ERR_BUSY (-10) // the synthesizer is in use by another program, or not ready #define AUDIO_ERR_NO_SYNTH (-11) // no such synthesizer (no FM chip, no MIDI port) #define AUDIO_ERR_COUNT 12 // AUDIO_OK and the eleven errors // Opaque handles typedef struct AudioCtxT AudioCtxT; typedef struct AudioNotesT AudioNotesT; typedef struct AudioSampleT AudioSampleT; typedef struct AudioStreamT AudioStreamT; // Tone waveforms typedef enum { AUDIO_WAVE_SQUARE = 0, AUDIO_WAVE_TRIANGLE = 1, AUDIO_WAVE_NOISE = 2 } AudioWaveE; // Why a voice ended typedef enum { AUDIO_END_FINISHED = 0, // played to its end (or its tone length) AUDIO_END_STOPPED = 1, // audioVoiceStop, audioStopAll, its sample or stream closed AUDIO_END_DROPPED = 2 // the voice limit dropped it for a louder sound } AudioEndE; // PCM layout: rate in Hz, 8 (unsigned) or 16 (signed, little-endian) // bits, 1 or 2 channels (stereo interleaved left, right). typedef struct { uint32_t rate; uint32_t bits; uint32_t channels; } AudioFormatT; // The sound device in use (audioGetInfo). typedef struct { char driver[AUDIO_NAME_MAX]; // driver name ("sb", "speaker", "null"); "" when none runs char description[AUDIO_DESC_MAX]; // for people, e.g. "Sound Blaster 16 (DSP 4.05)" uint32_t rate; // mixing rate the device achieved (Hz) uint32_t bits; // output bits uint32_t channels; // output channels uint32_t voiceLimit; // voices mixed at once bool running; // a device is playing (some context is open) bool hasDac; // plays sampled sound (else tones only, or nothing) bool hasSynth; // has a hardware music synthesizer bool hasTone; // plays tones on a hardware tone generator } AudioInfoT; // Mixer counters since the device started (audioGetStats). typedef struct { uint32_t renders; // blocks the device asked the mixer for uint32_t frames; // frames mixed uint32_t underruns; // stream frames that were due but not yet written uint32_t clipped; // output samples clipped to the 16-bit range uint32_t dropped; // voices dropped (or refused) by the voice limit uint32_t playing; // voices playing now } AudioStatsT; // A voice of ctx ended. Called from audioPump or the shell's idle time, // never from an interrupt, as the program that owns ctx. typedef void (*AudioEndFnT)(AudioCtxT *ctx, int32_t voice, AudioEndE reason, void *userData); // A pull stream wants up to frames frames in its own format in buf. // Return how many were written (fewer, even 0, is fine: the rest is asked // for later). Called from audioPump or the shell's idle time. typedef uint32_t (*AudioFillFnT)(AudioStreamT *stream, void *buf, uint32_t frames, void *userData); // ============================================================ // Contexts, device and volume // ============================================================ // Open an audio context for the calling program; the first one opened // starts the sound device. NULL when out of memory or when no driver // could be started. Every context is closed for its program when the // program ends. AudioCtxT *audioOpen(void); // Stop every voice of ctx, free its samples and streams and close it; the // last one closed stops the device. NULL is ignored. void audioClose(AudioCtxT *ctx); // Text for an AUDIO_OK / AUDIO_ERR_* code. const char *audioErrorText(int32_t err); // The device in use (running false and driver "" while none is open). void audioGetInfo(AudioInfoT *info); // Mixer counters since the device started. void audioGetStats(AudioStatsT *stats); // Master volume of all sound (0..AUDIO_VOLUME_MAX; DVX.INI [audio] // volume, in percent, sets it when the device starts). int32_t audioGetMasterVolume(void); void audioSetMasterVolume(int32_t volume); // Volume of everything ctx plays (0..AUDIO_VOLUME_MAX, default the // maximum). int32_t audioGetVolume(const AudioCtxT *ctx); void audioSetVolume(AudioCtxT *ctx, int32_t volume); // Call fn when a voice of ctx ends (NULL: no calls). void audioSetEndFn(AudioCtxT *ctx, AudioEndFnT fn, void *userData); // Deliver end notifications and fill pull streams now. The shell does // this in its idle time; a program that keeps the desktop busy every // frame should call it once a frame. void audioPump(void); // Stop every voice of ctx. void audioStopAll(AudioCtxT *ctx); // ============================================================ // Samples and voices // ============================================================ // Load a WAV (PCM, 8 or 16 bits, mono or stereo, any other chunks // skipped) or VOC (8-bit, 16-bit, silence and extended blocks) sound from // a file or from memory. int32_t audioSampleLoad(AudioCtxT *ctx, const char *path, AudioSampleT **out); int32_t audioSampleLoadMem(AudioCtxT *ctx, const void *data, uint32_t size, AudioSampleT **out); // A sample from raw PCM frames in format fmt. int32_t audioSampleCreate(AudioCtxT *ctx, const void *pcm, uint32_t frames, const AudioFormatT *fmt, AudioSampleT **out); // Stop the voices playing it and free it. NULL is ignored. void audioSampleFree(AudioSampleT *sample); // The sample's recorded format and length in frames. void audioSampleInfo(const AudioSampleT *sample, AudioFormatT *fmt, uint32_t *frames); // Play sample on a new voice at volume and pan, from its start, once or // looping until stopped. Returns the voice id. int32_t audioPlay(AudioSampleT *sample, int32_t volume, int32_t pan, bool loop); // Load a sound file and play it; the sample is freed when the voice ends. int32_t audioPlayFile(AudioCtxT *ctx, const char *path, int32_t volume, int32_t pan, bool loop); // Play a tone of hz for ms milliseconds (0: until stopped). int32_t audioTone(AudioCtxT *ctx, AudioWaveE wave, uint32_t hz, int32_t volume, uint32_t ms); // Change or stop a voice of ctx; AUDIO_ERR_VOICE when it is not one // (any more). Pitch changes a sample's or stream's speed (and a tone's // frequency); SetFrequency sets a tone's frequency. int32_t audioVoiceSetFrequency(AudioCtxT *ctx, int32_t voice, uint32_t hz); int32_t audioVoiceSetPan(AudioCtxT *ctx, int32_t voice, int32_t pan); int32_t audioVoiceSetPitch(AudioCtxT *ctx, int32_t voice, int32_t pitch); int32_t audioVoiceSetVolume(AudioCtxT *ctx, int32_t voice, int32_t volume); int32_t audioVoiceStop(AudioCtxT *ctx, int32_t voice); // True while the voice of ctx is still playing. bool audioVoiceIsPlaying(const AudioCtxT *ctx, int32_t voice); // ============================================================ // Streams // ============================================================ // Open a stream of format fmt with a buffer of bufferMs milliseconds (0: // AUDIO_STREAM_MS_DEFAULT). It starts playing at once on its own voice // (silence until samples arrive). With fill, the library asks for // samples whenever the buffer has room; without, the program writes them // with audioStreamWrite. int32_t audioStreamOpen(AudioCtxT *ctx, const AudioFormatT *fmt, uint32_t bufferMs, AudioFillFnT fill, void *userData, AudioStreamT **out); // Stop and free the stream. NULL is ignored. void audioStreamClose(AudioStreamT *stream); // Frames buffered and not yet played, and frames of room left. uint32_t audioStreamQueued(const AudioStreamT *stream); uint32_t audioStreamSpace(const AudioStreamT *stream); // The stream's voice id (for volume, pan and pitch). int32_t audioStreamVoice(const AudioStreamT *stream); // Append up to frames frames in the stream's format; returns how many fit. uint32_t audioStreamWrite(AudioStreamT *stream, const void *pcm, uint32_t frames); // ============================================================ // Note queues // ============================================================ // // Tones and rests played one after the other, each lasting exactly as // long as asked (to the output frame, with no drift over a long tune) as // long as the next is queued before the one before it ends. A queue // plays on its own voice, in the mixer or on the PC speaker's tone // generator (never on the FM chip), and the voice limit never drops it; // it is silent while empty. // A queue of wave tones (square, triangle or noise) at volume // (0..AUDIO_VOLUME_MAX; audioVoiceSetVolume on audioNotesVoice changes it). int32_t audioNotesOpen(AudioCtxT *ctx, AudioWaveE wave, int32_t volume, AudioNotesT **out); // Stop and free the queue. NULL is ignored. void audioNotesClose(AudioNotesT *notes); // Append a tone of milliHz thousandths of a hertz (AUDIO_TONE_MIN_HZ .. // AUDIO_TONE_MAX_HZ, or 0 for a rest) lasting us microseconds. // AUDIO_ERR_BUSY when AUDIO_NOTES_MAX entries are already waiting. int32_t audioNotesAdd(AudioNotesT *notes, uint32_t milliHz, uint32_t us); // Silence the queue now and forget everything in it. void audioNotesClear(AudioNotesT *notes); // Entries not yet finished (playing or waiting; 0 when the queue has gone // quiet); tones, when not NULL, gets how many of them are tones rather // than rests. uint32_t audioNotesQueued(const AudioNotesT *notes, uint32_t *tones); // Entries that can still be added. uint32_t audioNotesSpace(const AudioNotesT *notes); // The queue's voice id (for volume and pan). int32_t audioNotesVoice(const AudioNotesT *notes); // ============================================================ // FM synthesizer // ============================================================ // // The FM chip's two-operator voices are shared: a program takes one with // audioFmAlloc, programs it with audioFmWrite and gives it back with // audioFmFree (closing the context gives back all of its voices). Voices // are handed out least recently used first, so a released note's tail // is cut last. audioFmWrite takes the registers of the voice's own // channel, numbered as for the first channel of an OPL2 (AUDIO_FM_* // below); the library adds the channel's offsets. On an OPL3 a // AUDIO_FM_FEEDBACK value without either output bit plays on both sides. // // A program may instead take the whole chip (audioFmRawAcquire): every // voice of the other programs is silenced and taken back (their tones // go on in the mixer), new voices are refused until the chip is given // back, and a second program asking for the chip gets AUDIO_ERR_BUSY. // // audioFmAlloc, audioFmFree, audioFmWrite and audioFmRawWrite may also be // called from a timer callback (platformTimerAdd), as music playback does. // Most voices an FM chip has (OPL3; an OPL2 has 9) #define AUDIO_FM_VOICES_MAX 18 // The chip's own sample rate (Hz), which frequency numbers are based on: // hz = fnum * AUDIO_FM_CHIP_HZ * 2^block / 2^20 #define AUDIO_FM_CHIP_HZ 49716 #define AUDIO_FM_FNUM_MAX 1023 #define AUDIO_FM_BLOCK_MAX 7 #define AUDIO_FM_FNUM_HI_SHIFT 8 // fnum bits 8-9 go in AUDIO_FM_KEY_BLOCK bits 0-1 #define AUDIO_FM_BLOCK_SHIFT 2 // block in AUDIO_FM_KEY_BLOCK bits 2-4 // Channel registers for audioFmWrite (modulator / carrier operator) #define AUDIO_FM_MOD_CHAR 0x20 // tremolo, vibrato, sustaining, key scale rate, multiple #define AUDIO_FM_CAR_CHAR 0x23 #define AUDIO_FM_MOD_LEVEL 0x40 // key scale level (bits 6-7), attenuation (bits 0-5, 0.75 dB) #define AUDIO_FM_CAR_LEVEL 0x43 #define AUDIO_FM_MOD_ATTACK 0x60 // attack rate (bits 4-7), decay rate (bits 0-3) #define AUDIO_FM_CAR_ATTACK 0x63 #define AUDIO_FM_MOD_SUSTAIN 0x80 // sustain level (bits 4-7), release rate (bits 0-3) #define AUDIO_FM_CAR_SUSTAIN 0x83 #define AUDIO_FM_FNUM_LOW 0xA0 // frequency number bits 0-7 #define AUDIO_FM_KEY_BLOCK 0xB0 // key on, block, frequency number bits 8-9 #define AUDIO_FM_FEEDBACK 0xC0 // outputs, feedback (bits 1-3), additive (bit 0) #define AUDIO_FM_MOD_WAVE 0xE0 // waveform #define AUDIO_FM_CAR_WAVE 0xE3 // Bits of those registers #define AUDIO_FM_KEY_ON 0x20 // AUDIO_FM_KEY_BLOCK: sounding #define AUDIO_FM_OUT_LEFT 0x10 // AUDIO_FM_FEEDBACK: left output (OPL3) #define AUDIO_FM_OUT_RIGHT 0x20 // AUDIO_FM_FEEDBACK: right output (OPL3) #define AUDIO_FM_OUT_BOTH (AUDIO_FM_OUT_LEFT | AUDIO_FM_OUT_RIGHT) #define AUDIO_FM_ADDITIVE 0x01 // AUDIO_FM_FEEDBACK: both operators heard // The FM chip (audioFmGetInfo); voices 0 when there is none. typedef struct { char description[AUDIO_DESC_MAX]; // e.g. "OPL3 FM synthesizer at 388h" uint32_t voices; // two-operator voices uint32_t freeVoices; // not taken by any program bool stereo; // voices can be panned (OPL3) bool rawOwned; // one program has the whole chip } AudioFmInfoT; // Take a free FM voice for ctx. Returns its id (> 0), AUDIO_ERR_NO_VOICE // when all are taken, AUDIO_ERR_BUSY while a program has the whole chip, // AUDIO_ERR_NO_SYNTH without an FM chip. int32_t audioFmAlloc(AudioCtxT *ctx); // Silence the voice (key off) and give it back. int32_t audioFmFree(AudioCtxT *ctx, int32_t voice); // The FM chip in use. void audioFmGetInfo(AudioFmInfoT *info); // Set a register of the voice's channel (AUDIO_FM_*). int32_t audioFmWrite(AudioCtxT *ctx, int32_t voice, uint8_t reg, uint8_t value); // The whole chip for ctx alone; audioFmRawWrite sets any register // (bank * AUDIO_FM_BANK_REGS + index, bank 1 on an OPL3 only). Release // silences the chip and gives its voices back to everyone. int32_t audioFmRawAcquire(AudioCtxT *ctx); int32_t audioFmRawRelease(AudioCtxT *ctx); int32_t audioFmRawWrite(AudioCtxT *ctx, uint32_t reg, uint8_t value); // ============================================================ // MIDI port // ============================================================ // // The MIDI port (an MPU-401 in UART mode, used only when DVX.INI [audio] // midi = mpu401) belongs to one program at a time. audioMidiPut may // also be called from a timer callback; it returns AUDIO_ERR_BUSY when // the port cannot take a byte yet (send it again later). // The MIDI port (audioMidiGetInfo). typedef struct { char description[AUDIO_DESC_MAX]; // e.g. "MPU-401 MIDI port at 330h"; "" when none bool present; bool owned; // a program is using it } AudioMidiInfoT; int32_t audioMidiAcquire(AudioCtxT *ctx); void audioMidiGetInfo(AudioMidiInfoT *info); int32_t audioMidiPut(AudioCtxT *ctx, uint8_t byte); int32_t audioMidiRelease(AudioCtxT *ctx); // ============================================================ // Desktop sounds // ============================================================ // // The sounds DVX plays for its events (dvxPlaySound, DvxSoundE in // dvxApp.h). Each event's sound is a WAV or VOC file named in DVX.INI // [sounds] under the event's key: a name alone is a file in the sound // folders (the user's SOUNDS, then SHARED\SOUNDS: platformKindFind), a // name with a folder in it a path (empty or missing: none). The library // connects itself to DVX when it loads and plays them on a context of its // own, so they belong to no program; with no sound hardware they are // silent. #define AUDIO_SOUNDS_SECTION "sounds" // The DVX.INI key of an event ("startup", "error", ...), and its name for // people ("Start DVX", "Error", ...); NULL for an event out of range. const char *audioDeskKey(DvxSoundE event); const char *audioDeskLabel(DvxSoundE event); // Play the event's sound (the DvxSoundHookT that DVX calls); with wait, // return once it has played (at most a few seconds). void audioDeskPlay(DvxSoundE event, bool wait); // Play a sound file the way desktop sounds play (to try one out). // Returns the voice id or an AUDIO_ERR_* code. int32_t audioDeskPlayFile(const char *path); // DVX.INI [sounds] has changed: read it again before the next sound. void audioDeskReload(void); // ============================================================ // Drivers // ============================================================ // The short names of the sound drivers installed (DVX.INI [audio] // driver), the one tried first first; returns how many were put in names // (at most max). int32_t audioDriverNames(char names[][AUDIO_NAME_MAX], int32_t max); // The most drivers audioDriverNames is asked for by DVX's own callers #define AUDIO_DRIVERS_MAX 16 // ============================================================ // Settings (DVX.INI, the Control Panel's Sounds page) // ============================================================ // // What the Sounds page and the BASIC functions read and write; prefs is // a copy of DVX.INI the caller loads and saves. The device reads the // same keys when it starts (driver, volume, midi: audioDrv.h). // [audio] midi: where MIDI music plays, in dropdown order (label for // people, iniName stored; value unused). Default AUDIO_MIDI_AUTO. #define AUDIO_MIDI_CHOICE_COUNT 4 extern const PrefsChoiceT audioMidiChoices[AUDIO_MIDI_CHOICE_COUNT]; // The sound file of an event in [sounds] ("" for none or an event out of // range), and setting it ("" or NULL: none). const char *audioDeskFile(PrefsHandleT *prefs, DvxSoundE event); void audioDeskSetFile(PrefsHandleT *prefs, DvxSoundE event, const char *path); // A volume in percent (clamped to 0..100) as 0..AUDIO_VOLUME_MAX. int32_t audioPercentToVolume(int32_t percent); // [audio] driver (AUDIO_DRIVER_AUTO when missing), midi (the index in // audioMidiChoices; auto when missing or unknown) and volume (percent, // 0..100, 100 when missing). const char *audioSettingDriver(PrefsHandleT *prefs); int32_t audioSettingMidi(PrefsHandleT *prefs); int32_t audioSettingVolume(PrefsHandleT *prefs); // Store [audio] driver, midi (an audioMidiChoices index; out of range: // auto) and volume (percent, clamped). void audioSettingsStore(PrefsHandleT *prefs, const char *driver, int32_t midi, int32_t volume); // ============================================================ // BASIC (src/include/basic/sound.bas) // ============================================================ // Each BASIC program gets its own context on first use. Volumes, pans // and pitches are in percent (volume 0..100, pan -100..100, pitch // 25..400); a voice, sound or stream number is 0 on failure (SoundError$ // says why). Sounds and streams are numbered per program and freed with // its context. SoundCreate and SoundStreamWrite take BINARY STRING PCM // (bytes and byte count). The Midi... functions are declared in // music.bas. int32_t FmAlloc(void); void FmFree(int32_t voice); const char *FmInfo(const char *field); int32_t FmRawAcquire(void); void FmRawRelease(void); int32_t FmRawWrite(int32_t reg, int32_t value); int32_t FmWrite(int32_t voice, int32_t reg, int32_t value); int32_t MidiAcquire(void); const char *MidiPortInfo(const char *field); int32_t MidiPut(int32_t byteValue); void MidiRelease(void); int32_t PlayNoise(int32_t frequency, int32_t milliseconds, int32_t volume); int32_t PlayTone(int32_t frequency, int32_t milliseconds, int32_t volume); int32_t PlayTriangle(int32_t frequency, int32_t milliseconds, int32_t volume); int32_t PlayWave(const char *fileName); int32_t PlayWaveLoop(const char *fileName); int32_t SoundCaps(const char *field); int32_t SoundCreate(const uint8_t *pcm, int32_t len, int32_t rate, int32_t bits, int32_t channels); const char *SoundDriverAuto(void); int32_t SoundDriverCount(void); const char *SoundDriverName(int32_t index); const char *SoundError(void); int32_t SoundEventCount(void); const char *SoundEventFile(int32_t prefs, int32_t eventIdx); const char *SoundEventKey(int32_t eventIdx); const char *SoundEventLabel(int32_t eventIdx); void SoundEventsReload(void); const char *SoundFolder(void); void SoundFree(int32_t sound); int32_t SoundGetVolume(void); const char *SoundInfo(void); int32_t SoundLength(int32_t sound); int32_t SoundLoad(const char *fileName); int32_t SoundMasterVolume(void); int32_t SoundMidiCount(void); const char *SoundMidiLabel(int32_t index); int32_t SoundPlay(int32_t sound, int32_t volume, int32_t pan, int32_t loopIt); void SoundPlayEvent(int32_t eventIdx, int32_t wait); int32_t SoundPlaying(int32_t voice); void SoundSetEventFile(int32_t prefs, int32_t eventIdx, const char *fileName); void SoundSetFrequency(int32_t voice, int32_t frequency); void SoundSetMasterVolume(int32_t percent); void SoundSetPan(int32_t voice, int32_t pan); void SoundSetPitch(int32_t voice, int32_t percent); const char *SoundSettingDriver(int32_t prefs); int32_t SoundSettingMidi(int32_t prefs); void SoundSettingsStore(int32_t prefs, const char *driver, int32_t midi, int32_t volume); int32_t SoundSettingVolume(int32_t prefs); void SoundSetVolume(int32_t voice, int32_t volume); void SoundStreamClose(int32_t stream); int32_t SoundStreamOpen(int32_t rate, int32_t bits, int32_t channels, int32_t bufferMs); int32_t SoundStreamQueued(int32_t stream); int32_t SoundStreamSpace(int32_t stream); int32_t SoundStreamVoice(int32_t stream); int32_t SoundStreamWrite(int32_t stream, const uint8_t *pcm, int32_t len); int32_t SoundTestFile(const char *fileName); void SoundVolume(int32_t volume); void StopAllSounds(void); void StopWave(int32_t voice); #endif // AUDIO_LIB_H