diff --git a/CMakeLists.txt b/CMakeLists.txt index fd569ee..6e3f510 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,14 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) project(trakker) SET(CMAKE_CXX_STANDARD 17) SET(CMAKE_CXX_STANDARD_REQUIRED True) +SET(CMAKE_CXX_FLAGS "-O3") +include_directories(${CMAKE_BINARY_DIR}) +find_package(Git) find_package(ALSA REQUIRED) -#find_package(xmp REQUIRED) +find_package(LIBXMP REQUIRED) find_package(Curses REQUIRED) add_subdirectory(src) +add_custom_target(version ${CMAKE_COMMAND} -D SRC=${CMAKE_SOURCE_DIR}/src/trakker_version.h.in -D DST=${CMAKE_BINARY_DIR}/trakker_version.h -D GIT_EXECUTABLE=${GIT_EXECUTABLE} -P ${CMAKE_SOURCE_DIR}/GenerateVersionHeader.cmake) +add_dependencies(trakker version) install(TARGETS trakker RUNTIME DESTINATION bin) diff --git a/GenerateVersionHeader.cmake b/GenerateVersionHeader.cmake new file mode 100644 index 0000000..a46f55e --- /dev/null +++ b/GenerateVersionHeader.cmake @@ -0,0 +1,23 @@ +if(GIT_EXECUTABLE) + get_filename_component(SRC_DIR ${SRC} DIRECTORY) + # Generate a git-describe version string from Git repository tags + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --always + WORKING_DIRECTORY ${SRC_DIR} + OUTPUT_VARIABLE GIT_DESCRIBE_VERSION + RESULT_VARIABLE GIT_DESCRIBE_ERROR_CODE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(NOT GIT_DESCRIBE_ERROR_CODE) + set(TRAKKER_VERSION ${GIT_DESCRIBE_VERSION}) + endif() +endif() + +# Final fallback: Just use a bogus version string that is semantically older +# than anything else and spit out a warning to the developer. +if(NOT DEFINED TRAKKER_VERSION) + set(TRAKKER_VERSION v0.0.0-unknown) + message(WARNING "Failed to determine TRAKKER_VERSION from Git tags. Using default version \"${TRAKKER_VERSION}\".") +endif() + +configure_file(${SRC} ${DST} @ONLY) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c109a44..6a376d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,4 @@ add_executable(trakker main.cpp ) - target_link_libraries(trakker PUBLIC ALSA::ALSA xmp ${CURSES_LIBRARY}) \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5c1fada..7126d85 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,375 +1,467 @@ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include +#include #include #include #include +#include "trakker_version.h" -#define VERSION "0.3.1" #define SAMPLERATE 48000 #define BUFFER_SIZE 250000 static char *note_name[] = { "C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B " }; +static char* pages[] = { "[1] Info", "[2] Pattern", "[3] Channel Bars", "[4] Visualizer", "[5] About" }; +static char* device = "default"; + +int display = 0; +int mode = 0; +int vol; +int hMin = 0; int hMax = 2048; +int hOffset = 0; +int vMin = 0; int vMax = 2048; +int vOffset = 0; +int looped = 0; +bool stopped; +bool loop; + +WINDOW *dis; +WINDOW *tab; +void destroyWindows(); +void createWindows(); +void renderInfo(xmp_module_info *mi, xmp_frame_info *fi); +void renderAbout(); +void renderTrack(xmp_module_info *mi, xmp_frame_info *fi); +void renderRows(xmp_module_info *mi, xmp_frame_info *fi); +void renderChannels(xmp_module_info *mi, xmp_frame_info *fi); +void renderInstruments(xmp_module_info *mi, xmp_frame_info *fi); -void updateTrack(char* name, char* type); -void renderTrack(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi); -void renderRows(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi); -void renderChannels(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi); -void renderInstruments(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi); char getEffectType(int i); - -static char *device = "default"; -int chanOffset = 0; int insOffset = 0; int detail = 2; int vol = 100; int loop_times = 0; -bool looper = false, is_stopped = false; int main(int argc, char *argv[]) { - printf("Trakker %s (with libxmp %s)\n", VERSION, xmp_version); - int time, key, err, row, pos; - bool fupdate = false; - snd_pcm_t *handle; + int err; + snd_pcm_t *handle; snd_pcm_sframes_t frames; if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { - printf("Playback open error: %s\n", snd_strerror(err)); + fprintf(stderr, "Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 2, SAMPLERATE, 1, BUFFER_SIZE)) < 0) { - printf("Playback open error: %s\n", snd_strerror(err)); + fprintf(stderr, "Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } - printf("Using Audio Driver: %s\n", "ALSA"); + printf("%s initialized.\n", "ALSA"); - xmp_context c; - c = xmp_create_context(); - if (xmp_load_module(c, argv[1]) != 0) { - fprintf(stderr, "Failed to load Module: %s\n", argv[1]); - exit(EXIT_FAILURE); + xmp_context xc; + xc = xmp_create_context(); + if (xmp_load_module(xc, argv[1]) != 0) { + fprintf(stderr, "Failed to load Module: %s\n", argv[1]); + exit(EXIT_FAILURE); } - struct xmp_module_info mi; - struct xmp_frame_info fi; + struct xmp_module_info xmi; + struct xmp_frame_info xfi; - printf("Loaded module: %s\n", argv[1]); + printf("Loading Module: \"%s\"\n", argv[1]); - WINDOW *win; initscr(); - if (LINES < 5 || COLS < 5) { - endwin(); - fprintf(stderr, "ncurses failed: Display is too small.\n"); - exit(EXIT_FAILURE); + if (has_colors() == TRUE) { + start_color(); + if (can_change_color() == TRUE) { + // Primary Background + init_pair(1, COLOR_BLACK, 8); + // Inactive Section + init_pair(2, 8, 7); + // Active Section + init_pair(3, 0, 12); + // Display + init_pair(4, 7, COLOR_BLACK); + // Display Row# + init_pair(5, 3, COLOR_BLACK); + // Display Playhead + init_pair(6, COLOR_WHITE, COLOR_BLUE); + // Display Playhead Row# + init_pair(7, COLOR_YELLOW, COLOR_BLUE); + // Display Stopped Playhead + init_pair(8, COLOR_WHITE, COLOR_RED); + // Display Stopped Playhead Row# + init_pair(9, COLOR_YELLOW, COLOR_RED); + } else { + // Primary Background + init_pair(1, COLOR_BLACK, 8); + // Inactive Section + init_pair(2, COLOR_BLACK, COLOR_WHITE); + // Active Section + init_pair(3, COLOR_BLACK, COLOR_CYAN); + // Display + init_pair(4, COLOR_WHITE, COLOR_BLACK); + // Display Row# + init_pair(5, COLOR_YELLOW, COLOR_BLACK); + // Display Playhead + init_pair(6, COLOR_WHITE, COLOR_BLUE); + // Display Playhead Row# + init_pair(7, COLOR_YELLOW, COLOR_BLUE); + // Display Stopped Playhead + init_pair(8, COLOR_WHITE, COLOR_RED); + // Display Stopped Playhead Row# + init_pair(9, COLOR_YELLOW, COLOR_RED); + } + } else { + // Primary Background + init_pair(1, COLOR_BLACK, COLOR_BLACK); + // Inactive Section + init_pair(2, COLOR_WHITE, COLOR_BLACK); + // Active Section + init_pair(3, COLOR_BLACK, COLOR_WHITE); + // Display + init_pair(4, COLOR_WHITE, COLOR_BLACK); + // Display Row# + init_pair(5, COLOR_WHITE, COLOR_BLACK); + // Display Playhead + init_pair(6, COLOR_BLACK, COLOR_WHITE); + // Display Playhead Row# + init_pair(7, COLOR_BLACK, COLOR_WHITE); + // Display Stopped Playhead + init_pair(8, COLOR_WHITE, COLOR_BLACK); + // Display Stopped Playhead Row# + init_pair(9, COLOR_WHITE, COLOR_BLACK); } - if(has_colors() == FALSE) { - endwin(); - fprintf(stderr, "ncurses failed: No color support.\n"); - exit(EXIT_FAILURE); - } - start_color(); - - if (can_change_color() == TRUE) { - init_color(COLOR_BLACK, 0, 0, 0); - } else { printf("Color changing not supported!\n"); } - - init_pair(1, COLOR_WHITE, COLOR_BLUE); // PLAYHEAD - init_pair(2, COLOR_WHITE, COLOR_RED); // PAUSED - cbreak(); noecho(); curs_set(0); - - win = newwin(LINES-2, COLS-2, 1, 1); - keypad(win, TRUE); - wmove(win, 0, 0); - wprintw(win, ""); - printf("Loaded ncurses display.\n"); - + bkgd(COLOR_PAIR(1)); refresh(); - xmp_get_module_info(c, &mi); - row = pos = -1; - chanOffset = 0; - xmp_start_player(c, SAMPLERATE, 0); + createWindows(); - updateTrack(mi.mod->name, mi.mod->type); + keypad(stdscr, TRUE); + + int row, pos; + xmp_get_module_info(xc, &xmi); + row = pos = -1; + xmp_start_player(xc, SAMPLERATE, 0); + + int key; + bool displayChanged; + display = 0; displayChanged = true; while (true) { - xmp_get_frame_info(c, &fi); - if (xmp_play_frame(c) != 0 && !is_stopped) break; - if (fi.loop_count > loop_times) - if (looper) loop_times = fi.loop_count; - else break; - - // Print Top-Right time - mvprintw( - 0, COLS-11, - "%02u:%02u/%02u:%02u", - ((fi.time / 1000) / 60) % 60, - (fi.time / 1000) % 60, - ((fi.total_time / 1000) / 60) % 60, - (fi.total_time / 1000) % 60 - ); - - - /* - Handles Key Events - * Key timeout is set to 0 to become non-blocking if playing. This allows - * Continualy looping to play the track without requiring a key press. - * Once the playstate changes through the boolean 'is_stopped', the timeout - * changes to -1 for an infinite timeout in the 'keys' loop which will loop - * until is_stopped is false. The block state is for efficiency. - */ - keys: - wtimeout(win, is_stopped?-1:0); - if ((key = wgetch(win)) != 0) { - vol = xmp_get_player(c, XMP_PLAYER_VOLUME); + xmp_get_frame_info(xc, &xfi); + if (xmp_play_frame(xc) != 0 && !stopped) break; + if (xfi.loop_count > looped && !loop) break; + else looped = xfi.loop_count; + + keys: + timeout(stopped?-1:0); + if ((key = getch()) != 0) { + vol = xmp_get_player(xc, XMP_PLAYER_VOLUME); switch (key) { case KEY_RESIZE: - werase(stdscr); - updateTrack(mi.mod->name, mi.mod->type); - wresize(win, LINES-2, COLS-2); - break; - case ' ': // Pause/Play - time = fi.time; - is_stopped = !is_stopped; + destroyWindows(); + createWindows(); + displayChanged = true; // Update top section. break; + case 'q': + goto end; break; case KEY_LEFT: // Move Channels Left - if (chanOffset > 0 && detail < 7) chanOffset--; + if (hOffset > hMin) hOffset--; break; case KEY_RIGHT: // Move Channels Right - if (chanOffset < mi.mod->chn-1 && detail < 7) chanOffset++; + if (hOffset < hMax) hOffset++; break; case KEY_UP: // Seek Up - if (insOffset > 0 && detail == 7) insOffset--; - else if (detail < 7) fi.row--; + if (vOffset > vMin) vOffset--; break; case KEY_DOWN: // Seek Down - if (insOffset < mi.mod->ins-1 && detail == 7) insOffset++; - else if (detail < 7) fi.row++; + if (vOffset < vMax) vOffset++; break; - case KEY_PPAGE: - xmp_set_position(c, fi.pos-1); + case 10: + hOffset = 0; + vOffset = 0; break; - case KEY_NPAGE: - xmp_set_position(c, fi.pos+1); + case ' ': // Pause/Play + xfi.time-=20; + stopped = !stopped; break; - case '+': - if (vol < 200) xmp_set_player(c, XMP_PLAYER_VOLUME, vol+=5); + case '.': + if (vol < 200) xmp_set_player(xc, XMP_PLAYER_VOLUME, vol+=5); break; - case '-': - if (vol > 0) xmp_set_player(c, XMP_PLAYER_VOLUME, vol-=5); + case ',': + if (vol > 0) xmp_set_player(xc, XMP_PLAYER_VOLUME, vol-=5); break; case 'l': - looper = !looper; + loop = !loop; break; case '1': case '2': case '3': case '4': case '5': - case '6': - case '7': - detail = key-48; + display = key-49; + displayChanged = true; break; }; - renderTrack(win, &mi, &fi); + renderTrack(&xmi, &xfi); } - - if (!is_stopped) { - frames = snd_pcm_bytes_to_frames(handle, fi.buffer_size); - if (snd_pcm_writei(handle, fi.buffer, frames) < 0) { + + if (displayChanged) { + werase(dis); + werase(tab); + hOffset = 0; + vOffset = 0; + move(0, 0); + for (int d = 0; d < sizeof(pages)/sizeof(*pages); d++) { + printw(" "); + chtype tpair; + if (display == d) tpair = COLOR_PAIR(3); + else tpair = COLOR_PAIR(2); + attron(tpair); + printw(" "); printw(pages[d]); printw(" "); + attroff(tpair); + printw(" "); + } + mode = 0; + wmove(tab, 0, 0); + displayChanged = false; + } + + if (!stopped) { + frames = snd_pcm_bytes_to_frames(handle, xfi.buffer_size); + if (snd_pcm_writei(handle, xfi.buffer, frames) < 0) { snd_pcm_prepare(handle); } - if (fi.pos != pos) { - pos = fi.pos; + if (xfi.pos != pos) { + pos = xfi.pos; row = -1; } - if (fi.row != row || detail >= 6) { - renderTrack(win, &mi, &fi); - row = fi.row; - fupdate = false; + if (xfi.row != row) { + row = xfi.row; } + renderTrack(&xmi, &xfi); + wrefresh(tab); + wrefresh(dis); } else goto keys; } - printf("Closing ncurses...\n"); + end: clrtoeol(); refresh(); endwin(); - printf("Releasing libxmp...\n"); - xmp_end_player(c); - xmp_release_module(c); - xmp_free_context(c); - - printf("Shutting down audio driver...\n"); - err = snd_pcm_drain(handle); - if (err < 0) + xmp_end_player(xc); + xmp_release_module(xc); + xmp_free_context(xc); + if ((err = snd_pcm_drain(handle)) < 0) { printf("snd_pcm_drain failed: %s\n", snd_strerror(err)); + } snd_pcm_close(handle); + printf("Goodbye!\n"); return 0; } -void updateTrack(char* name, char* type) { - mvprintw( - 0, 0, - "%s (%s)", - name, - type - ); +void destroyWindows() { + delwin(tab); + delwin(dis); } -void renderTrack(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi) { - werase(win); - move(LINES-1, 0); - wclrtoeol(stdscr); - mvprintw( - LINES-1, 0, - "[%c] PAT:%02x:%02x/%02x BPM:%02u SPD:%02u CHN:%02u/%02u INS:%02u/%02u VOL:%03u WIN:%i %s", - is_stopped?'x':'>', - fi->pos, - fi->pattern, - mi->mod->pat, - fi->bpm, - fi->speed, - chanOffset+1, - mi->mod->chn, - insOffset, - mi->mod->ins, - vol, - detail, - looper?"LOOP ":"" - ); - if (detail < 6) // Row views - renderRows(win, mi, fi); - else if (detail == 6) //Channel views - renderChannels(win, mi, fi); - else if (detail == 7) - renderInstruments(win, mi, fi); +void createWindows() { + tab = newwin(LINES-1, COLS, 1, 0); + wmove(tab, 0, 0); + wprintw(tab, ""); + wbkgd(tab, COLOR_PAIR(3)); + wrefresh(tab); - refresh(); - wrefresh(win); + dis = newwin(LINES-4, COLS-2, 3, 1); + wmove(dis, 0, 0); + wprintw(dis, ""); + wbkgd(dis, COLOR_PAIR(4)); + wrefresh(dis); } -void renderRows(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi) { - int dlvl; - // Set proper sizes for channels. - if (detail == 5) dlvl = 19; - else if (detail == 4) dlvl = 15; - else if (detail == 3) dlvl = 11; - else if (detail == 2) dlvl = 7; - else dlvl = 2; - for (int y = 0; y < LINES - 2; y++) { +void renderTrack(xmp_module_info *mi, xmp_frame_info *fi) { + werase(dis); + mvwprintw(tab, 0, 1, mi->mod->name); + mvwprintw( + tab, + 0, COLS-12, + "%02u:%02u/%02u:%02u", + ((fi->time / 1000) / 60) % 60, + (fi->time / 1000) % 60, + ((fi->total_time / 1000) / 60) % 60, + (fi->total_time / 1000) % 60 + ); + mvwprintw(tab, 1, COLS-10, "VOL: %i%%", vol); + mvwprintw(tab, 1, 1, "%i/%ibpm", fi->speed, fi->bpm); + mvwprintw(tab, LINES-2, (COLS/2)-4, stopped?"STOPPED":"PLAYING"); + if (display == 0) { + renderInfo(mi, fi); + } else if (display == 1) { + renderRows(mi, fi); + } else if (display == 2) { + renderChannels(mi, fi); + } else if (display == 3) { + renderInstruments(mi, fi); + } else { + renderAbout(); + } + refresh(); + wrefresh(dis); + wrefresh(tab); +} + +void renderInfo(xmp_module_info *mi, xmp_frame_info *fi) { + wattron(dis, A_BOLD); + mvwprintw(dis, 3-vOffset, 0, "Format:"); + mvwprintw(dis, 4-vOffset, 0, "Instruments:"); + mvwprintw(dis, 5-vOffset, 0, "Channels:"); + mvwprintw(dis, 6-vOffset, 0, "Looping:"); + mvwprintw(dis, 8-vOffset, 0, "Comments:"); + wattroff(dis, A_BOLD); + + mvwprintw(dis, 3-vOffset, 16, mi->mod->type); + mvwprintw(dis, 4-vOffset, 16, "%i", mi->mod->ins); + mvwprintw(dis, 5-vOffset, 16, "%i", mi->mod->chn); + mvwprintw(dis, 6-vOffset, 16, loop?"YES":"NO"); + + if (mi->comment != NULL) { + mvwprintw(dis, 9-vOffset, 0, "%s", mi->comment); + } +} + +void renderAbout() { + wattron(dis, A_BOLD); + mvwprintw(dis, 1-vOffset, 2, "======== || // || //"); + mvwprintw(dis, 2-vOffset, 2, " || || // || //"); + mvwprintw(dis, 3-vOffset, 2, " || ||// ||//"); + mvwprintw(dis, 4-vOffset, 2, " || //==\\\\ //===|| ||\\\\ ||\\\\ //===\\\\ //===\\\\"); + mvwprintw(dis, 5-vOffset, 2, " || || || | || \\\\ || \\\\ ||===// ||"); + mvwprintw(dis, 6-vOffset, 2, " || || \\\\===|| || \\\\ || \\\\ \\\\___/ ||"); + mvwprintw(dis, 8-vOffset, 1, "TRAKKER v%s", TRAKKER_VERSION); + mvwprintw(dis, 9-vOffset, 1, "libXMP v%s", xmp_version); + + mvwprintw(dis, 11-vOffset, 1, "[Spacebar]"); + mvwprintw(dis, 12-vOffset, 1, "Number Keys"); + mvwprintw(dis, 13-vOffset, 1, "Arrow Keys"); + mvwprintw(dis, 14-vOffset, 1, "[,] and [.]"); + mvwprintw(dis, 15-vOffset, 1, "[Return]"); + mvwprintw(dis, 16-vOffset, 1, "[L]"); + wattroff(dis, A_BOLD); + + mvwprintw(dis, 11-vOffset, 16, "Play/Pause"); + mvwprintw(dis, 12-vOffset, 16, "Change Tab"); + mvwprintw(dis, 13-vOffset, 16, "Change Hori or Vert Display Offset"); + mvwprintw(dis, 14-vOffset, 16, "Control volume"); + mvwprintw(dis, 15-vOffset, 16, "Reset Display"); + mvwprintw(dis, 16-vOffset, 16, "Toggle Loop"); +} + +void renderRows(xmp_module_info *mi, xmp_frame_info *fi) { + int chnsize = 15; + for (int j = 0; j < mi->mod->len; j++) { + if (mi->mod->xxo[j] == 0xFF) continue; + chtype patpair = (j == fi->pos)?COLOR_PAIR(6):COLOR_PAIR(4); + wattron(dis, patpair); + mvwprintw(dis, LINES-5, (COLS/2)+(j*3)-(fi->pos*3), "%02X", mi->mod->xxo[j]); + wattroff(dis, patpair); + } + wattroff(tab, COLOR_PAIR(5)); + for (int y = 0; y < LINES - 5; y++) { int trow = (fi->row - ((LINES - 2) / 2))+y; - if (trow > fi->num_rows-1 || trow < 0) { continue;} - if (trow == fi->row) { - wattron(win, COLOR_PAIR(is_stopped?2:1)); - wattron(win, A_BOLD); - } else { - wattroff(win, COLOR_PAIR(is_stopped?2:1)); - wattroff(win, A_BOLD); - } - wmove(win, y, 0); - wprintw(win, "%02X", trow); - int maxcol = -1; - for (int i = chanOffset; i < mi->mod->chn; i++) { - if (1+(((i-chanOffset)+1)*dlvl)+dlvl > COLS) { - maxcol = i; + if (trow > fi->num_rows-1 || trow < 0) { continue; } + chtype numpair = COLOR_PAIR((trow==fi->row)?(stopped?9:7):5); + chtype rowpair = COLOR_PAIR((trow==fi->row)?(stopped?8:6):4); + if (trow == fi->row) wattron(dis, A_BOLD); + wmove(dis, y, 0); + wattron(dis, numpair); + wprintw(dis, "%02X", trow); + wattroff(dis, numpair); + wattron(dis, rowpair); + for (int i = 0; i < mi->mod->chn+1; i++) { + if (i >= mi->mod->chn) { + mvwaddch(dis, y, ((i*chnsize)+2)-hOffset, '|'); break; } - wmove(win, y, 1+((i-chanOffset)*dlvl)+2); int track = mi->mod->xxp[fi->pattern]->index[i]; struct xmp_event event = mi->mod->xxt[track]->event[trow]; - if (i > 0 && i == chanOffset) wprintw(win, "<"); - else wprintw(win, "|"); - if (detail >= 2) { - if (event.note > 0x80) { - wprintw(win, "=== "); - } else if (event.note > 0) { - int note = event.note - 1; - wprintw(win, "%s%d ", note_name[note % 12], note / 12); - } else { - wprintw(win, "... "); - } - - if (event.ins > 0) { - wprintw(win, "%02X", event.ins); - } else { - wprintw(win, ".."); - } - - if (detail >= 3) { - int vol; - if ((vol = event.vol) != 0) { - char v = 'v'; - wprintw(win, " %c%02X", v, vol-1); - } else { - wprintw(win, " ..."); - } + char *lnbuf = new char[chnsize+1]; + char *note = new char[4]; + char *ins = new char[3]; + char *vol = new char[4]; + char *efx = new char[4]; + + if (event.note > 0x80) + snprintf(note, 4, "==="); + else if (event.note > 0) + snprintf(note, 4, "%s%d", note_name[event.note % 12], event.note / 12); + else + snprintf(note, 4, "..."); + + if (event.ins > 0) snprintf(ins, 3, "%02X", event.ins); + else snprintf(ins, 3, ".."); + + if (event.vol != 0) + snprintf(vol, 4, "v%02X", event.vol-1); + else if (event.note != 0) + snprintf(vol, 4, "v40"); + else snprintf(vol, 4, "..."); - if (detail >= 4) { - char f1; - if ((f1 = getEffectType(event.fxt)) != 0) - wprintw(win, " %c%02X", f1, event.fxp); - else - wprintw(win, " ..."); - - if (detail >= 5) { - char f2; - if ((f2 = getEffectType(event.fxt)) != 0) - wprintw(win, " %c%02X", f2, event.f2p); - else - wprintw(win, " ..."); - } - } - } - } else { - if (event.note > 0x80) { - wprintw(win, "-"); - } else if (event.note > 0) { - wprintw(win, "#"); - } else { - wprintw(win, " "); - } + char f1; + if ((f1 = getEffectType(event.fxt)) != 0) snprintf(efx, 4, "%c%02X", f1, event.fxp); + else snprintf(efx, 4, "..."); + sprintf(lnbuf, "|%s %s %s %s", note, ins, vol, efx); + for (int z = 0; z < chnsize; z++) { + if (((i*chnsize)+2+z)-hOffset < 2) continue; + mvwaddch(dis, y, ((i*chnsize)+2+z)-hOffset, lnbuf[z]); } + free(lnbuf); + free(note); + free(ins); + free(vol); + free(efx); } - if (maxcol < mi->mod->chn && maxcol > 0) wprintw(win, ">"); - else wprintw(win, "|"); + wattroff(dis, rowpair); + if (trow == fi->row) wattroff(dis, A_BOLD); } } -void renderChannels(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi) { +void renderChannels(xmp_module_info *mi, xmp_frame_info *fi) { int chns = mi->mod->chn; - for (int y = chanOffset; y < chns; y++) { + chtype no_pair = COLOR_PAIR(5); + for (int y = vOffset; y < chns; y++) { + if (y > (LINES - 4)+vOffset || y < 0) continue; struct xmp_channel_info cinfo = fi->channel_info[y]; - if (y > (LINES - 3)+chanOffset) break; - wmove(win, y-chanOffset, 0); - int cvol = (cinfo.volume * (COLS - 7)) / (64 * (vol / 100)); - wprintw(win, "%02X [", y); - for (int c = 0; c < COLS - 7; c++) { - if (c < cvol) wprintw(win, "#"); - else wprintw(win, " "); + if (y > (LINES - 3)+vOffset) break; + wmove(dis, y-vOffset, 0); + int cvol = (cinfo.volume * (COLS - 5)) / (64 * (vol / 100)); + wattron(dis, no_pair); + wprintw(dis, "%02X", y); + wattroff(dis, no_pair); + for (int c = 0; c < COLS - 5; c++) { + if (c < cvol) wprintw(dis, "#"); + else wprintw(dis, " "); } - wprintw(win, "]"); } } -void renderInstruments(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi) { +void renderInstruments(xmp_module_info *mi, xmp_frame_info *fi) { int ins = mi->mod->ins; - for (int y = insOffset; y < ins; y++) { - if (y > (LINES - 3)+insOffset) break; - wmove(win, y-insOffset, 0); - wprintw(win, "%02X [", y); + chtype no_pair = COLOR_PAIR(5); + for (int y = vOffset; y < ins; y++) { + if (y > (LINES - 5)+vOffset || y < 0) continue; + wmove(dis, y-vOffset, 0); + wattron(dis, no_pair); + wprintw(dis, "%02X", y); + wattroff(dis, no_pair); for (int c = 0; c < mi->mod->chn; c++) { struct xmp_channel_info cinfo = fi->channel_info[c]; - int note = (cinfo.note * (COLS - 7)) / 144; + int note = (cinfo.note * (COLS - 4)) / 144; if (cinfo.instrument != y) continue; - wmove(win, y-insOffset, note+3); - if (cinfo.volume >= 16) wprintw(win, "#"); - else if (cinfo.volume > 0) wprintw(win, "-"); + wmove(dis, y-vOffset, note+3); + if (cinfo.volume >= 32) wprintw(dis, "#"); + else if (cinfo.volume >= 16) wprintw(dis, "="); + else if (cinfo.volume > 0) wprintw(dis, "-"); } - wmove(win, y-insOffset, COLS-3); - wprintw(win, "]"); + wmove(dis, y, COLS-4); } } @@ -407,4 +499,4 @@ char getEffectType(int i) { case 180: return 'J'; default: return 0x00; } -} +} \ No newline at end of file diff --git a/src/trakker_version.h.in b/src/trakker_version.h.in new file mode 100644 index 0000000..0b4e1ea --- /dev/null +++ b/src/trakker_version.h.in @@ -0,0 +1,4 @@ +#ifndef TRAKKER_VERSION_H_ +#define TRAKKER_VERSION_H_ +#define TRAKKER_VERSION "@TRAKKER_VERSION@" +#endif /* TRAKKER_VERSION_H_ */ \ No newline at end of file