From 1daa5b5f2d712490e4518729726fe0efa606d6bc Mon Sep 17 00:00:00 2001 From: KonAki Date: Wed, 14 Oct 2026 18:42:43 +0800 Subject: add sound module: RPG Maker style audio channels --- kon/konsound.h | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 kon/konsound.h (limited to 'kon/konsound.h') diff --git a/kon/konsound.h b/kon/konsound.h new file mode 100644 index 0000000..296c691 --- /dev/null +++ b/kon/konsound.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: MIT */ +/* + * konsound.h + * + * Copyright (c) 2026 KonAki + * + * 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. + */ + +#ifndef KONSOUND_H +#define KONSOUND_H + +#include +#include + +#include "konaudio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*** definition ***/ + +#define KON_SOUND_NAME 64 +#define KON_SOUND_SE_TRACKED 16 + +#define KON_SOUND_BGM 0 +#define KON_SOUND_BGS 1 +#define KON_SOUND_ME 2 +#define KON_SOUND_SE 3 + +/* finds the sound for a name. loopStart and loopEnd are frames, leave them 0 for no loop points. + the sound has to stay alive while it plays. return NULL for a name you do not have */ +typedef const kon_sound_t *(*kon_soundLookup_t)(int kind, const char *name, uint64_t *loopStart, uint64_t *loopEnd, void *user); + +typedef struct kon_soundChannel { + kon_audioHandle_t handle; + char name[KON_SOUND_NAME]; + int volume, pitch, pan; +} kon_soundChannel_t; + +/* volumes, pitches and pans are the RPG Maker numbers: volume 0 to 100, pitch 50 to 150 (100 is normal), pan -100 to 100 */ +typedef struct kon_soundDeck { + kon_audio_t *audio; + kon_soundLookup_t lookup; + void *user; + kon_soundChannel_t bgm, bgs, me; + kon_soundChannel_t savedBgm; + kon_soundChannel_t resumeBgm; /* the music that was playing when a ME started */ + int meHeld; + kon_audioHandle_t se[KON_SOUND_SE_TRACKED]; + int seNext; +} kon_soundDeck_t; + +/*** deck ***/ + +void kon_soundDeckInit(kon_soundDeck_t *deck, kon_audio_t *audio, kon_soundLookup_t lookup, void *user); + +/* stops everything this deck started */ +void kon_soundDeckStop(kon_soundDeck_t *deck); + +/* call once per frame. brings the music back when a ME is over */ +void kon_soundUpdate(kon_soundDeck_t *deck); + +/*** channels ***/ + +/* a new name replaces the music, the same name only changes volume, pitch and pan. an empty name stops it */ +void kon_soundPlayBgm(kon_soundDeck_t *deck, const char *name, int volume, int pitch, int pan); +void kon_soundPlayBgs(kon_soundDeck_t *deck, const char *name, int volume, int pitch, int pan); +void kon_soundFadeBgm(kon_soundDeck_t *deck, int seconds); +void kon_soundFadeBgs(kon_soundDeck_t *deck, int seconds); + +/* remembers the music, and starts it again from the beginning (the position is not kept) */ +void kon_soundSaveBgm(kon_soundDeck_t *deck); +void kon_soundReplayBgm(kon_soundDeck_t *deck); + +/* plays once. the music pauses until it is over */ +void kon_soundPlayMe(kon_soundDeck_t *deck, const char *name, int volume, int pitch, int pan); +void kon_soundPlaySe(kon_soundDeck_t *deck, const char *name, int volume, int pitch, int pan); +void kon_soundStopSe(kon_soundDeck_t *deck); + +/*** konscript host commands ***/ + +/* handles the RPG Maker audio commands 241 to 246, 249, 250 and 251 the way mzscript writes them. + returns 1 when the code was one of those, 0 when it is not yours to handle */ +int kon_soundHost(kon_soundDeck_t *deck, int code, int b, int c, int d, const char *text); + +/*** ogg loop points ***/ + +/* looks for LOOPSTART and LOOPLENGTH tags in the start of an ogg file, the way RPG Maker games write them. + returns 1 and sets start and end (frames) when there is a loop start, else 0 */ +int kon_soundOggLoop(const uint8_t *data, size_t size, uint64_t *start, uint64_t *end); + +#ifdef __cplusplus +} +#endif +#endif -- cgit