X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fsdlmixer%2Fsound.c;h=593f1389dda3318a8e8cfad4f0df7e4fc958e366;hb=b7c6f2a0e12b4ee2d4111d1e671bf2b8b14c71b4;hp=026e01fec9486d79a499196d596c412ccc2e618a;hpb=dbfaa4949fe7c5be64cf3e98b1875b711656ff67;p=flatwaifu.git
diff --git a/src/sdlmixer/sound.c b/src/sdlmixer/sound.c
index 026e01f..593f138 100644
--- a/src/sdlmixer/sound.c
+++ b/src/sdlmixer/sound.c
@@ -1,33 +1,50 @@
+/* Copyright (C) 2020 SovietPony
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License ONLY.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
#include "glob.h"
#include "sound.h"
#include "music.h"
-#include "misc.h" // int2host
#include "memory.h" // M_lock M_unlock
#include "files.h" // F_findres
#include "error.h"
-#include
-#include
+#include "common/endianness.h"
+
+#include "SDL.h"
+#include "SDL_mixer.h"
#include
+#include
#define TAG_MIX1 0x4d495831
#pragma pack(1)
-struct dmi {
+typedef struct dmi {
Uint32 len; // length [bytes]
Uint32 rate; // freq [Hz]
Uint32 lstart; // loop start offset [bytes]
Uint32 llen; // loop length [bytes]
Uint8 data[]; // sound data
-};
+} dmi;
#pragma pack()
-struct sound {
+typedef struct sdlmixer_snd {
snd_t base;
Mix_Chunk *c;
-};
+} sdlmixer_snd;
-short snd_vol; // public 0..128
+static short snd_vol;
static int devfreq = MIX_DEFAULT_FREQUENCY;
static Uint32 devformat = AUDIO_S16SYS; // MIX_DEFAULT_FORMAT
@@ -38,44 +55,91 @@ static int devinit;
/* music */
-short mus_vol;
-char music_random;
-int music_time;
-int music_fade;
+const cfg_t *MUS_args (void) {
+ return NULL;
+}
+
+const cfg_t *MUS_conf (void) {
+ return NULL;
+}
+
+const menu_t *MUS_menu (void) {
+ return NULL;
+}
+
+void MUS_init (void) {
+
+}
+
+void MUS_done (void) {
-void S_initmusic (void) {
+}
+
+void MUS_start (int time) {
}
-void S_donemusic (void) {
+void MUS_stop (void) {
}
-void S_startmusic (int time) {
+void MUS_volume (int v) {
}
-void S_stopmusic (void) {
+void MUS_load (char n[8]) {
}
-void S_volumemusic (int v) {
+void MUS_free (void) {
}
-void F_loadmus (char n[8]) {
+void MUS_update (void) {
}
-void F_freemus (void) {
+/* Sound */
+static int sound_menu_handler (menu_msg_t *msg, const menu_t *m, int i) {
+ static int cur;
+ enum { VOLUME, __NUM__ };
+ static const simple_menu_t sm = {
+ GM_BIG, "Sound", NULL,
+ {
+ { "Volume", NULL },
+ }
+ };
+ if (i == VOLUME) {
+ switch (msg->type) {
+ case GM_GETENTRY: return GM_init_int0(msg, GM_SCROLLER, 0, 0, 0);
+ case GM_GETINT: return GM_init_int(msg, snd_vol, 0, 128, 8);
+ case GM_SETINT: S_volume(msg->integer.i); return 1;
+ }
+ }
+ return simple_menu_handler(msg, i, __NUM__, &sm, &cur);
}
-void S_updatemusic (void) {
+const menu_t *S_menu (void) {
+ static const menu_t m = { sound_menu_handler };
+ return &m;
+}
+const cfg_t *S_args (void) {
+ static const cfg_t args[] = {
+ { "sndvol", &snd_vol, Y_WORD },
+ { NULL, NULL, 0 }
+ };
+ return args;
}
-/* sound */
+const cfg_t *S_conf (void) {
+ static const cfg_t conf[] = {
+ { "sound_volume", &snd_vol, Y_WORD },
+ { NULL, NULL, 0 }
+ };
+ return conf;
+}
void S_init (void) {
assert(devinit == 0);
@@ -86,16 +150,17 @@ void S_init (void) {
devinit = 1;
} else {
logo("S_init: Mix_OpenAudio: %s\n", Mix_GetError());
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
} else {
logo("S_init: SDL_InitSubSytem: %s\n", SDL_GetError());
}
}
-static Mix_Chunk *convert_this (int rate, const Uint8 *buf, int len) {
+static Mix_Chunk *convert_this (int rate, int sign, const Uint8 *buf, int len) {
SDL_AudioCVT cvt;
Mix_Chunk *c = NULL;
- if (SDL_BuildAudioCVT(&cvt, AUDIO_S8, 1, rate, devformat, devchannels, devfreq) != -1) {
+ if (SDL_BuildAudioCVT(&cvt, sign ? AUDIO_S8 : AUDIO_U8, 1, rate, devformat, devchannels, devfreq) != -1) {
int maxlen = len * cvt.len_mult;
Uint8 *maxbuf = malloc(maxlen);
if (maxbuf != NULL) {
@@ -120,44 +185,55 @@ static Mix_Chunk *convert_this (int rate, const Uint8 *buf, int len) {
return c;
}
-// TODO load raw sounds with voices
+static sdlmixer_snd *new_sdlmixer_snd (const void *data, dword len, dword rate, dword lstart, dword llen, int sign) {
+ Mix_Chunk *c = NULL;
+ sdlmixer_snd *snd = NULL;
+ c = convert_this(rate, sign, data, len);
+ if (c != NULL) {
+ snd = malloc(sizeof(sdlmixer_snd));
+ if (snd != NULL) {
+ snd->base.tag = TAG_MIX1;
+ snd->c = c;
+ } else {
+ free(c->abuf);
+ free(c);
+ }
+ }
+ return snd;
+}
snd_t *S_get (int id) {
- if (!devinit) {
- return NULL;
- }
- struct dmi *snd = M_lock(id);
- struct sound *res = NULL;
- if (snd != NULL) {
- int rlen = F_getreslen(id);
- if (rlen > 16) {
- Uint32 len = int2host(snd->len);
- Uint32 rate = int2host(snd->rate);
- Uint32 lstart = int2host(snd->lstart);
- Uint32 llen = int2host(snd->llen);
- if (len <= rlen - 8 && lstart + llen <= rlen - 16) {
- Mix_Chunk *c = convert_this(rate, snd->data, len);
- if (c != NULL) {
- res = malloc(sizeof(struct sound));
- if (res != NULL) {
- res->base.tag = TAG_MIX1;
- res->c = c;
- // TODO loops
- } else {
- free(c);
- }
+ void *handle;
+ sdlmixer_snd *snd = NULL;
+ if (devinit) {
+ handle = M_lock(id);
+ if (handle != NULL) {
+ void *data = handle;
+ dword len = F_getreslen(id);
+ dword rate = 11025;
+ dword lstart = 0;
+ dword llen = 0;
+ int sign = 0;
+ if (len > 16) {
+ dmi *hdr = handle;
+ dword hdr_len = int2host(hdr->len);
+ dword hdr_rate = int2host(hdr->rate);
+ dword hdr_lstart = int2host(hdr->lstart);
+ dword hdr_llen = int2host(hdr->llen);
+ if (hdr_len <= len - 8 && hdr_lstart + hdr_llen <= len - 16) {
+ data = hdr->data;
+ len = hdr_len;
+ rate = hdr_rate;
+ lstart = hdr_lstart;
+ llen = hdr_llen;
+ sign = 1;
}
- } else {
- logo("S_get(%i): invalid header {len=%u:rate=%u:lstart=%u:llen=%u:rlen=%i}\n", id, len, rate, lstart, llen, rlen);
}
- } else {
- logo("S_load(%i): too short\n", id);
+ snd = new_sdlmixer_snd(data, len, rate, lstart, llen, sign);
+ M_unlock(handle);
}
- M_unlock(snd);
- } else {
- logo("S_load(%i): not found\n", id);
}
- return (snd_t*)res;
+ return (snd_t*)snd;
}
snd_t *S_load (const char name[8]) {
@@ -165,29 +241,43 @@ snd_t *S_load (const char name[8]) {
return S_get(id);
}
+void S_free (snd_t *s) {
+ int i;
+ sdlmixer_snd *snd = (sdlmixer_snd*)s;
+ if (snd != NULL) {
+ assert(snd->base.tag == TAG_MIX1);
+ if (devinit) {
+ for (i = 0; i < devchunkchannels; i++) {
+ if (Mix_GetChunk(i) == snd->c) {
+ Mix_HaltChannel(i);
+ }
+ }
+ }
+ free(snd->c->abuf);
+ free(snd->c);
+ free(snd);
+ }
+}
+
short S_play (snd_t *s, short c, short v) {
+ short channel = 0;
+ sdlmixer_snd *snd = (sdlmixer_snd*)s;
assert(c >= 0 && c <= 8);
assert(v >= 0 && v <= 255);
- short channel = 0;
- if (devinit) {
- if (s) {
- struct sound *snd = (struct sound *)s;
- assert(snd->base.tag == TAG_MIX1);
- // TODO care about global volume level
- snd->c->volume = v * MIX_MAX_VOLUME / 255;
- channel = Mix_PlayChannel(c <= 0 ? -1 : c - 1, snd->c, 0);
- channel = channel == -1 ? 0 : channel + 1;
- }
+ if (devinit && snd != NULL) {
+ assert(snd->base.tag == TAG_MIX1);
+ // TODO care about global volume level
+ snd->c->volume = v * MIX_MAX_VOLUME / 255;
+ channel = Mix_PlayChannel(c <= 0 ? -1 : c - 1, snd->c, 0);
+ channel = channel == -1 ? 0 : channel + 1;
}
return channel;
}
void S_stop (short c) {
assert(c >= 0 && c <= 8);
- if (devinit) {
- if (c > 0) {
- Mix_HaltChannel(c - 1);
- }
+ if (devinit && c > 0) {
+ Mix_HaltChannel(c - 1);
}
}