# HG changeset patch # User Matti Hamalainen # Date 1366120482 -10800 # Node ID 84811c6dd32da4a65b9092488a67e33b52f49711 # Parent 686c23d69aa2928a799241c9024686cf2d20afc8 Added Auval with removed Lua dependancy, using dmeval only. diff -r 686c23d69aa2 -r 84811c6dd32d Makefile.gen --- a/Makefile.gen Tue Apr 16 16:38:25 2013 +0300 +++ b/Makefile.gen Tue Apr 16 16:54:42 2013 +0300 @@ -122,6 +122,12 @@ DM_CFLAGS += -DDM_GFX_TTF_TEXT DMLIB_OBJS += dmtext_ttf.o +ifeq ($(DM_BUILD_TOOLS),yes) +ifeq ($(DM_GFX_BLITS),yes) +TOOL_BINARIES += auval +endif +endif + ifeq ($(DM_BUILD_TESTS),yes) ifeq ($(DM_GFX_BLITS),yes) ifeq ($(DM_USE_STDIO),yes) @@ -468,6 +474,10 @@ @echo " LINK $+" @$(CC) -o $@ $(filter %.o %.a,$+) $(DM_LDFLAGS) -lm +$(BINPATH)auval$(EXEEXT): $(OBJPATH)auval.o $(OBJPATH)dmeval.o $(DMLIB_A) + @echo " LINK $+" + @$(CC) -o $@ $(filter %.o %.a,$+) $(DM_LDFLAGS) $(SDL_LDFLAGS) -lSDL_ttf + ### ### Demo binary diff -r 686c23d69aa2 -r 84811c6dd32d tools/auval.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/auval.c Tue Apr 16 16:54:42 2013 +0300 @@ -0,0 +1,1150 @@ +#include "dmlib.h" +#include "dmargs.h" +#include "dmeval.h" +#include "dmtext.h" +#include + +#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 = 0xffffffff, +}; + + +typedef struct +{ + DMEvalNode *expr; + DMEvalContext *engine; + + char *errStr; + int err; + + double varTime, varFreq, varKeyTime, + varKeyTimeRev, varKeyFreq, varUnit; + + int avail, bufsize, pos, oldpos; + Uint8 *buf; + + SDL_mutex *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, + optAutoReturn = TRUE; + + +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); +} + + +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) + { + dmError("Invalid width or height: %d x %d\n", w, h); + return FALSE; + } + optScrWidth = w; + optScrHeight = h; + } + else + { + dmError("Invalid size argument '%s'.\n", optArg); + return FALSE; + } + } + else + { + dmError("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) + { + dmError("Invalid audio frequency '%s'.\n", optArg); + return FALSE; + } + optAudioFreq = tmp; + } + break; + + case 8: + { + int tmp = atoi(optArg); + if (tmp < 32 || tmp > 512) + { + dmError("Invalid bitmap size '%s'.\n", optArg); + return FALSE; + } + optBMPSize = tmp; + } + break; + + case 10: + optClipping = FALSE; + break; + + case 11: + optScale = FALSE; + break; + + default: + dmError("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) + { + dmError("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; + + SDL_LockMutex(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; + } + + SDL_UnlockMutex(data->mutex); +} + + +void au_vis_image(SDL_Surface *screen, AUAudioData *data) +{ + int y; + Uint8 *p = (Uint8 *) screen->pixels; + + SDL_LockMutex(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; + } + + SDL_UnlockMutex(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) + { + dmError("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) + { + dmError("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; + + SDL_LockMutex(data->mutex); + + data->avail = 0; + + if (data->err == 0) + { + while (data->avail < len && data->avail < data->bufsize) + { + double value; + + data->varKeyTimeRev = 1.0f - data->varKeyTime; + + if (dm_eval_exec(data->engine, 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->err == 0) + { + memcpy(buf, data->buf, len); + data->pos += len; + } + else + memset(buf, 0, len); + } + + SDL_UnlockMutex(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; + + memset(&audata, 0, sizeof(audata)); + + /* Parse arguments */ + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, FALSE)) + exit(1); + + + /* Allocate edit history buffers */ + histBuf = dmCalloc(sizeof(histBuf[0]), optHistoryLen + 2); + if (histBuf == NULL) + { + dmError("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 engine */ + audata.engine = dm_eval_new(); + audata.expr = NULL; + + dm_eval_add_var(audata.engine, "t", &audata.varTime); + dm_eval_add_var(audata.engine, "k", &audata.varKeyTime); + dm_eval_add_var(audata.engine, "q", &audata.varKeyTimeRev); + dm_eval_add_var(audata.engine, "f", &audata.varUnit); + + + /* Initialize SDL */ + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = TRUE; + + if (TTF_Init() < 0) + { + dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); + goto error_exit; + } + initTTF = TRUE; + + font = TTF_OpenFont(optFontFile, optFontSize); + if (font == NULL) + { + dmError("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) + { + dmError("Could not initialize SDL audio.\n"); + goto error_exit; + } + + audata.bufsize = optAudioFreq; + audata.buf = dmMalloc(audata.bufsize * sizeof(*audata.buf)); + audata.mutex = SDL_CreateMutex(); + 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; + 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_F7: + /* Toggle "auto return" for Lua mode */ + optAutoReturn = !optAutoReturn; + 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) + { + SDL_LockMutex(audata.mutex); + audata.varFreq = 1.0f; + audata.pos = 0; + audata.varTime = 0; + audata.varKeyTime = 0; + audata.varUnit = 0; + SDL_UnlockMutex(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; + + SDL_LockMutex(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; + SDL_UnlockMutex(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; + + SDL_LockMutex(audata.mutex); + + DMEvalNode *tmp = NULL; + dm_eval_free(audata.expr); + audata.expr = NULL; + + audata.err = dm_eval_parse_expr(audata.engine, editBuf->data, &tmp); + if (audata.err == 0) + audata.err = dm_eval_reorder(audata.engine, tmp, &audata.expr); + + dm_eval_free(tmp); + + audata.pos = 0; + audata.varTime = 0; + audata.varFreq = 1.0f; + audata.varKeyTime = 0; + audata.varUnit = 0; + + SDL_UnlockMutex(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) + { + dmError("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 | %s", + optClipping ? "CLIPPED" : "WRAPPED", + optScale ? "0.0-1.0" : "0 - 255", + optAutoReturn ? "RETURN" : "no ret", + 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) + { + SDL_LockMutex(audata.mutex); + + dmFillBox3D(screen, 0, eh - 15, screen->w - 1, screen->h - 1, + audata.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.errStr != NULL) + dmDrawTTFTextConst(screen, font, fontcol, 5, screen->h - fh, audata.errStr); + + SDL_UnlockMutex(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 (screen) + SDL_FreeSurface(screen); + + if (font) + TTF_CloseFont(font); + + if (audioPlaying) + SDL_PauseAudio(1); + + SDL_DestroyMutex(audata.mutex); + + if (initSDL) + SDL_Quit(); + + if (initTTF) + TTF_Quit(); + + return 0; +}