Mercurial > hg > dmlib
view ppl.c @ 87:baf72a99d5ee
Cosmetics.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 02 Oct 2012 10:50:44 +0300 |
parents | 5cefa59baa9d |
children | 7a59611f9d4f |
line wrap: on
line source
#include "jss.h" #include "jssmod.h" #include "jssmix.h" #include "jssplr.h" #include "dmlib.h" #include "dmargs.h" #include "dmimage.h" #include "dmtext.h" #include <errno.h> struct { BOOL exitFlag; SDL_Surface *screen; SDL_Event event; int optScrWidth, optScrHeight, optVFlags, optScrDepth; } engine; struct { Uint32 boxBg, inboxBg, box1, box2, viewDiv, activeRow; } col; DMBitmapFont *font = NULL; char *optFilename = NULL, *optFontFilename = "c64font.png"; int optOutFormat = JSS_AUDIO_S16, optOutChannels = 2, optOutFreq = 48000, optMuteOChannels = -1, optStartOrder = -1; BOOL optUsePlayTime = FALSE; size_t optPlayTime; DMOptArg optList[] = { { 0, '?', "help", "Show this help", OPT_NONE }, { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, { 2, 0, "fs", "Fullscreen", OPT_NONE }, { 3, 'w', "window", "Initial window size/resolution -w 640x480", OPT_ARGREQ }, { 4, '1', "16bit", "16-bit output", OPT_NONE }, { 5, '8', "8bit", "8-bit output", OPT_NONE }, { 6, 'm', "mono", "Mono output", OPT_NONE }, { 7, 's', "stereo", "Stereo output", OPT_NONE }, { 8, 'f', "freq", "Output frequency", OPT_ARGREQ }, { 9, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, { 10, 'o', "order", "Start from order #", OPT_ARGREQ }, { 11, 't', "time", "Play for # seconds", OPT_ARGREQ }, }; const int optListN = sizeof(optList) / sizeof(optList[0]); void argShowHelp() { dmPrintBanner(stdout, dmProgName, "[options] <module>"); dmArgsPrintHelp(stdout, optList, optListN); } BOOL argHandleOpt(const int optN, char *optArg, char *currArg) { switch (optN) { case 0: argShowHelp(); exit(0); break; case 1: dmVerbosity++; break; case 2: engine.optVFlags |= SDL_FULLSCREEN; break; case 3: { int w, h; if (sscanf(optArg, "%dx%d", &w, &h) == 2) { if (w < 320 || h < 200 || w > 3200 || h > 3200) { dmError("Invalid width or height: %d x %d\n", w, h); return FALSE; } engine.optScrWidth = w; engine.optScrHeight = h; } else { dmError("Invalid size argument '%s'.\n", optArg); return FALSE; } } break; case 4: optOutFormat = JSS_AUDIO_S16; break; case 5: optOutFormat = JSS_AUDIO_U8; break; case 6: optOutChannels = JSS_AUDIO_MONO; break; case 7: optOutChannels = JSS_AUDIO_STEREO; break; case 8: optOutFreq = atoi(optArg); break; case 9: optMuteOChannels = atoi(optArg); break; case 10: optStartOrder = atoi(optArg); break; case 11: optPlayTime = atoi(optArg); optUsePlayTime = TRUE; break; default: dmError("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } BOOL argHandleFile(char *currArg) { if (!optFilename) optFilename = currArg; else { dmError("Too many filename arguments '%s'\n", currArg); return FALSE; } return TRUE; } Uint32 dmCol(float r, float g, float b) { return dmMapRGB(engine.screen, 255.0f * r, 255.0f * g, 255.0f * b); } BOOL dmInitializeVideo() { engine.screen = SDL_SetVideoMode( engine.optScrWidth, engine.optScrHeight, engine.optScrDepth, engine.optVFlags | SDL_RESIZABLE | SDL_SWSURFACE | SDL_HWPALETTE); if (engine.screen == NULL) { dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); return FALSE; } col.inboxBg = dmCol(0.7, 0.55, 0.1); col.boxBg = dmCol(0.8, 0.65, 0.15); col.box1 = dmCol(0.95, 0.95, 0.8); col.box2 = dmCol(0.3, 0.3, 0.15); col.viewDiv = dmCol(0,0,0); col.activeRow = dmCol(150,80,0); return TRUE; } 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 dmPrintNote(SDL_Surface *screen, int xc, int yc, JSSNote *n) { char text[32]; char *ptr = text; switch (n->note) { case jsetNotSet: sprintf(ptr, "..._"); break; case jsetNoteOff: sprintf(ptr, "===_"); break; default: sprintf(ptr, "%s%i_", patNoteTable[n->note % 12], n->note / 12); break; } ptr += 4; if (n->instrument != jsetNotSet) sprintf(ptr, "%.2x_", n->instrument + 1); else sprintf(ptr, ".._"); ptr += 3; if (n->volume == jsetNotSet) sprintf(ptr, ".._"); else if (n->volume >= 0x00 && n->volume <= 0x40) sprintf(ptr, "%.2x_", n->volume); else { char c; switch (n->volume & 0xf0) { case 0x50: c = '-'; break; case 0x60: c = '+'; break; case 0x70: c = '/'; break; case 0x80: c = '\\'; break; case 0x90: c = 'S'; break; case 0xa0: c = 'V'; break; case 0xb0: c = 'P'; break; case 0xc0: c = '<'; break; case 0xd0: c = '>'; break; case 0xe0: c = 'M'; break; default: c = '?'; break; } sprintf(ptr, "%c%x_", c, (n->volume & 0x0f)); } ptr += 3; if (n->effect >= 0 && n->effect < jmpNMODEffectTable) *ptr = jmpMODEffectTable[n->effect]; else if (n->effect == jsetNotSet) *ptr = '.'; else *ptr = '?'; ptr += 1; if (n->param != jsetNotSet) sprintf(ptr, "%.2x", n->param); else sprintf(ptr, ".."); dmDrawBMTextConst(screen, font, DMD_SATURATE, xc, yc, text); } void dmDisplayPattern(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSPattern *pat, int row, int choffs) { int cwidth = (font->width * 10 + 3 * 4 + 5), lwidth = 6 + font->width * 3, qwidth = ((x1 - x0 - lwidth) / cwidth), qheight = ((y1 - y0 - 4) / (font->height + 1)), nrow, nchannel, midrow = qheight / 2; dmDrawBox3D(screen, x0 + lwidth, y0, x1, y1, col.inboxBg, col.box2, col.box1); for (nchannel = 1; nchannel < qwidth; nchannel++) { dmDrawVLine(screen, y0 + 1, y1 - 1, x0 + lwidth + 1 + nchannel * cwidth, col.viewDiv); } for (nrow = 0; nrow < qheight; nrow++) { int yc = y0 + 2 + (font->height + 1) * nrow; dmDrawBMText(screen, font, DMD_SATURATE, x0, yc, "%03d", nrow); if (nrow == row) { dmFillRect(screen, x0 + lwidth + 1, yc - 1, x1 - 1, yc + font->height, col.activeRow); } for (nchannel = 0; nchannel < qwidth; nchannel++) { if (choffs + nchannel >= pat->nchannels) break; dmPrintNote(screen, x0 + lwidth + 4 + nchannel * cwidth, yc, pat->data + (pat->nchannels * nrow) + choffs + nchannel); } } } 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[]) { BOOL initSDL = FALSE; DMResource *file = NULL; JSSModule *mod = NULL; JSSMixer *dev = NULL; JSSPlayer *plr = NULL; SDL_AudioSpec afmt; int result = -1; memset(&afmt, 0, sizeof(afmt)); memset(&engine, 0, sizeof(engine)); engine.optScrWidth = 640; engine.optScrHeight = 480; engine.optScrDepth = 32; dmInitProg("ppl", "Penis Player", "0.1", NULL, NULL); // Parse arguments if (!dmArgsProcess(argc, argv, optList, optListN, argHandleOpt, argHandleFile, TRUE)) exit(1); // Open the files if (optFilename == NULL) { dmError("No filename specified.\n"); return 1; } if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) { dmError("Error opening file '%s', %d: (%s)\n", optFilename, errno, strerror(errno)); return 1; } // Initialize miniJSS jssInit(); // Read module file dmMsg(1, "Reading file: %s\n", optFilename); #ifdef JSS_SUP_XM dmMsg(2, "* Trying XM...\n"); result = jssLoadXM(file, &mod); #endif #ifdef JSS_SUP_JSSMOD if (result != 0) { size_t bufgot, bufsize = dmfsize(file); Uint8 *buf = dmMalloc(bufsize); dmfseek(file, 0L, SEEK_SET); dmMsg(2, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) { dmf_close(file); dmError("Error reading file (not enough data %d), #%d: %s\n", bufgot, dmferror(file), dmErrorStr(dmferror(file))); goto error_exit; } result = jssLoadJSSMOD(buf, bufsize, &mod); dmFree(buf); } #endif dmf_close(file); if (result != DMERR_OK) { dmError("Error loading module file, %d: %s\n", result, dmErrorStr(result)); goto error_exit; } // Try to convert it if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) { dmError("Could not convert module for playing, %d: %s\n", result, dmErrorStr(result)); goto error_exit; } if ((file = dmf_create_stdio(optFontFilename, "rb")) == NULL) { dmError("Error opening font file '%s', %d: %s\n", optFontFilename, errno, strerror(errno)); goto error_exit; } SDL_Surface *fontbmap = dmLoadImage(file); dmf_close(file); if (fontbmap == NULL) { dmError("Could not load image file '%s'.\n", optFontFilename); goto error_exit; } if ((result = dmCreateBitmapFontFromImage(fontbmap, 8, 8, &font)) != DMERR_OK) { dmError("Could not create a font from image, %d: %s\n", result, dmErrorStr(result)); goto error_exit; } SDL_FreeSurface(fontbmap); // Initialize SDL components if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) { dmError("Could not initialize SDL: %s\n", SDL_GetError()); goto error_exit; } initSDL = TRUE; // Initialize mixing device dmMsg(2, "Initializing miniJSS mixer with: %d, %d, %d\n", optOutFormat, optOutChannels, optOutFreq); dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); if (dev == NULL) { dmError("jvmInit() returned NULL\n"); goto error_exit; } switch (optOutFormat) { case JSS_AUDIO_S16: afmt.format = AUDIO_S16SYS; break; case JSS_AUDIO_U16: afmt.format = AUDIO_U16SYS; break; case JSS_AUDIO_S8: afmt.format = AUDIO_S8; break; case JSS_AUDIO_U8: afmt.format = AUDIO_U8; break; default: dmError("Unsupported audio format %d (could not set matching SDL format)\n", optOutFormat); goto error_exit; } afmt.freq = optOutFreq; afmt.channels = optOutChannels; afmt.samples = optOutFreq * optOutChannels * 4; afmt.callback = audioCallback; afmt.userdata = (void *) dev; // Open the audio device if (SDL_OpenAudio(&afmt, NULL) < 0) { dmError("Couldn't open SDL audio: %s\n", SDL_GetError()); goto error_exit; } // Initialize player if ((plr = jmpInit(dev)) == NULL) { dmError("jmpInit() returned NULL\n"); goto error_exit; } jvmSetCallback(dev, jmpExec, plr); jmpSetModule(plr, mod); jmpPlayOrder(plr, 0); jvmSetGlobalVol(dev, 60); // Initialize video if (!dmInitializeVideo()) goto error_exit; SDL_WM_SetCaption(dmProgDesc, dmProgName); // okay, main loop here ... "play" module and print out info SDL_PauseAudio(0); while (!engine.exitFlag && plr->isPlaying) { while (SDL_PollEvent(&engine.event)) switch (engine.event.type) { case SDL_KEYDOWN: switch (engine.event.key.keysym.sym) { case SDLK_ESCAPE: engine.exitFlag = TRUE; break; default: break; } break; case SDL_VIDEORESIZE: engine.optScrWidth = engine.event.resize.w; engine.optScrHeight = engine.event.resize.h; if (!dmInitializeVideo()) goto error_exit; break; case SDL_VIDEOEXPOSE: break; case SDL_QUIT: engine.exitFlag = TRUE; break; } // Draw frame if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0) { dmError("Can't lock surface.\n"); goto error_exit; } dmDrawBox3D(engine.screen, 0, 0, engine.screen->w - 1, engine.screen->h - 1, col.boxBg, col.box1, col.box2); dmDrawBMText(engine.screen, font, DMD_SATURATE, 5, 5, "%s v%s by ccr/TNSP - (c) Copyright 2012 TNSP", dmProgDesc, dmProgVersion); JSS_LOCK(dev); JSS_LOCK(plr); dmDrawBMText(engine.screen, font, DMD_SATURATE, 5, 5 + 9, "Tempo %3d | Speed: %3d | Row: %3d | Order: %d", plr->tempo, plr->speed, plr->row, plr->order ); dmDisplayPattern(engine.screen, 5, 30, engine.screen->w - 6, engine.screen->h - 10, plr->pattern, plr->row, 0); JSS_UNLOCK(plr); JSS_UNLOCK(dev); // Flip screen if (SDL_MUSTLOCK(engine.screen) != 0) SDL_UnlockSurface(engine.screen); SDL_Flip(engine.screen); SDL_Delay(10); } error_exit: SDL_PauseAudio(1); if (engine.screen) SDL_FreeSurface(engine.screen); SDL_LockAudio(); jmpClose(plr); jvmClose(dev); jssFreeModule(mod); SDL_UnlockAudio(); dmFreeBitmapFont(font); if (initSDL) SDL_Quit(); jssClose(); return 0; }