Mercurial > hg > xmms-sid
diff src/xs_sidplay1.cpp @ 834:a7ee5dc23e78
Rename .cc -> .cpp.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 08 Nov 2012 20:47:05 +0200 |
parents | src/xs_sidplay1.cc@b158abe91a75 |
children | 5b3e2116408f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xs_sidplay1.cpp Thu Nov 08 20:47:05 2012 +0200 @@ -0,0 +1,352 @@ +/* + XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS) + + libSIDPlay v1 support + + Programmed and designed by Matti 'ccr' Hamalainen <ccr@tnsp.org> + (C) Copyright 1999-2007 Tecnic Software productions (TNSP) + + 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; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "xmms-sid.h" + +#ifdef HAVE_SIDPLAY1 + +#include "xs_sidplay1.h" +#include "xs_slsup.h" +#include "xs_config.h" + +#include <sidplay/player.h> +#include <sidplay/myendian.h> +#include <sidplay/fformat.h> + + +/* Maximum audio frequency supported by libSIDPlay v1 */ +#define SIDPLAY1_MAX_FREQ (48000) + + +typedef struct { + emuEngine *emu; + emuConfig currConfig; + sidTune *tune; + guint8 *buf; + size_t bufSize; +} XSSIDPlay1; + + +/* We need to 'export' all this pseudo-C++ crap */ +extern "C" { + + +/* Return song information + */ +#define TFUNCTION xs_sidplay1_getinfo +#define TFUNCTION2 xs_sidplay1_updateinfo +#define TTUNEINFO sidTuneInfo +#define TTUNE sidTune +#define TENGINE XSSIDPlay1 +#include "xs_sidplay.h" + + +/* Check if we can play the given file + */ +gboolean xs_sidplay1_probe(XSFile *f) +{ + gchar tmpBuf[4]; + + if (!f) return FALSE; + + if (xs_fread(tmpBuf, sizeof(gchar), 4, f) != 4) + return FALSE; + + if (!strncmp(tmpBuf, "PSID", 4)) + return TRUE; + else + return FALSE; +} + + +/* Initialize SIDPlay1 + */ +gboolean xs_sidplay1_init(XSEngineState * state) +{ + gint tmpFreq; + XSSIDPlay1 *engine; + assert(state); + + /* Allocate internal structures */ + engine = (XSSIDPlay1 *) g_malloc0(sizeof(XSSIDPlay1)); + if (!engine) return FALSE; + + /* Initialize engine */ + engine->emu = new emuEngine(); + if (!engine->emu) { + xs_error("[SIDPlay1] Could not initialize emulation engine.\n"); + g_free(engine); + return FALSE; + } + + /* Verify endianess */ + if (!engine->emu->verifyEndianess()) { + xs_error("[SIDPlay1] Endianess verification failed.\n"); + delete engine->emu; + g_free(engine); + return FALSE; + } + + state->internal = engine; + + /* Get current configuration */ + engine->emu->getConfig(engine->currConfig); + + /* Configure channel parameters */ + switch (state->audioChannels) { + + case XS_CHN_AUTOPAN: + engine->currConfig.channels = SIDEMU_STEREO; + engine->currConfig.autoPanning = SIDEMU_CENTEREDAUTOPANNING; + engine->currConfig.volumeControl = SIDEMU_FULLPANNING; + break; + + case XS_CHN_STEREO: + engine->currConfig.channels = SIDEMU_STEREO; + engine->currConfig.autoPanning = SIDEMU_NONE; + engine->currConfig.volumeControl = SIDEMU_NONE; + break; + + case XS_CHN_MONO: + default: + engine->currConfig.channels = SIDEMU_MONO; + engine->currConfig.autoPanning = SIDEMU_NONE; + engine->currConfig.volumeControl = SIDEMU_NONE; + state->audioChannels = XS_CHN_MONO; + break; + } + + + /* Memory mode settings */ + switch (xs_cfg.memoryMode) { + case XS_MPU_TRANSPARENT_ROM: + engine->currConfig.memoryMode = MPU_TRANSPARENT_ROM; + break; + + case XS_MPU_PLAYSID_ENVIRONMENT: + engine->currConfig.memoryMode = MPU_PLAYSID_ENVIRONMENT; + break; + + case XS_MPU_BANK_SWITCHING: + default: + engine->currConfig.memoryMode = MPU_BANK_SWITCHING; + xs_cfg.memoryMode = XS_MPU_BANK_SWITCHING; + break; + } + + + /* Audio parameters sanity checking and setup */ + engine->currConfig.bitsPerSample = state->audioBitsPerSample; + tmpFreq = state->audioFrequency; + + if (tmpFreq > SIDPLAY1_MAX_FREQ) + tmpFreq = SIDPLAY1_MAX_FREQ; + + engine->currConfig.frequency = tmpFreq; + + switch (state->audioBitsPerSample) { + case XS_RES_8BIT: + switch (state->audioFormat) { + case FMT_S8: + state->audioFormat = FMT_S8; + engine->currConfig.sampleFormat = SIDEMU_SIGNED_PCM; + break; + + case FMT_U8: + default: + state->audioFormat = FMT_U8; + engine->currConfig.sampleFormat = SIDEMU_UNSIGNED_PCM; + break; + } + break; + + case XS_RES_16BIT: + default: + switch (state->audioFormat) { + case FMT_U16_NE: + case FMT_U16_LE: + case FMT_U16_BE: + state->audioFormat = FMT_U16_NE; + engine->currConfig.sampleFormat = SIDEMU_UNSIGNED_PCM; + break; + + case FMT_S16_NE: + case FMT_S16_LE: + case FMT_S16_BE: + default: + state->audioFormat = FMT_S16_NE; + engine->currConfig.sampleFormat = SIDEMU_SIGNED_PCM; + break; + } + break; + } + + /* Clockspeed settings */ + switch (xs_cfg.clockSpeed) { + case XS_CLOCK_NTSC: + engine->currConfig.clockSpeed = SIDTUNE_CLOCK_NTSC; + break; + + case XS_CLOCK_PAL: + default: + engine->currConfig.clockSpeed = SIDTUNE_CLOCK_PAL; + xs_cfg.clockSpeed = XS_CLOCK_PAL; + break; + } + + engine->currConfig.forceSongSpeed = xs_cfg.forceSpeed; + + + /* Configure rest of the emulation */ + /* if (xs_cfg.forceModel) */ + engine->currConfig.mos8580 = xs_cfg.mos8580; + engine->currConfig.emulateFilter = xs_cfg.emulateFilters; + engine->currConfig.filterFs = xs_cfg.sid1Filter.fs; + engine->currConfig.filterFm = xs_cfg.sid1Filter.fm; + engine->currConfig.filterFt = xs_cfg.sid1Filter.ft; + + + /* Now set the emulator configuration */ + if (!engine->emu->setConfig(engine->currConfig)) { + xs_error("[SIDPlay1] Emulator engine configuration failed!\n"); + return FALSE; + } + + /* Create sidtune object */ + engine->tune = new sidTune(0); + if (!engine->tune) { + xs_error("[SIDPlay1] Could not initialize SIDTune object.\n"); + return FALSE; + } + + return TRUE; +} + + +/* Close SIDPlay1 engine + */ +void xs_sidplay1_close(XSEngineState * state) +{ + XSSIDPlay1 *engine; + assert(state); + + engine = (XSSIDPlay1 *) state->internal; + + /* Free internals */ + if (engine->emu) { + delete engine->emu; + engine->emu = NULL; + } + + if (engine->tune) { + delete engine->tune; + engine->tune = NULL; + } + + xs_sidplay1_delete(state); + + g_free(engine); + state->internal = NULL; +} + + +/* Initialize current song and sub-tune + */ +gboolean xs_sidplay1_initsong(XSEngineState * state) +{ + XSSIDPlay1 *engine; + assert(state); + + engine = (XSSIDPlay1 *) state->internal; + if (!engine) return FALSE; + + if (!engine->tune) { + xs_error("[SIDPlay1] SID-tune struct pointer was NULL. This should not happen, report to XMMS-SID author.\n"); + return FALSE; + } + + if (!engine->tune->getStatus()) { + xs_error("[SIDPlay1] SID-tune status check failed. This should not happen, report to XMMS-SID author.\n"); + return FALSE; + } + + return sidEmuInitializeSong(*engine->emu, *engine->tune, state->currSong); +} + + +/* Emulate and render audio data to given buffer + */ +guint xs_sidplay1_fillbuffer(XSEngineState * state, gchar * audioBuffer, guint audioBufSize) +{ + XSSIDPlay1 *engine; + assert(state); + + engine = (XSSIDPlay1 *) state->internal; + if (!engine) return 0; + + sidEmuFillBuffer(*engine->emu, *engine->tune, audioBuffer, audioBufSize); + + return audioBufSize; +} + + +/* Load a given SID-tune file + */ +gboolean xs_sidplay1_load(XSEngineState * state, gchar * filename) +{ + XSSIDPlay1 *engine; + assert(state); + + engine = (XSSIDPlay1 *) state->internal; + if (!engine) return FALSE; + + /* Try to get the tune */ + if (!filename) return FALSE; + + if (xs_fload_buffer(filename, &(engine->buf), &(engine->bufSize)) != 0) + return FALSE; + + if (!engine->tune->load(engine->buf, engine->bufSize)) + return FALSE; + + return TRUE; +} + + +/* Delete INTERNAL information + */ +void xs_sidplay1_delete(XSEngineState * state) +{ + XSSIDPlay1 *engine; + assert(state); + + engine = (XSSIDPlay1 *) state->internal; + if (!engine) return; + + g_free(engine->buf); + engine->buf = NULL; + engine->bufSize = 0; +} + + +} /* extern "C" */ +#endif /* HAVE_SIDPLAY1 */