Mercurial > hg > dmlib
view tools/auval.c @ 1291:2c4acbc3e7bf
More work on libgfx etc.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 18 Aug 2017 18:56:09 +0300 |
parents | 5b8245e5f785 |
children | 2260ed90ab6b |
line wrap: on
line source
#include "dmlib.h" #include "dmargs.h" #include "dmeval.h" #include "dmtext.h" #include <math.h> #define AUVAL_NAME "AuVal" #define AUVAL_VERSION "0.6" #define AUVAL_TMPBUF_SIZE (4096) #define AUVAL_HISTORY_FILE "history.txt" #define AUVAL_HISTORY_USER "formulas.txt" #define SDL_NCOLORS 256 enum { REDRAW_VISUALIZER = 0x00000001, REDRAW_EDITOR = 0x00000002, REDRAW_INFO = 0x00000004, REDRAW_ALL = 0x0fffffff, }; typedef struct { DMEvalNode *expr; DMEvalContext *ctx; double varTime, varFreq, varKeyTime, varKeyTimeRev, varKeyFreq, varUnit; int avail, bufsize, pos, oldpos; Uint8 *buf; DMMutex *mutex; } AUAudioData; char *optFontFile = "font.ttf"; int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE, optScrWidth = 640, optScrHeight = 480, optScrDepth = 32, optFontSize = 20, optAudioFreq = 44100, optBMPSize = 32, optHistoryLen = 64; BOOL optClipping = TRUE, optScale = TRUE; static const DMOptArg optList[] = { { 0, '?', "help", "Show this help", OPT_NONE }, { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, { 3, 0, "fs", "Fullscreen", OPT_NONE }, { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, { 6, 'd', "depth", "Color depth of mode/window in bits (8/15/16/32)", OPT_ARGREQ }, { 7, 'f', "freq", "Audio output frequency", OPT_ARGREQ }, { 8, 'b', "bmpsize", "Bitmap size", OPT_ARGREQ }, {10, 'n', "noclip", "Disable clipping by default", OPT_NONE }, {11, 'r', "range", "Use range [0, 255] instead of [0.0, 1.0]", OPT_NONE }, }; const int optListN = sizeof(optList) / sizeof(optList[0]); void argShowHelp() { printf("%s v%s\n(C) Copyright 2011 ccr/TNSP\n", AUVAL_NAME, AUVAL_VERSION); dmArgsPrintHelp(stdout, optList, optListN, 0); } BOOL argHandleOpt(const int optN, char *optArg, char *currArg) { switch (optN) { case 0: argShowHelp(); exit(0); break; case 2: dmVerbosity++; break; case 3: optVFlags |= SDL_FULLSCREEN; break; case 5: if (optArg) { int w, h; if (sscanf(optArg, "%dx%d", &w, &h) == 2) { if (w < 320 || h < 200 || w > 3200 || h > 3200) { dmErrorMsg("Invalid width or height: %d x %d\n", w, h); return FALSE; } optScrWidth = w; optScrHeight = h; } else { dmErrorMsg("Invalid size argument '%s'.\n", optArg); return FALSE; } } else { dmErrorMsg("Dimensions option %s requires an argument.\n", currArg); } break; case 6: optScrDepth = atoi(optArg); break; case 7: { int tmp = atoi(optArg); if (tmp < 4000 || tmp > 96000) { dmErrorMsg("Invalid audio frequency '%s'.\n", optArg); return FALSE; } optAudioFreq = tmp; } break; case 8: { int tmp = atoi(optArg); if (tmp < 32 || tmp > 512) { dmErrorMsg("Invalid bitmap size '%s'.\n", optArg); return FALSE; } optBMPSize = tmp; } break; case 10: optClipping = FALSE; break; case 11: optScale = FALSE; break; default: dmErrorMsg("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } typedef struct { ssize_t pos, len, size; char *data; BOOL dirty; } AUEditBuf; int au_editbuf_write(AUEditBuf *buf, ssize_t pos, int ch) { if (buf->len+1 >= buf->size) return -3; if (pos < 0) return -1; else if (pos >= buf->len) { buf->data[buf->len++] = ch; } else { buf->data[pos] = ch; } buf->dirty = TRUE; return 0; } int au_editbuf_insert(AUEditBuf *buf, ssize_t pos, int ch) { if (buf->len+1 >= buf->size) return -3; if (pos < 0) return -1; else if (pos >= buf->len) { buf->data[buf->len] = ch; } else { memmove(&(buf->data[pos+1]), &(buf->data[pos]), buf->len - pos + 1); buf->data[pos] = ch; } buf->len++; buf->dirty = TRUE; return 0; } int au_editbuf_delete(AUEditBuf *buf, ssize_t pos) { if (pos < 0) return -1; else if (pos < buf->len) { memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos); buf->len--; buf->dirty = TRUE; return 0; } else return -2; } void au_editbuf_clear(AUEditBuf *buf) { buf->len = 0; buf->pos = 0; buf->dirty = TRUE; } AUEditBuf * au_editbuf_new(ssize_t n) { AUEditBuf *res = dmCalloc(1, sizeof(AUEditBuf)); res->data = (char *) dmMalloc(n); res->size = n; res->dirty = TRUE; return res; } AUEditBuf * au_editbuf_new_str(ssize_t n, const char *str) { AUEditBuf *res = au_editbuf_new(n); strncpy(res->data, str, res->size); res->data[res->size - 1] = 0; res->pos = res->len = strlen(res->data); return res; } void au_editbuf_free(AUEditBuf *buf) { if (buf != NULL) { dmFree(buf->data); dmFree(buf); } } AUEditBuf * au_editbuf_copy(AUEditBuf *src) { AUEditBuf *res; if (src == NULL) return NULL; if ((res = au_editbuf_new(src->size)) == NULL) return NULL; memcpy(res->data, src->data, src->size); res->pos = res->len = src->len; res->dirty = TRUE; return res; } char * au_editbuf_get_string(AUEditBuf *buf, ssize_t start, ssize_t end) { char *str; ssize_t siz; if (buf == NULL) return NULL; if (start < 0 || end > buf->len || start >= buf->len) return NULL; if (end < 0) { siz = buf->len - start + 1; } else if (start <= end) { siz = end - start + 1; } else return NULL; if ((str = dmMalloc(siz + 1)) == NULL) return NULL; memcpy(str, buf->data + start, siz); str[siz] = 0; return str; } void au_editbuf_setpos(AUEditBuf *buf, ssize_t pos) { if (pos < 0) buf->pos = 0; else if (pos >= buf->len) buf->pos = buf->len; else buf->pos = pos; } BOOL au_init_video(SDL_Surface **screen) { *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); if (*screen == NULL) { dmErrorMsg("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); return FALSE; } return TRUE; } void au_draw_editbuf(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int xc, int yc, int w, int h, AUEditBuf *buf, int curcol) { ssize_t left, maxlen, pos; int strw, strh, y1 = yc + h; char *line = NULL, *ptr; if (buf == NULL) return; if (TTF_SizeText(font, "X", &strw, &strh) != 0) goto error; maxlen = w / strw; line = dmMalloc(maxlen + 2); pos = 0; left = buf->len; ptr = buf->data; do { ssize_t ppos = buf->pos - pos; if (ppos >= 0 && ppos < maxlen) { int x0 = xc + ppos * strw; dmFillRect(screen, x0, yc, x0 + strw, yc + strh, curcol); } else if ((buf->pos % maxlen) == 0) { dmFillRect(screen, xc, yc + strh, xc + strw, yc + strh + strh, curcol); } ssize_t len = left > maxlen ? maxlen : left; strncpy(line, ptr, len); line[len] = 0; dmDrawTTFTextConst(screen, font, col, xc, yc, line); left -= len; ptr += len; pos += len; yc += strh; } while (left > 0 && yc < y1); error: dmFree(line); } void au_vis_wave(SDL_Surface *screen, int x0, int y0, int x1, int y1, AUAudioData *data) { int x, offs; const int height = y1 - y0, center = y0 + (height / 2); const int pitch = screen->pitch, bpp = screen->format->BytesPerPixel; const int xend = x1 * bpp; const float scale = 128.0f / (float) height; dmMutexLock(data->mutex); Uint8 *dp = data->buf, *sp = screen->pixels; for (offs = 0, x = x0 * bpp; x < xend && offs < data->avail; x += bpp, offs++) { const int curr = center + ((dp[offs] - 128) * scale); sp[x + curr * pitch] = 255; } dmMutexUnlock(data->mutex); } void au_vis_image(SDL_Surface *screen, AUAudioData *data) { int y; Uint8 *p = (Uint8 *) screen->pixels; dmMutexLock(data->mutex); Uint8 *dp = data->buf; for (y = 0; y < screen->h; y++) { int x; for (x = 0; x < screen->w; x++) *p++ = *dp++; p += screen->pitch - screen->w; } dmMutexUnlock(data->mutex); } int au_get_note_from_key(SDL_keysym *key, int octave) { int note; switch (key->sym) { case SDLK_z: note = 1; break; case SDLK_s: note = 2; break; case SDLK_x: note = 3; break; case SDLK_d: note = 4; break; case SDLK_c: note = 5; break; case SDLK_v: note = 6; break; case SDLK_g: note = 7; break; case SDLK_b: note = 8; break; case SDLK_h: note = 9; break; case SDLK_n: note = 10; break; case SDLK_j: note = 11; break; case SDLK_m: note = 12; break; case SDLK_q: note = 13; break; case SDLK_2: note = 14; break; case SDLK_w: note = 15; break; case SDLK_3: note = 16; break; case SDLK_e: note = 17; break; case SDLK_r: note = 18; break; case SDLK_5: note = 19; break; case SDLK_t: note = 20; break; case SDLK_6: note = 21; break; case SDLK_y: note = 22; break; case SDLK_7: note = 23; break; case SDLK_u: note = 24; break; case SDLK_i: note = 25; break; case SDLK_9: note = 26; break; case SDLK_o: note = 27; break; case SDLK_0: note = 28; break; case SDLK_p: note = 29; break; default: return -1; } note += 12 * octave; return (note < 1) ? 1 : (note > 120 ? 120 : note); } void au_adjust_value(int *val, int min, int max, int delta) { *val += delta; if (*val < min) *val = min; else if (*val > max) *val = max; } int au_read_history(const char *filename, AUEditBuf **history, int maxHistory, int *histMax) { char tmpStr[1024]; int i; FILE *f = fopen(filename, "r"); if (f == NULL) { dmErrorMsg("Could not open input file '%s'.\n", filename); return -1; } while (fgets(tmpStr, sizeof(tmpStr), f) != NULL) { /* Strip the string end from linefeeds etc. */ for (i = 0; tmpStr[i] != 0 && i < 512; i++); while (--i >= 0 && (tmpStr[i] == '\n' || tmpStr[i] == '\r' || isspace(tmpStr[i]))) tmpStr[i] = 0; /* Add to history only if it's not an empty line */ if (tmpStr[0] != 0) { au_editbuf_free(history[maxHistory + 1]); history[maxHistory + 1] = NULL; memmove(&history[2], &history[1], maxHistory * sizeof(history[0])); history[1] = au_editbuf_new_str(AUVAL_TMPBUF_SIZE, tmpStr); if (*histMax < maxHistory) (*histMax)++; } } fclose(f); return 0; } int au_save_history(const char *filename, AUEditBuf **history, int histMax) { int i; FILE *f = fopen(filename, "w"); if (f == NULL) { dmErrorMsg("Could not create output file '%s'.\n", filename); return -1; } for (i = histMax; i >= 0; i--) { AUEditBuf *buf = history[i]; if (buf != NULL) { buf->data[buf->len] = 0; fprintf(f, "%s\n", buf->data); } } fclose(f); return 0; } /* SDL audio callback. We do the actual rendering here, by setting * Lua variables and calling Lua evaluation function to generate samples. * * Mutex locking is used to ensure that the variables are not improperly * accessed. */ void au_sdl_audio_fill(void *udata, Uint8 *buf, int len) { AUAudioData *data = (AUAudioData *) udata; dmMutexLock(data->mutex); data->avail = 0; if (!data->ctx->err) { while (data->avail < len && data->avail < data->bufsize) { double value; data->varKeyTimeRev = 1.0f - data->varKeyTime; if (dmEvalTreeExecute(data->ctx, data->expr, &value) != 0) break; if (optScale) { if (optClipping) value = ((value < -1.0f) ? -1.0f : ((value > 1.0f) ? 1.0f : value)); value = 128 + (value * 126); } else { if (optClipping) value = ((value < 0) ? 0 : ((value > 255) ? 255 : value)); } data->buf[data->avail++] = value; data->varTime += data->varFreq; data->varUnit += data->varKeyFreq; data->varKeyTime += data->varKeyFreq; if (data->varKeyTime > 1.0f) data->varKeyTime = 1.0f; } if (data->avail >= len && !data->ctx->err) { memcpy(buf, data->buf, len); data->pos += len; } else dmMemset(buf, 0, len); } dmMutexUnlock(data->mutex); } int main(int argc, char *argv[]) { AUEditBuf *editBuf = au_editbuf_new(AUVAL_TMPBUF_SIZE); AUEditBuf **histBuf = NULL; int histPos = 0, histMax = 0, viewMode; SDL_Surface *screen = NULL, *bmp = NULL; TTF_Font *font = NULL; SDL_Color fontcol = {255,255,255, 0}; SDL_Event event; SDL_AudioSpec fmt; AUAudioData audata; int needRedraw; BOOL initSDL = FALSE, initTTF = FALSE, exitFlag, insertMode, audioPlaying = FALSE, jazzMode; dmMemset(&audata, 0, sizeof(audata)); /* Parse arguments */ if (!dmArgsProcess(argc, argv, optList, optListN, argHandleOpt, NULL, 0)) exit(1); /* Allocate edit history buffers */ histBuf = dmCalloc(sizeof(histBuf[0]), optHistoryLen + 2); if (histBuf == NULL) { dmErrorMsg("Could not allocate memory for edit history buffer!\n"); goto error_exit; } /* Read in history file, if any exists */ au_read_history(AUVAL_HISTORY_FILE, histBuf, optHistoryLen, &histMax); /* Initialize evaluator ctx */ audata.ctx = dmEvalContextNew(); audata.expr = NULL; dmEvalContextAddVar(audata.ctx, "t", &audata.varTime); dmEvalContextAddVar(audata.ctx, "k", &audata.varKeyTime); dmEvalContextAddVar(audata.ctx, "q", &audata.varKeyTimeRev); dmEvalContextAddVar(audata.ctx, "f", &audata.varUnit); /* Initialize SDL */ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) != 0) { dmErrorMsg("Could not initialize SDL: %s\n", SDL_GetError()); goto error_exit; } initSDL = TRUE; if (TTF_Init() < 0) { dmErrorMsg("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); goto error_exit; } initTTF = TRUE; font = TTF_OpenFont(optFontFile, optFontSize); if (font == NULL) { dmErrorMsg("Could not load TTF font '%s' (%d): %s\n", optFontFile, optFontSize, SDL_GetError()); goto error_exit; } TTF_SetFontStyle(font, TTF_STYLE_NORMAL); if (!au_init_video(&screen)) goto error_exit; SDL_WM_SetCaption(AUVAL_NAME " v" AUVAL_VERSION, AUVAL_NAME); SDL_EnableUNICODE(1); SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); /* Initialize audio */ fmt.freq = optAudioFreq; fmt.format = AUDIO_U8; fmt.channels = 1; fmt.samples = 512; fmt.callback = au_sdl_audio_fill; fmt.userdata = &audata; if (SDL_OpenAudio(&fmt, NULL) < 0) { dmErrorMsg("Could not initialize SDL audio.\n"); goto error_exit; } audata.bufsize = optAudioFreq; audata.buf = dmMalloc(audata.bufsize * sizeof(*audata.buf)); audata.mutex = dmCreateMutex(); audata.varTime = 0; audata.varKeyFreq = 1.0f / (double) optAudioFreq; SDL_PauseAudio(0); SDL_PauseAudio(1); /* Create visualizer bitmap surface */ bmp = SDL_CreateRGBSurface(SDL_SWSURFACE, optBMPSize, optBMPSize, 8, 0, 0, 0, 0); SDL_Color pal[SDL_NCOLORS]; int n; for (n = 0; n < SDL_NCOLORS; n++) { pal[n].r = n; pal[n].g = n; pal[n].b = n; } SDL_SetColors(bmp, pal, 0, SDL_NCOLORS); /* Misc inits */ au_editbuf_clear(editBuf); needRedraw = REDRAW_ALL; exitFlag = FALSE; insertMode = TRUE; jazzMode = FALSE; viewMode = 0; /* Enter mainloop */ while (!exitFlag) { /* Handle events */ while (SDL_PollEvent(&event)) switch (event.type) { case SDL_KEYDOWN: { /* Get key event modifiers into handy booleans */ BOOL modCtrl = event.key.keysym.mod & KMOD_CTRL, modShift = event.key.keysym.mod & KMOD_SHIFT; switch (event.key.keysym.sym) { case SDLK_F1: audioPlaying = !audioPlaying; SDL_PauseAudio(!audioPlaying); needRedraw |= REDRAW_ALL; break; case SDLK_F2: audata.varTime = 0; audata.varKeyTime = 0; needRedraw |= REDRAW_ALL; break; case SDLK_F4: optClipping = !optClipping; needRedraw |= REDRAW_VISUALIZER; break; case SDLK_F5: /* Toggle audio scaling / range between [0.0, 1.0] and [0, 255] */ optScale = !optScale; needRedraw |= REDRAW_VISUALIZER; break; case SDLK_F6: viewMode = (viewMode + 1) % 2; needRedraw |= REDRAW_VISUALIZER; break; case SDLK_F8: /* Toggle keyboard jazz mode */ jazzMode = !jazzMode; needRedraw |= REDRAW_VISUALIZER; break; case SDLK_F9: /* Save history to file */ au_save_history(AUVAL_HISTORY_USER, histBuf, histMax); break; case SDLK_ESCAPE: exitFlag = TRUE; break; case SDLK_RETURN: /* Add to history buffer */ if (!jazzMode && editBuf->len > 0) { if (histMax > 0) { au_editbuf_free(histBuf[optHistoryLen+1]); histBuf[optHistoryLen+1] = NULL; memmove(&histBuf[2], &histBuf[1], histMax * sizeof(histBuf[0])); } histPos = 0; histBuf[1] = au_editbuf_copy(editBuf); if (histMax < optHistoryLen) histMax++; au_editbuf_insert(editBuf, editBuf->len, 0); /* You could do something here with the data ... */ //result = handleUserInput(conn, editBuf->data, editBuf->len); au_editbuf_clear(editBuf); } break; case SDLK_UP: /* Backwards in input history */ if (jazzMode) break; if (histPos == 0) { au_editbuf_free(histBuf[0]); histBuf[0] = au_editbuf_copy(editBuf); } if (histPos < histMax) { histPos++; au_editbuf_free(editBuf); editBuf = au_editbuf_copy(histBuf[histPos]); } break; case SDLK_DOWN: /* Forwards in input history */ if (jazzMode) break; if (histPos > 0) { histPos--; au_editbuf_free(editBuf); editBuf = au_editbuf_copy(histBuf[histPos]); } break; case SDLK_LEFT: if (jazzMode) break; /* ctrl+left arrow = Skip words left */ if (modCtrl) { while (editBuf->pos > 0 && isspace((int) editBuf->data[editBuf->pos - 1])) editBuf->pos--; while (editBuf->pos > 0 && !isspace((int) editBuf->data[editBuf->pos - 1])) editBuf->pos--; } else { au_editbuf_setpos(editBuf, editBuf->pos - 1); } break; case SDLK_RIGHT: if (jazzMode) break; /* ctrl+right arrow = Skip words right */ if (modCtrl) { while (editBuf->pos < editBuf->len && isspace((int) editBuf->data[editBuf->pos])) editBuf->pos++; while (editBuf->pos < editBuf->len && !isspace((int) editBuf->data[editBuf->pos])) editBuf->pos++; } else { au_editbuf_setpos(editBuf, editBuf->pos + 1); } break; case SDLK_HOME: if (jazzMode) break; au_editbuf_setpos(editBuf, 0); break; case SDLK_END: if (jazzMode) break; au_editbuf_setpos(editBuf, editBuf->len); break; case SDLK_BACKSPACE: if (jazzMode) break; au_editbuf_delete(editBuf, editBuf->pos - 1); au_editbuf_setpos(editBuf, editBuf->pos - 1); break; case SDLK_DELETE: /* Delete character */ if (jazzMode) break; au_editbuf_delete(editBuf, editBuf->pos); break; case SDLK_INSERT: /* Ins = Toggle insert / overwrite mode */ if (jazzMode) break; insertMode = !insertMode; break; default: if (jazzMode) { int key = event.key.keysym.unicode; /* In keyboard jazz-mode, space stops playing */ if (key == SDLK_SPACE) { dmMutexLock(audata.mutex); audata.varFreq = 1.0f; audata.pos = 0; audata.varTime = 0; audata.varKeyTime = 0; audata.varUnit = 0; dmMutexUnlock(audata.mutex); audioPlaying = FALSE; SDL_PauseAudio(!audioPlaying); break; } else { /* Calculate note based on key */ int period, note = au_get_note_from_key(&event.key.keysym, 4); if (note > 0) { period = 7680 - (note * 64) - (/* finetune */ 128 / 2); if (period < 1) period = 1; dmMutexLock(audata.mutex); audata.varFreq = 8363.0f * pow(2.0f, (4608.0f - (double) period) / 768.0f) / optAudioFreq ; audata.pos = 0; audata.varTime = 0; audata.varKeyTime = 0; audata.varUnit = 0; dmMutexUnlock(audata.mutex); audioPlaying = TRUE; SDL_PauseAudio(!audioPlaying); } } needRedraw |= REDRAW_VISUALIZER; } else { int key = event.key.keysym.unicode; if (isprint(key)) { if (insertMode) au_editbuf_insert(editBuf, editBuf->pos, key); else au_editbuf_write(editBuf, editBuf->pos, key); au_editbuf_setpos(editBuf, editBuf->pos + 1); } } break; } } needRedraw |= REDRAW_EDITOR | REDRAW_INFO; break; case SDL_VIDEORESIZE: /* Window resized, reinit video etc */ optScrWidth = event.resize.w; optScrHeight = event.resize.h; if (!au_init_video(&screen)) goto error_exit; needRedraw = REDRAW_ALL; break; case SDL_VIDEOEXPOSE: /* Window exposed, redraw everything just to be sure */ needRedraw = REDRAW_ALL; break; case SDL_QUIT: goto error_exit; } /* If formula has changed, update evaluation variables and load the * expression into Lua. Check for errors. The actual expression * evaluation is done in the audio rendering callback. */ if (!jazzMode && editBuf->len > 0 && editBuf->dirty) { editBuf->dirty = FALSE; editBuf->data[editBuf->len] = 0; dmMutexLock(audata.mutex); dmEvalTreeFree(audata.expr); audata.expr = NULL; audata.ctx->err = dmEvalParseExpr(audata.ctx, editBuf->data, &audata.expr); dmEvalPrintOpTree(stdout, audata.ctx, audata.expr); printf("--\n"); audata.pos = 0; audata.varTime = 0; audata.varFreq = 1.0f; audata.varKeyTime = 0; audata.varUnit = 0; dmMutexUnlock(audata.mutex); } /* Check if visualizer needs redrawing */ if (audata.pos != audata.oldpos) { audata.oldpos = audata.pos; needRedraw |= REDRAW_VISUALIZER; } /* Redraw screen, if needed */ if (needRedraw) { if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) { dmErrorMsg("Can't lock surface"); goto error_exit; } /* Clear the surface, draw copyright etc */ int fh = TTF_FontHeight(font); int eh = screen->h - fh * 4; if (needRedraw & REDRAW_INFO) { dmFillBox3D(screen, 0, 0, screen->w - 1, fh + 5, dmMapRGB(screen, 50, 50, 150), dmMapRGB(screen, 150,150,250), dmMapRGB(screen, 25,25,50)); dmDrawTTFTextConst(screen, font, fontcol, 5, 2, AUVAL_NAME " v" AUVAL_VERSION " (C) Copyright 2013 ccr/TNSP"); dmFillBox3D(screen, 0, eh - 25 - fh, screen->w - 1, eh - 16, dmMapRGB(screen, 50, 50, 150), dmMapRGB(screen, 150,150,250), dmMapRGB(screen, 25,25,50)); dmDrawTTFText(screen, font, fontcol, 5, eh - fh - 20, "%s | [%-8s] | %s", optClipping ? "CLIPPED" : "WRAPPED", optScale ? "0.0-1.0" : "0 - 255", jazzMode ? "jazz" : "edit"); } /* Draw the visualizer, based on the current mode*/ if (needRedraw & REDRAW_VISUALIZER) { char *vms; dmFillRect(screen, 0, fh + 6, screen->w - 1, eh - fh - 27, dmMapRGB(screen, 15, 15, 15)); switch (viewMode) { case 0: au_vis_wave(screen, 5, fh * 2 + 15, screen->w - 5, eh - 20, &audata); vms = "scope"; break; case 1: au_vis_image(bmp, &audata); dmScaledBlitSurfaceAny(bmp, 5, fh * 2 + 15, screen->w - 10, eh - fh * 2 - 30, screen, DMD_NONE); vms = "bitmap"; break; default: vms = "?"; } dmDrawTTFText(screen, font, fontcol, 5, fh + 10, "%s | %s | f=%dHz | t=%-8.1f", audioPlaying ? "PLAYING" : "STOPPED", vms, optAudioFreq, audata.varTime ); } /* Draw the function editor box */ if (needRedraw & REDRAW_EDITOR) { dmMutexLock(audata.mutex); dmFillBox3D(screen, 0, eh - 15, screen->w - 1, screen->h - 1, audata.ctx->err ? dmMapRGB(screen, 255, 0, 0) : dmMapRGB(screen, 0, 128, 64), dmMapRGB(screen, 200, 255, 200), 100); au_draw_editbuf(screen, font, fontcol, 5, eh - 10, screen->w - 10, eh - 15, editBuf, dmMapRGB(screen, 0, 0, 150)); if (audata.ctx->err && audata.ctx->errStr != NULL) dmDrawTTFTextConst(screen, font, fontcol, 5, screen->h - fh, audata.ctx->errStr); dmMutexUnlock(audata.mutex); } if (SDL_MUSTLOCK(screen) != 0) SDL_UnlockSurface(screen); SDL_Flip(screen); needRedraw = 0; } SDL_Delay(50); } /* Save history */ au_save_history(AUVAL_HISTORY_FILE, histBuf, histMax); error_exit: if (font) TTF_CloseFont(font); if (audioPlaying) SDL_PauseAudio(1); dmDestroyMutex(audata.mutex); if (initSDL) SDL_Quit(); if (initTTF) TTF_Quit(); return 0; }