Completely revamp interface

This commit is contained in:
Wirlaburla 2023-09-13 22:14:31 -05:00
parent 8bbb6a5b99
commit 5ca2e7c1c0
5 changed files with 393 additions and 270 deletions

View File

@ -1,9 +1,14 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.5)
project(trakker) project(trakker)
SET(CMAKE_CXX_STANDARD 17) SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED True) 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(ALSA REQUIRED)
#find_package(xmp REQUIRED) find_package(LIBXMP REQUIRED)
find_package(Curses REQUIRED) find_package(Curses REQUIRED)
add_subdirectory(src) 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) install(TARGETS trakker RUNTIME DESTINATION bin)

View File

@ -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)

View File

@ -1,5 +1,4 @@
add_executable(trakker add_executable(trakker
main.cpp main.cpp
) )
target_link_libraries(trakker PUBLIC ALSA::ALSA xmp ${CURSES_LIBRARY}) target_link_libraries(trakker PUBLIC ALSA::ALSA xmp ${CURSES_LIBRARY})

View File

@ -1,375 +1,467 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
#include <stdio.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <xmp.h> #include <xmp.h>
#include <ncurses.h> #include <ncurses.h>
#include "trakker_version.h"
#define VERSION "0.3.1"
#define SAMPLERATE 48000 #define SAMPLERATE 48000
#define BUFFER_SIZE 250000 #define BUFFER_SIZE 250000
static char *note_name[] = { "C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B " }; 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); 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[]) { int main(int argc, char *argv[]) {
printf("Trakker %s (with libxmp %s)\n", VERSION, xmp_version); int err;
int time, key, err, row, pos; snd_pcm_t *handle;
bool fupdate = false;
snd_pcm_t *handle;
snd_pcm_sframes_t frames; snd_pcm_sframes_t frames;
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { 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); 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) { 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); exit(EXIT_FAILURE);
} }
printf("Using Audio Driver: %s\n", "ALSA"); printf("%s initialized.\n", "ALSA");
xmp_context c; xmp_context xc;
c = xmp_create_context(); xc = xmp_create_context();
if (xmp_load_module(c, argv[1]) != 0) { if (xmp_load_module(xc, argv[1]) != 0) {
fprintf(stderr, "Failed to load Module: %s\n", argv[1]); fprintf(stderr, "Failed to load Module: %s\n", argv[1]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct xmp_module_info mi; struct xmp_module_info xmi;
struct xmp_frame_info fi; struct xmp_frame_info xfi;
printf("Loaded module: %s\n", argv[1]); printf("Loading Module: \"%s\"\n", argv[1]);
WINDOW *win;
initscr(); initscr();
if (LINES < 5 || COLS < 5) { if (has_colors() == TRUE) {
endwin(); start_color();
fprintf(stderr, "ncurses failed: Display is too small.\n"); if (can_change_color() == TRUE) {
exit(EXIT_FAILURE); // 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(); cbreak();
noecho(); noecho();
curs_set(0); curs_set(0);
bkgd(COLOR_PAIR(1));
win = newwin(LINES-2, COLS-2, 1, 1);
keypad(win, TRUE);
wmove(win, 0, 0);
wprintw(win, "");
printf("Loaded ncurses display.\n");
refresh(); refresh();
xmp_get_module_info(c, &mi); createWindows();
row = pos = -1;
chanOffset = 0;
xmp_start_player(c, SAMPLERATE, 0);
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) { while (true) {
xmp_get_frame_info(c, &fi); xmp_get_frame_info(xc, &xfi);
if (xmp_play_frame(c) != 0 && !is_stopped) break; if (xmp_play_frame(xc) != 0 && !stopped) break;
if (fi.loop_count > loop_times) if (xfi.loop_count > looped && !loop) break;
if (looper) loop_times = fi.loop_count; else looped = xfi.loop_count;
else break;
keys:
// Print Top-Right time timeout(stopped?-1:0);
mvprintw( if ((key = getch()) != 0) {
0, COLS-11, vol = xmp_get_player(xc, XMP_PLAYER_VOLUME);
"%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);
switch (key) { switch (key) {
case KEY_RESIZE: case KEY_RESIZE:
werase(stdscr); destroyWindows();
updateTrack(mi.mod->name, mi.mod->type); createWindows();
wresize(win, LINES-2, COLS-2); displayChanged = true; // Update top section.
break;
case ' ': // Pause/Play
time = fi.time;
is_stopped = !is_stopped;
break; break;
case 'q':
goto end; break;
case KEY_LEFT: // Move Channels Left case KEY_LEFT: // Move Channels Left
if (chanOffset > 0 && detail < 7) chanOffset--; if (hOffset > hMin) hOffset--;
break; break;
case KEY_RIGHT: // Move Channels Right case KEY_RIGHT: // Move Channels Right
if (chanOffset < mi.mod->chn-1 && detail < 7) chanOffset++; if (hOffset < hMax) hOffset++;
break; break;
case KEY_UP: // Seek Up case KEY_UP: // Seek Up
if (insOffset > 0 && detail == 7) insOffset--; if (vOffset > vMin) vOffset--;
else if (detail < 7) fi.row--;
break; break;
case KEY_DOWN: // Seek Down case KEY_DOWN: // Seek Down
if (insOffset < mi.mod->ins-1 && detail == 7) insOffset++; if (vOffset < vMax) vOffset++;
else if (detail < 7) fi.row++;
break; break;
case KEY_PPAGE: case 10:
xmp_set_position(c, fi.pos-1); hOffset = 0;
vOffset = 0;
break; break;
case KEY_NPAGE: case ' ': // Pause/Play
xmp_set_position(c, fi.pos+1); xfi.time-=20;
stopped = !stopped;
break; break;
case '+': case '.':
if (vol < 200) xmp_set_player(c, XMP_PLAYER_VOLUME, vol+=5); if (vol < 200) xmp_set_player(xc, XMP_PLAYER_VOLUME, vol+=5);
break; break;
case '-': case ',':
if (vol > 0) xmp_set_player(c, XMP_PLAYER_VOLUME, vol-=5); if (vol > 0) xmp_set_player(xc, XMP_PLAYER_VOLUME, vol-=5);
break; break;
case 'l': case 'l':
looper = !looper; loop = !loop;
break; break;
case '1': case '1':
case '2': case '2':
case '3': case '3':
case '4': case '4':
case '5': case '5':
case '6': display = key-49;
case '7': displayChanged = true;
detail = key-48;
break; break;
}; };
renderTrack(win, &mi, &fi); renderTrack(&xmi, &xfi);
} }
if (!is_stopped) { if (displayChanged) {
frames = snd_pcm_bytes_to_frames(handle, fi.buffer_size); werase(dis);
if (snd_pcm_writei(handle, fi.buffer, frames) < 0) { 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); snd_pcm_prepare(handle);
} }
if (fi.pos != pos) { if (xfi.pos != pos) {
pos = fi.pos; pos = xfi.pos;
row = -1; row = -1;
} }
if (fi.row != row || detail >= 6) { if (xfi.row != row) {
renderTrack(win, &mi, &fi); row = xfi.row;
row = fi.row;
fupdate = false;
} }
renderTrack(&xmi, &xfi);
wrefresh(tab);
wrefresh(dis);
} else goto keys; } else goto keys;
} }
printf("Closing ncurses...\n"); end:
clrtoeol(); clrtoeol();
refresh(); refresh();
endwin(); endwin();
printf("Releasing libxmp...\n"); xmp_end_player(xc);
xmp_end_player(c); xmp_release_module(xc);
xmp_release_module(c); xmp_free_context(xc);
xmp_free_context(c); if ((err = snd_pcm_drain(handle)) < 0) {
printf("Shutting down audio driver...\n");
err = snd_pcm_drain(handle);
if (err < 0)
printf("snd_pcm_drain failed: %s\n", snd_strerror(err)); printf("snd_pcm_drain failed: %s\n", snd_strerror(err));
}
snd_pcm_close(handle); snd_pcm_close(handle);
printf("Goodbye!\n");
return 0; return 0;
} }
void updateTrack(char* name, char* type) { void destroyWindows() {
mvprintw( delwin(tab);
0, 0, delwin(dis);
"%s (%s)",
name,
type
);
} }
void renderTrack(WINDOW* win, xmp_module_info *mi, xmp_frame_info *fi) { void createWindows() {
werase(win); tab = newwin(LINES-1, COLS, 1, 0);
move(LINES-1, 0); wmove(tab, 0, 0);
wclrtoeol(stdscr); wprintw(tab, "");
mvprintw( wbkgd(tab, COLOR_PAIR(3));
LINES-1, 0, wrefresh(tab);
"[%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);
refresh(); dis = newwin(LINES-4, COLS-2, 3, 1);
wrefresh(win); 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) { void renderTrack(xmp_module_info *mi, xmp_frame_info *fi) {
int dlvl; werase(dis);
// Set proper sizes for channels. mvwprintw(tab, 0, 1, mi->mod->name);
if (detail == 5) dlvl = 19; mvwprintw(
else if (detail == 4) dlvl = 15; tab,
else if (detail == 3) dlvl = 11; 0, COLS-12,
else if (detail == 2) dlvl = 7; "%02u:%02u/%02u:%02u",
else dlvl = 2; ((fi->time / 1000) / 60) % 60,
for (int y = 0; y < LINES - 2; y++) { (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; int trow = (fi->row - ((LINES - 2) / 2))+y;
if (trow > fi->num_rows-1 || trow < 0) { continue;} if (trow > fi->num_rows-1 || trow < 0) { continue; }
if (trow == fi->row) { chtype numpair = COLOR_PAIR((trow==fi->row)?(stopped?9:7):5);
wattron(win, COLOR_PAIR(is_stopped?2:1)); chtype rowpair = COLOR_PAIR((trow==fi->row)?(stopped?8:6):4);
wattron(win, A_BOLD); if (trow == fi->row) wattron(dis, A_BOLD);
} else { wmove(dis, y, 0);
wattroff(win, COLOR_PAIR(is_stopped?2:1)); wattron(dis, numpair);
wattroff(win, A_BOLD); wprintw(dis, "%02X", trow);
} wattroff(dis, numpair);
wmove(win, y, 0); wattron(dis, rowpair);
wprintw(win, "%02X", trow); for (int i = 0; i < mi->mod->chn+1; i++) {
int maxcol = -1; if (i >= mi->mod->chn) {
for (int i = chanOffset; i < mi->mod->chn; i++) { mvwaddch(dis, y, ((i*chnsize)+2)-hOffset, '|');
if (1+(((i-chanOffset)+1)*dlvl)+dlvl > COLS) {
maxcol = i;
break; break;
} }
wmove(win, y, 1+((i-chanOffset)*dlvl)+2);
int track = mi->mod->xxp[fi->pattern]->index[i]; int track = mi->mod->xxp[fi->pattern]->index[i];
struct xmp_event event = mi->mod->xxt[track]->event[trow]; struct xmp_event event = mi->mod->xxt[track]->event[trow];
if (i > 0 && i == chanOffset) wprintw(win, "<"); char *lnbuf = new char[chnsize+1];
else wprintw(win, "|"); char *note = new char[4];
if (detail >= 2) { char *ins = new char[3];
if (event.note > 0x80) { char *vol = new char[4];
wprintw(win, "=== "); char *efx = new char[4];
} else if (event.note > 0) {
int note = event.note - 1; if (event.note > 0x80)
wprintw(win, "%s%d ", note_name[note % 12], note / 12); snprintf(note, 4, "===");
} else { else if (event.note > 0)
wprintw(win, "... "); snprintf(note, 4, "%s%d", note_name[event.note % 12], event.note / 12);
} else
snprintf(note, 4, "...");
if (event.ins > 0) {
wprintw(win, "%02X", event.ins); if (event.ins > 0) snprintf(ins, 3, "%02X", event.ins);
} else { else snprintf(ins, 3, "..");
wprintw(win, "..");
} if (event.vol != 0)
snprintf(vol, 4, "v%02X", event.vol-1);
if (detail >= 3) { else if (event.note != 0)
int vol; snprintf(vol, 4, "v40");
if ((vol = event.vol) != 0) { else snprintf(vol, 4, "...");
char v = 'v';
wprintw(win, " %c%02X", v, vol-1);
} else {
wprintw(win, " ...");
}
if (detail >= 4) { char f1;
char f1; if ((f1 = getEffectType(event.fxt)) != 0) snprintf(efx, 4, "%c%02X", f1, event.fxp);
if ((f1 = getEffectType(event.fxt)) != 0) else snprintf(efx, 4, "...");
wprintw(win, " %c%02X", f1, event.fxp); sprintf(lnbuf, "|%s %s %s %s", note, ins, vol, efx);
else for (int z = 0; z < chnsize; z++) {
wprintw(win, " ..."); if (((i*chnsize)+2+z)-hOffset < 2) continue;
mvwaddch(dis, y, ((i*chnsize)+2+z)-hOffset, lnbuf[z]);
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, " ");
}
} }
free(lnbuf);
free(note);
free(ins);
free(vol);
free(efx);
} }
if (maxcol < mi->mod->chn && maxcol > 0) wprintw(win, ">"); wattroff(dis, rowpair);
else wprintw(win, "|"); 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; 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]; struct xmp_channel_info cinfo = fi->channel_info[y];
if (y > (LINES - 3)+chanOffset) break; if (y > (LINES - 3)+vOffset) break;
wmove(win, y-chanOffset, 0); wmove(dis, y-vOffset, 0);
int cvol = (cinfo.volume * (COLS - 7)) / (64 * (vol / 100)); int cvol = (cinfo.volume * (COLS - 5)) / (64 * (vol / 100));
wprintw(win, "%02X [", y); wattron(dis, no_pair);
for (int c = 0; c < COLS - 7; c++) { wprintw(dis, "%02X", y);
if (c < cvol) wprintw(win, "#"); wattroff(dis, no_pair);
else wprintw(win, " "); 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; int ins = mi->mod->ins;
for (int y = insOffset; y < ins; y++) { chtype no_pair = COLOR_PAIR(5);
if (y > (LINES - 3)+insOffset) break; for (int y = vOffset; y < ins; y++) {
wmove(win, y-insOffset, 0); if (y > (LINES - 5)+vOffset || y < 0) continue;
wprintw(win, "%02X [", y); 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++) { for (int c = 0; c < mi->mod->chn; c++) {
struct xmp_channel_info cinfo = fi->channel_info[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; if (cinfo.instrument != y) continue;
wmove(win, y-insOffset, note+3); wmove(dis, y-vOffset, note+3);
if (cinfo.volume >= 16) wprintw(win, "#"); if (cinfo.volume >= 32) wprintw(dis, "#");
else if (cinfo.volume > 0) wprintw(win, "-"); else if (cinfo.volume >= 16) wprintw(dis, "=");
else if (cinfo.volume > 0) wprintw(dis, "-");
} }
wmove(win, y-insOffset, COLS-3); wmove(dis, y, COLS-4);
wprintw(win, "]");
} }
} }
@ -407,4 +499,4 @@ char getEffectType(int i) {
case 180: return 'J'; case 180: return 'J';
default: return 0x00; default: return 0x00;
} }
} }

4
src/trakker_version.h.in Normal file
View File

@ -0,0 +1,4 @@
#ifndef TRAKKER_VERSION_H_
#define TRAKKER_VERSION_H_
#define TRAKKER_VERSION "@TRAKKER_VERSION@"
#endif /* TRAKKER_VERSION_H_ */