Mercurial > hg > dmlib
view tests/plrtest.c @ 2571:bb44c48cffac
Add helper function for getting C64 chargen ROM path from environment
variable 'CHARGEN_ROM' and use it instead of the compile-time hardcoded
value.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 02 Mar 2022 23:23:05 +0200 |
parents | aacf3bd1cceb |
children | 9807ae37ad69 |
line wrap: on
line source
#include "jss.h" #include "jssmod.h" #include "jssmix.h" #include "jssplr.h" #include <string.h> #include <unistd.h> #include <SDL.h> static const char patNoteTable[12][3] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" }; #define jmpNMODEffectTable (36) static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; void printRow(FILE * fh, const JSSPattern * pat, const int row) { const JSSNote *note = &(pat->data[pat->nchannels * row]); int width = pat->nchannels < 5 ? pat->nchannels : 5; fprintf(fh, "%.2x: ", row); for (int channel = 0; channel < width; channel++) { switch (note->note) { case jsetNotSet: fprintf(fh, "... "); break; case jsetNoteOff: fprintf(fh, "=== "); break; default: fprintf(fh, "%s%d ", patNoteTable[note->note % 12], note->note / 12); break; } if (note->instrument != jsetNotSet) fprintf(fh, "%.2x ", note->instrument + 1); else fprintf(fh, ".. "); if (note->volume == jsetNotSet) fprintf(fh, ".. "); else if (note->volume >= 0x00 && note->volume <= 0x40) fprintf(fh, "%.2x ", note->volume); else { char ch; switch (note->volume & 0xf0) { case 0x50: ch = '-'; break; case 0x60: ch = '+'; break; case 0x70: ch = '/'; break; case 0x80: ch = '\\'; break; case 0x90: ch = 'S'; break; case 0xa0: ch = 'V'; break; case 0xb0: ch = 'P'; break; case 0xc0: ch = '<'; break; case 0xd0: ch = '>'; break; case 0xe0: ch = 'M'; break; default: ch = '?'; break; } fprintf(fh, "%c%x ", ch, note->volume & 0x0f); } if (note->effect >= 0 && note->effect < jmpNMODEffectTable) fprintf(fh, "%c", jmpMODEffectTable[note->effect]); else fprintf(fh, "%c", note->effect == jsetNotSet ? '.' : '?'); if (note->param != jsetNotSet) fprintf(fh, "%.2x|", note->param); else fprintf(fh, "..|"); note++; } } void audioCallback(void *userdata, Uint8 *stream, int len) { JSSMixer *d = (JSSMixer *) userdata; if (d != NULL) { jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); } } int main(int argc, char *argv[]) { SDL_AudioSpec afmt; DMResource *file = NULL; char *inFilename = NULL; int res = -1; JSSModule *mod = NULL; JSSMixer *dev = NULL; JSSPlayer *plr = NULL; if (argc > 1) inFilename = argv[1]; // Open the files if (inFilename == NULL) res = dmf_open_stdio_stream(stdin, &file); else res = dmf_open_stdio(inFilename, "rb", &file); if (res != DMERR_OK) { dmErrorMsg("Error opening input file '%s': %s\n", inFilename, dmErrorStr(res)); goto exit; } // Initialize miniJSS printf("Initializing miniJSS\n"); jssInit(); // Read module file printf("Reading file: %s\n", inFilename); #ifdef JSS_SUP_XM if (mod == NULL) { printf("* Trying XM...\n"); dmfreset(file); if ((res = jssLoadXM(file, &mod, TRUE)) == DMERR_OK) { dmfreset(file); res = jssLoadXM(file, &mod, FALSE); } } #endif #ifdef JSS_SUP_JSSMOD if (mod == NULL) { printf("* Trying JSSMOD ...\n"); dmfreset(file); if ((res = jssLoadJSSMOD(file, &mod, TRUE)) == DMERR_OK) { dmfreset(file); res = jssLoadJSSMOD(file, &mod, FALSE); } } #endif dmf_close(file); // Check for errors, we still might have some data tho if (res != DMERR_OK) { dmErrorMsg( "Error loading module file: %s\n", dmErrorStr(res)); } // Check if we have anything if (mod == NULL) { res = dmError(DMERR_INIT_FAIL, "Could not load module file.\n"); goto exit; } // Try to convert it if ((res = jssConvertModuleForPlaying(mod)) != DMERR_OK) { dmErrorMsg("Could not convert module for playing: %s\n", dmErrorStr(res)); goto exit; } // Initialize SDL audio afmt.freq = 48000; afmt.format = AUDIO_S16SYS; afmt.channels = 2; // Initialize mixing device printf("Initializing miniJSS mixer with: %d, %d, %d\n", JSS_AUDIO_S16, afmt.channels, afmt.freq); dev = jvmInit(JSS_AUDIO_S16, afmt.channels, afmt.freq, JMIX_AUTO); if (dev == NULL) { res = dmError(DMERR_INIT_FAIL, "jvmInit() returned NULL\n"); goto exit; } afmt.samples = afmt.freq / 4; afmt.callback = audioCallback; afmt.userdata = (void *) dev; // Open the audio device fprintf(stderr, "Trying to init SDL with: %d, %d, %d\n", afmt.format, afmt.channels, afmt.freq); if (SDL_OpenAudio(&afmt, NULL) < 0) { res = dmError(DMERR_INIT_FAIL, "Couldn't open audio: %s\n", SDL_GetError()); goto exit; } // Initialize player if ((plr = jmpInit(dev)) == NULL) { res = dmError(DMERR_INIT_FAIL, "jmpInit() returned NULL\n"); goto exit; } // Initialize playing jvmSetCallback(dev, jmpExec, plr); jmpSetModule(plr, mod); jmpPlayOrder(plr, 0); jvmSetGlobalVol(dev, 100); // okay, main loop here ... "play" module and print out info printf("----------------------------------------------------\n"); SDL_LockAudio(); SDL_PauseAudio(0); SDL_UnlockAudio(); BOOL playing = TRUE; while (playing) { JSSPattern *pattern = NULL; int currRow, prevRow; JSS_LOCK(plr); currRow = prevRow = plr->row; JSS_UNLOCK(plr); while (currRow == prevRow && playing) { JSS_LOCK(plr); currRow = plr->row; playing = plr->isPlaying; pattern = plr->pattern; JSS_UNLOCK(plr); SDL_Delay(50); } if (playing && pattern != NULL) { printRow(stdout, pattern, currRow); printf("\n"); } } printf("----------------------------------------------------\n"); exit: SDL_LockAudio(); SDL_PauseAudio(1); jmpClose(plr); jvmClose(dev); jssFreeModule(mod); SDL_UnlockAudio(); SDL_Quit(); jssClose(); return res; }