From f8b07a32b9efa8e3cf61de2c9f9ebe84d9264872 Mon Sep 17 00:00:00 2001 From: Sen Date: Mon, 25 Aug 2025 18:07:15 +0200 Subject: [PATCH] add midi player --- client/src/main/java/client/Client.java | 50 +- .../java/client/audio/AudioInterface.java | 843 ------------------ .../main/java/client/audio/MidiDecoder.java | 33 +- client/src/main/java/client/gui/GuiMenu.java | 45 +- .../src/main/java/client/gui/GuiPlayer.java | 570 ++++++++++++ client/src/main/java/client/vars/EnumVar.java | 2 +- 6 files changed, 608 insertions(+), 935 deletions(-) create mode 100644 client/src/main/java/client/gui/GuiPlayer.java diff --git a/client/src/main/java/client/Client.java b/client/src/main/java/client/Client.java index 26d2b1d1..ed606813 100755 --- a/client/src/main/java/client/Client.java +++ b/client/src/main/java/client/Client.java @@ -14,7 +14,6 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.file.Files; import java.text.SimpleDateFormat; import java.util.ArrayDeque; import java.util.Date; @@ -47,6 +46,7 @@ import client.gui.GuiConsole; import client.gui.GuiInfo; import client.gui.GuiLoading; import client.gui.GuiMenu; +import client.gui.GuiPlayer; import client.gui.GuiServer; import client.gui.Style; import client.gui.character.GuiChar; @@ -634,25 +634,25 @@ public class Client implements IThreadListener { private int soundFrameSize = 32; @Variable(name = "mid_dont_fade", category = CVarCategory.SOUND, display = "Nicht ausklingen") - private boolean midiNoWait = false; + public boolean midiNoWait = false; @Variable(name = "mid_opl_voices", category = CVarCategory.SOUND, min = 4, max = 192, display = "OPL-Stimmen") - private int midiVoices = 64; + public int midiVoices = 64; @Variable(name = "mid_keep_notes", category = CVarCategory.SOUND, display = "Stimmen behalten") - private boolean midiKeep = false; + public boolean midiKeep = false; @Variable(name = "mid_play_unknown", category = CVarCategory.SOUND, display = "Unbekannte Banken") - private boolean midiUnknown = true; + public boolean midiUnknown = true; // STR(MID_VELO_LOG, "", "Log.+Minimum [m+nlog(x)]") // STR(MID_VELO_ATTN, "", "Log. Gedämpft [nlog(x)]") // STR(MID_VELO_LIN, "", "Linear [x]") // STR(MID_VELO_ONE, "", "Vollklang [1]") @Variable(name = "mid_velocity_func", category = CVarCategory.SOUND, min = -128, max = 127, display = "Anschlag") - private int midiVelocity = 1; + public int midiVelocity = 1; @Variable(name = "mid_opl_bank", category = CVarCategory.SOUND, display = "Bank") - private MidiBank midiBank = MidiBank.DMX_DMX; + public MidiBank midiBank = MidiBank.DMX_DMX; @Variable(name = "mid_debug_events", category = CVarCategory.SOUND, display = "MIDI-Debug", callback = MidiDebugFunction.class) - private boolean midiDebug = false; + public boolean midiDebug = false; @Variable(name = "mid_visualizer", category = CVarCategory.SOUND, display = "Visualisation") - private boolean midiVisualizer = true; + public boolean midiVisualizer = true; public static final Client CLIENT = new Client(); @@ -1025,6 +1025,7 @@ public class Client implements IThreadListener { this.world.updateEntities(); } this.soundManager.update(); + GuiPlayer.INSTANCE.updatePlayer(); if (this.world != null) { this.tickWorld(); @@ -3450,37 +3451,6 @@ public class Client implements IThreadListener { Log.NETWORK.debug("Variable %s = %s", name, value); } } - - public void playMidi(File file) { - byte[] data; - try { - data = Files.readAllBytes(file.toPath()); - } - catch(Throwable e) { - Log.SOUND.error(e, "Konnte Datei '%s' nicht laden", file); - return; - } - MidiDecoder midi; - try { - midi = new MidiDecoder(data, this.midiNoWait, this.midiVoices, this.midiBank, this.midiKeep, this.midiUnknown, this.midiVelocity); - } - catch(Throwable e) { - Log.SOUND.error(e, "Konnte MIDI '%s' nicht laden", file); - return; - } - midi.setDebug(this.midiDebug); - this.audio.alMidi(midi); - } - - public void testMidi(int start) { - MidiDecoder midi = new MidiDecoder(this.midiVoices, this.midiBank, this.midiKeep, this.midiUnknown, this.midiVelocity, start); - midi.setDebug(this.midiDebug); - this.audio.alMidi(midi); - } - - public void stopMidi() { - this.audio.alMidi(null); - } private void displayTick(int posX, int posY, int posZ) { int range = 16; diff --git a/client/src/main/java/client/audio/AudioInterface.java b/client/src/main/java/client/audio/AudioInterface.java index d38a2a09..7df951f7 100644 --- a/client/src/main/java/client/audio/AudioInterface.java +++ b/client/src/main/java/client/audio/AudioInterface.java @@ -57,849 +57,6 @@ public class AudioInterface implements Runnable { private boolean waiting; private MidiDecoder mid; - - /* -STR(OPL_CHANNEL, "", "Kanal") -STR(OPL_MODULATOR, "", "Operator 1 + 3 / Modulator") -STR(OPL_CARRIER, "", "Operator 2 + 4 / Träger") -STR(OPL_POINTER, "", "Stimmen-Zeiger") -STR(OPL_OUTPUT, "", "Pegel") -STR(OPL_MODE, "", "Modus/Al.") -STR(OPL_FEEDBACK, "", "Feedback") -STR(OPL_FREQUENCY, "", "Frequenz") -STR(OPL_FLAGS, "", "T-V-S-K") -STR(OPL_MULTIPLIER, "", "Frq.-Mult.") -STR(OPL_LEVEL, "", "Op.-Pegel") -STR(OPL_KEYSCALE, "", "Tst.-Skale") -STR(OPL_WAVEFORM, "", "Wellenf.") -STR(OPL_ATTACK, "", "Attack") -STR(OPL_DECAY, "", "Decay") -STR(OPL_SUSTAIN, "", "Sustain") -STR(OPL_RELEASE, "", "Release") -STR(OPL_ENVELOPE, "", "Hüllkurve") -STR(OPL_TICK, "", "Tick/Pos.") -STR(OPL_ACTIVE, "", "Aktiv") -STR(OPL_TEMPO, "", "Tempo BPM") - -STR(MID_PLAY, "s", "Spiele MIDI '$1'") -STR(CMD_PLAY_QUEUED, "d", "$1 MIDIs werden abgespielt") -STR(CMD_PLAY_STOPPED, "", "Wiedergabe ist angehalten") -STR(CMD_PLAY_PLAYING, "d", "$1 MIDIs sind in der Liste") -STR(CMD_PLAY_ENDED, "", "Wiedergabe gestoppt") -STR(CMD_PLAY_BANKID, "d", "Bank-ID: $1") - -STR(PLR_MODE_NORM, "", "Normal") -STR(PLR_MODE_REPEAT, "", "Wiederholen") -STR(PLR_MODE_LOOP, "", "Schleife") -STR(PLR_MODE_RAND, "", "Zufällig") -STR(PLR_START, "", "Start") -STR(PLR_STOP, "", "Stop") -STR(PLR_PAUSE, "", "Pause") -STR(PLR_MODE, "", "Modus") -STR(PLR_PREV, "", "Vorheriger") -STR(PLR_NEXT, "", "Nächster") -STR(PLR_RANDOM, "", "Zufälliger") -STR(PLR_JUMP, "", "Springe zu") -STR(PLR_INFO, "", "Titelinfo") -STR(PLR_KARAOKE, "", "Karaoke-Texte") - -STR(TITLE_PLAYER, "", "MIDI-Player") - -STR(TITLE_MIDI, "", "Optionen für MIDI-Wiedergabe") -STR(TITLE_PLR_FULL, "", "SKC OPL MIDI Player v 0.0.1 (~ Sen)") - -#define STR_IMID_TITLE "Titel" -#define STR_IMID_INFO "Info" -#define STR_IMID_COPY "Hinweis" -#define STR_IMID_WARN "Lizenz" -#define STR_IMID_LANG "Sprache" -#define STR_IMID_VER "Version" - - -#define SYM_PLAY "\U00100000" -#define SYM_STOP "\U00100001" -#define SYM_PAUSE "\U00100002" -#define SYM_NEXT "\U00100003" -#define SYM_PREV "\U00100004" -#define SYM_FFORWARD "\U00100005" -#define SYM_FREVERSE "\U00100006" -#define SYM_CONTINUOS "\U00100007" -#define SYM_REPEAT "\U00100008" -#define SYM_LOOPED "\U00100009" -#define SYM_SHUFFLE "\U0010000a" -#define SYM_PRANDOM "\U0010000b" -#define SYM_JUMPTO "\U0010000c" -#define SYM_FOLDER "\U0010000d" -#define SYM_DELETE "\U0010000e" -#define SYM_SAVEDISK "\U0010000f" - - -#define SND_INFO 64 -#define SND_KAR 72 -#define SND_KLOG 5 - -#define BNK_IDX_MELO_ONLY 25 -#define BNK_IDX_DRUM_ONLY 30 - -static const char plr_wheel[] = { '/', '-', '\\', '|'}; - -static const char *mid_extensions[] = {"mid", "kar", "midi"}; - -typedef struct { - window_t *player; - ulong mid_poll; - char **mid_queue; - char *mid_list; - byte mid_nowait; - byte mid_repeat; - byte mid_bank; - int mid_queued; - int mid_playpos; - int mid_prevpos; - - byte mid_keep; - byte mid_unknown; - byte mid_visual; - int mid_velo; - int mid_voices; - - byte mid_debug; - byte mid_karaoke; - uint mid_klog_pos; - uint mid_klog_offs; - uint mid_info_offs[6]; - char mid_klogger[SND_KLOG * SND_KAR]; - char mid_info[SND_INFO * 6]; -} snd_t; - -snd_t snd; - -plr_debug(cvar_byte("mid_debug_events")); - - -static const char **plr_descs[] = { &STR_IMID_TITLE, &STR_IMID_INFO, &STR_IMID_COPY, &STR_IMID_WARN, &STR_IMID_LANG, &STR_IMID_VER }; - -byte plr_play_file(const char *midname, byte nowait) { - mid_handle mid; - uint size; - if(!(size = mid_read(&mid, midname))) - return 0; - logi(LOG_CON, STR_MID_PLAY, midname); - snd_instruct(mid.track, size, SND_CMD_LOAD, 0, (uint)mid.tracks | ((uint)mid.tpqn << 16) | ((uint)nowait << 31)); - mem_free(mid.track); - return 1; -} - -void plr_cmlog(byte empty); - -byte plr_play(int pos, byte nowait) { - plr_cmlog(0); - if(pos != (snd.mid_queued - 1)) - snd.mid_queue[pos+1][-1] = 0; - byte status = plr_play_file(&(snd.mid_queue[pos])[6], nowait); - if(pos != (snd.mid_queued - 1)) - snd.mid_queue[pos+1][-1] = '\n'; - snd.mid_queue[pos][0] = COL_GREEN[0]; - if(snd.mid_prevpos >= 0) - snd.mid_queue[snd.mid_prevpos][0] = COL_NEON[0]; - snd.mid_prevpos = pos; - return status; -} - -byte plr_stopped() { - return snd_query(SND_STAT_STOPPED, 0); -} - -// voices -- 2 ~ 192 -byte plr_setup(byte voices, const char *dmxname, const char *drumname, byte keep, byte useunkn, char velofunc) { - // if(dmxname) { - bank_instr *instr = bnk_read_banks(dmxname, drumname, 0); - if(!instr) - return 0; - snd_instruct(instr, sizeof(bank_instr) * 256, SND_CMD_VOICES, 0, 0); - mem_free(instr); - // } - voices = (voices & 1) ? (voices + 1) : voices; - // snd_instruct(NULL, 0, SND_CMD_BANK, dmxname ? 31 : bank, 0); - snd_instruct(NULL, 0, SND_CMD_MKOPL, 0, (uint)voices | ((uint)((byte)(velofunc & 0xff)) << 8) | ((uint)keep << 16) | ((uint)useunkn << 17)); - return 1; -} - -void plr_debug(byte debug) { - snd_instruct(NULL, 0, SND_CMD_DEBUG, 0, debug); - snd.mid_debug = debug; -} - -void plr_volume(byte channel, ushort volume) { - snd_instruct(NULL, 0, SND_CMD_VOLUME, channel, volume); -} - -enum repeat_type { - REPEAT_OFF, - REPEAT_SINGLE, - REPEAT_ALL, - REPEAT_SHUFFLE -}; - -void plr_end() { - if(snd.mid_queue) { - mem_free(snd.mid_queue); - mem_free(snd.mid_list); - } - snd.mid_queue = NULL; - snd.mid_list = NULL; - snd.mid_queued = 0; - snd_instruct(NULL, 0, SND_CMD_LOAD, 0, 0); - snd_instruct(NULL, 0, SND_CMD_MKOPL, 0, 0); -} - -byte plr_queue(const char *dmxname, const char *drumname, const char **files, int count) { - plr_end(); - if(!plr_setup(snd.mid_voices, dmxname, drumname, snd.mid_keep, snd.mid_unknown, (char)snd.mid_velo)) - return 0; - snd.mid_queue = mem_alloc(sizeof(char *) * count, MEM_FILE); - int size = 0; - for(int z = 0; z < count; z++) { - size += strlen(files[z]) + 7; - } - char *list = snd.mid_list = mem_alloc(size, MEM_FILE); - for(int z = 0; z < count; z++) { - snd.mid_queue[z] = list; - list += snprintf(list, 1024, (z == (count - 1)) ? COL_NEON "#%03d %s" : COL_NEON "#%03d %s\n", z + 1, files[z]); - } - snd.mid_queued = count; - snd.mid_playpos = -1; - snd.mid_prevpos = -1; -} - -void plr_mode(byte repeat) { - snd.mid_repeat = repeat; -} - -void plr_pause() { - if(!snd.mid_queue || (snd.mid_playpos == INT_MIN)) - return; - if(snd.mid_playpos >= -1) - snd.mid_playpos = -(snd.mid_playpos + 3); - else - snd.mid_playpos = -(snd.mid_playpos) - 3; - if(snd.mid_playpos >= 0 || snd.mid_playpos < -2) - snd.mid_queue[(snd.mid_playpos < -1) ? (-(snd.mid_playpos) - 3) : snd.mid_playpos][0] = snd.mid_playpos < -1 ? COL_YELLOW[0] : COL_GREEN[0]; - snd_instruct(NULL, 0, SND_CMD_PAUSE, 0, snd.mid_playpos < -1); -} - -void plr_stop() { - if(!snd.mid_queue) - return; - plr_cmlog(1); - snd.mid_playpos = INT_MIN; - if(snd.mid_prevpos >= 0) - snd.mid_queue[snd.mid_prevpos][0] = COL_NEON[0]; - snd.mid_prevpos = -1; - snd_instruct(NULL, 0, SND_CMD_LOAD, 0, 0); -} - -void plr_resume() { - if(!snd.mid_queue) - return; - if(snd.mid_playpos == INT_MIN) - plr_play(snd.mid_playpos = 0, snd.mid_nowait); - else if(snd.mid_playpos < -1) - plr_pause(); -} - -void plr_update() { - if(snd.mid_queue && (sys.tmr_current - snd.mid_poll) >= 250000ULL) { - snd.mid_poll = sys.tmr_current; - if((snd.mid_playpos >= -1) && plr_stopped()) { - if(snd.mid_playpos >= 0) { - switch(snd.mid_repeat) { - case REPEAT_OFF: - snd.mid_playpos += 1; - break; - case REPEAT_SINGLE: - break; - case REPEAT_ALL: - if((snd.mid_playpos += 1) >= snd.mid_queued) - snd.mid_playpos = 0; - break; - case REPEAT_SHUFFLE: - snd.mid_playpos = rand() % snd.mid_queued; - break; - } - } - else { - snd.mid_playpos = 0; - } - if(snd.mid_playpos >= snd.mid_queued) - plr_stop(); - else - plr_play(snd.mid_playpos, snd.mid_nowait); - if(snd.player && snd.player.open) { - gui_update_text(gui_get(snd.player, 1)); - gui_plr_update(snd.player); - } - } - } -} - -void plr_jump(int pos) { - if(!snd.mid_queue) - return; - plr_resume(); - pos = CLAMP_VALUE(pos, 0, snd.mid_queued - 1); - plr_play(snd.mid_playpos = pos, snd.mid_nowait); -} - -void plr_next() { - if(!snd.mid_queue) - return; - plr_resume(); - if((snd.mid_playpos += 1) >= snd.mid_queued) - snd.mid_playpos = 0; - plr_play(snd.mid_playpos, snd.mid_nowait); -} - -void plr_prev() { - if(!snd.mid_queue) - return; - plr_resume(); - if((snd.mid_playpos -= 1) < 0) - snd.mid_playpos = snd.mid_queued - 1; - plr_play(snd.mid_playpos, snd.mid_nowait); -} - -void plr_rand() { - if(!snd.mid_queue) - return; - plr_resume(); - plr_play((snd.mid_playpos = rand() % snd.mid_queued), snd.mid_nowait); -} - -void plr_capture(const char *wavname) { - snd_instruct(wavname, wavname ? (strlen(wavname) + 1) : 0, SND_CMD_WAVECAP, 0, 0); -} - -void plr_clog() { - snd.mid_klog_pos = 0; - snd.mid_klog_offs = 0; - for(int z = 0; z < SND_KLOG; z++) { - memset(&snd.mid_klogger[z * SND_KAR], ' ', SND_KAR - 1); - snd.mid_klogger[z * SND_KAR + (SND_KAR - 1)] = (z == (SND_KLOG - 1)) ? 0 : '\n'; - } - if(snd.player && snd.player.open) - gui_update_text(gui_get(snd.player, 16)); -} - -void plr_cmlog(byte empty) { - snd.mid_karaoke = 0; - for(int z = 0; z < 6; z++) { - snd.mid_info_offs[z] = empty ? 0 : sprintf(&snd.mid_info[z * SND_INFO], "%-12s: ", *(plr_descs[z])); - if(!empty) { - memset(&snd.mid_info[z * SND_INFO + snd.mid_info_offs[z]], ' ', SND_INFO - 1); - snd.mid_info[z * SND_INFO + (SND_INFO - 1)] = (z == 5) ? 0 : '\n'; - } - } - if(empty) - snd.mid_info[0] = 0; - plr_clog(); - if(snd.player && snd.player.open) - gui_update_text(gui_get(snd.player, 15)); -} - -void plr_kar() { - if(snd.mid_karaoke ^ 1) { - snd.mid_karaoke = 1; - plr_clog(); - } -} - -void plr_info(int type, const char *text) { - char *info = &snd.mid_info[type * SND_INFO]; - int offs = snd.mid_info_offs[type]; - int len = strlen(text); - int max = (SND_INFO - 1) - 14; - max -= (offs > 14) ? 2 : 0; - len = (len > (max-offs)) ? (max-offs) : len; - if(len <= 0) { - return; - } - if(offs > 14) { - info[offs++] = ';'; - info[offs++] = ' '; - } - // else { - // max = sprintf(info, "%-12s: ", *(plr_descs[type])); - // memset(info+(max + len), ' ', SND_INFO - (1 + max + len)); - // offs += max; - // } - memcpy(info+offs, text, len); - offs += len; - // info[SND_INFO - 1] = (type == 5) ? 0 : '\n'; - snd.mid_info_offs[type] = offs; - if(snd.player && snd.player.open) - gui_update_text(gui_get(snd.player, 15)); -} - -void plr_tlog(int type, const char *text) { - int slen = strlen(text); - // for(int h = 0; h < slen; h++) { - // text[h] = ((text[h] < 32) && (text[h] >= 0)) ? ((h == (slen-1)) ? 0 : '?') : text[h]; - // } - if((type == 1) && (text[0] == '@')) { - // text += 1; - switch(text[1]) { - case 'T': - plr_info(0, text+2); - return; - case 'I': - plr_info(1, text+2); - return; - case 'K': - plr_info(2, text+2); - return; - case 'W': - plr_info(3, text+2); - return; - case 'L': - plr_info(4, text+2); - return; - case 'V': - plr_info(5, text+2); - return; - } - // text += (text[0] == 0) ? 0 : 1; - } - else if((type == 1) && (text[0] == '%') && (text[1] == '-')) { - plr_kar(); - return; - } - else if(type == 1) { - switch(text[0]) { - case '\\': - plr_kar(); - plr_clog(); - text += 1; - slen -= 1; - break; - case '/': - // mid_kar(); - if(snd.mid_karaoke) { - snd.mid_klog_pos += 1; - snd.mid_klog_offs = 0; - if(snd.mid_klog_pos == SND_KLOG) - plr_clog(); - text += 1; - slen -= 1; - } - break; - } - if(snd.mid_karaoke) { - int len; - while(slen > 0) { - len = (slen > ((SND_KAR - 1) - snd.mid_klog_offs)) ? ((SND_KAR - 1) - snd.mid_klog_offs) : slen; - if(len <= 0) - break; - memcpy(&snd.mid_klogger[snd.mid_klog_pos * SND_KAR + snd.mid_klog_offs], text, len); - snd.mid_klog_offs += len; - // snd.mid_klogger[snd.mid_klog_pos * SND_KAR + snd.mid_klog_offs] = 0; - slen -= len; - if(slen > 0) { - snd.mid_klog_pos += 1; - snd.mid_klog_offs = 0; - if(snd.mid_klog_pos == SND_KLOG) - plr_clog(); - } - } - if(snd.player && snd.player.open) - gui_update_text(gui_get(snd.player, 16)); - return; - } - } - if(snd.mid_debug || (type <= 2) || (type >= 5)) - logd(LOG_CON, STR_MID_TEXT, type, text); -} - - - - - - - - - - - - - - - - - -void gui_fmt_velofunc(gui_t *elem, int value) { - snprintf(elem.text, elem.capacity, "%s %d: %s", elem.format_text, value, (value ? (value == -128 ? STR_MID_VELO_ONE : (value < 0 ? STR_MID_VELO_ATTN : STR_MID_VELO_LOG)) : STR_MID_VELO_LIN)); -} - -byte gui_init_sound(window_t *win, int frame_x, int frame_y, byte open) { - gui_add_cvtoggle(win, 20, 360, 340, 24, STR_MID_USEUNKN, "mid_play_unknown"); - gui_add_cvtoggle(win, 380, 360, 340, 24, STR_MID_KEEPNOTES, "mid_keep_notes"); - gui_add_cvtoggle(win, 20, 400, 340, 24, STR_MID_DONTFADE, "mid_dont_fade"); - gui_add_cvtoggle(win, 380, 400, 340, 24, STR_MID_DEBUGEVT, "mid_debug_events"); - gui_add_cvslider(win, 20, 440, 340, 24, STR_MID_VELOFUNC, "mid_velocity_func").format = gui_fmt_velofunc; - gui_add_cvslider(win, 380, 440, 340, 24, STR_MID_OPVOICES, "mid_opl_voices"); - return 0; -} - -void plr_mode(byte repeat); -void plr_pause(); -void plr_stop(); -void plr_resume(); -void plr_jump(int pos); -void plr_next(); -void plr_prev(); -void plr_rand(); - -void gui_plr_update_text(window_t *win) { - gui_t *elem = gui_get(win, 17); - const char *name = ""; - int pos = (snd.mid_queue && (snd.mid_playpos != INT_MIN)) ? ((snd.mid_playpos < -1) ? (-(snd.mid_playpos) - 3) : snd.mid_playpos) : -1; - if(pos >= 0) { - if(pos != (snd.mid_queued - 1)) - snd.mid_queue[pos+1][-1] = 0; - if(name = strrchr(&(snd.mid_queue[pos])[6], '/')) - name += 1; - else - name = &(snd.mid_queue[pos])[6]; - snprintf(elem.text, elem.capacity, "%s: %d/%d - %s", STR_PLR_INFO, pos + 1, snd.mid_queued, name); - if(pos != (snd.mid_queued - 1)) - snd.mid_queue[pos+1][-1] = '\n'; - } - else { - snprintf(elem.text, elem.capacity, "%s", STR_PLR_INFO); - } - gui_update_text(elem); -} - -void gui_plr_update(window_t *win) { - gui_t *elem = gui_get(win, 2); - snprintf(elem.text, elem.capacity, snd.mid_queue && (snd.mid_playpos >= -1) ? COL_GREEN SYM_PLAY : SYM_PLAY); - gui_update_text(elem); - elem = gui_get(win, 3); - snprintf(elem.text, elem.capacity, !snd.mid_queue || (snd.mid_playpos == INT_MIN) ? COL_RED SYM_STOP : SYM_STOP); - gui_update_text(elem); - elem = gui_get(win, 4); - snprintf(elem.text, elem.capacity, snd.mid_queue && (snd.mid_playpos != INT_MIN) && (snd.mid_playpos < -1) ? COL_YELLOW SYM_PAUSE : SYM_PAUSE); - gui_update_text(elem); - gui_plr_update_text(win); -} - -void gui_fnc_plr_start(gui_t *elem, int value) { - plr_resume(); - gui_update_text(gui_get(elem.window, 1)); - gui_plr_update(elem.window); -} - -void gui_fnc_plr_stop(gui_t *elem, int value) { - plr_stop(); - gui_update_text(gui_get(elem.window, 1)); - gui_plr_update(elem.window); -} - -void gui_fnc_plr_pause(gui_t *elem, int value) { - plr_pause(); - gui_update_text(gui_get(elem.window, 1)); - gui_plr_update(elem.window); -} - -void gui_fnc_plr_mode(gui_t *elem, int value) { - plr_mode((byte)value); -} - -void gui_fnc_plr_prev(gui_t *elem, int value) { - plr_prev(); - gui_update_text(gui_get(elem.window, 1)); - gui_plr_update(elem.window); -} - -void gui_fnc_plr_next(gui_t *elem, int value) { - plr_next(); - gui_update_text(gui_get(elem.window, 1)); - gui_plr_update(elem.window); -} - -void gui_fnc_plr_rand(gui_t *elem, int value) { - plr_rand(); - gui_update_text(gui_get(elem.window, 1)); - gui_plr_update(elem.window); -} - -void gui_fnc_plr_clear(gui_t *elem, int value) { - plr_stop(); - plr_end(); - elem = gui_get(elem.window, 1); - elem.text = &elem.window.strings[GUI_STR_SIZE * elem.id]; - elem.text[0] = 0; - elem.capacity = GUI_STR_SIZE; - gui_update_text(elem); - elem.sel_start = elem.sel_end = elem.sel_drag = 0; - gui_text_update_cur(elem, elem.sel_start, 1); - elem.sel_start = elem.sel_end = elem.sel_drag = -1; - gui_plr_update(elem.window); -} - -void gui_fnc_plr_open(gui_t *elem, int value) { -} - -static const char *gui_plr_modes[] = { - SYM_CONTINUOS, - SYM_REPEAT, - SYM_LOOPED, - SYM_SHUFFLE -}; - -void gui_fnc_plr_jump(gui_t *elem, int value) { - if(!value && str_parse_int(elem.text, &value, -10) && value && (value <= snd.mid_queued)) { - plr_jump(value - 1); - snprintf(elem.text, elem.capacity, SYM_JUMPTO "#"); - gui_update_text(elem); - gui_deselect(elem.window); - gui_text_update_cur(elem, elem.sel_start, 1); - gui_update_text(gui_get(elem.window, 1)); - gui_plr_update(elem.window); - } - else if(value == 4) { - elem.text[0] = 0; - gui_update_text(elem); - gui_text_update_cur(elem, elem.sel_start, 1); - } - else if(value == -4) { - snprintf(elem.text, elem.capacity, SYM_JUMPTO "#"); - gui_update_text(elem); - gui_text_update_cur(elem, elem.sel_start, 1); - } -} - -void gui_fnc_plr_load(gui_t *elem, int value) { - if(!value) { - int count; - const char **files = file_list(&count, elem.text, mid_extensions, 3); - if(files) { - count = count > 999 ? 999 : count; - plr_queue(snd_bankfiles[snd.mid_bank], NULL, files, count); - mem_free(files); - elem.text[0] = 0; - gui_update_text(elem); - gui_deselect(elem.window); - gui_text_update_cur(elem, elem.sel_start, 1); - elem = gui_get(elem.window, 1); - elem.text = snd.mid_list; - elem.capacity = strlen(snd.mid_list) + 1; - gui_update_text(elem); - elem.sel_start = elem.sel_end = elem.sel_drag = 0; - gui_text_update_cur(elem, elem.sel_start, 1); - elem.sel_start = elem.sel_end = elem.sel_drag = -1; - gui_plr_update(elem.window); - } - } -} - -void gui_fmt_bankdrop(gui_t *elem, int value) { - int pos = 0; - for(int z = 0; z < elem.max && pos < (elem.capacity - 1); z++) { - pos += snprintf(&elem.text[pos], elem.capacity - pos, z ? "\n%s%s" : "%s%s", ((const char **)elem.aux_data)[z], z < BNK_IDX_MELO_ONLY ? "" : (z < BNK_IDX_DRUM_ONLY ? " [0-127]" : " [128-255]")); - } -} - -static const uint plr_waveforms[] = {0xff00ff00, 0xffff0000, 0xff0000ff, 0xff00ffff, 0xffff00ff, 0xffffff00, 0xff80ff00, 0xff00ff80}; - -int gui_render_bar(gui_t *elem, int x, int y, int w, int h, uint top, uint bottom, uint bg, int v) { - v = (v < 0) ? 0 : v; - gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h, 0, 0, 0xff000000 | top, 0xff000000 | bottom, 0, 0); - if(++v < h) - gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h - v, 0, 0, 0xff000000 | bg, 0xff000000 | bg, 0, 0); - return h; -} - -int gui_render_grad(gui_t *elem, int x, int y, int w, int h, uint top, uint bottom) { - gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h, 0, 0, 0xff000000 | top, 0xff000000 | bottom, 0, 0); - return h; -} - -int gui_render_rect(gui_t *elem, int x, int y, int w, int h, uint color) { - gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h, 0, 0, 0xff000000 | color, 0xff000000 | color, 0, 0); - return h; -} - -int gui_render_text(gui_t *elem, int x, int y, uint color, const char *text) { - txt_draw(elem.pos_x + x, elem.pos_y + y, 0, sys.font.yglyph, sys.font.yglyph, elem.pos_x + x, elem.pos_y + y, elem.pos_x + elem.size_x, elem.pos_y + elem.size_y, - 0xff000000 | color, 0x00000000, &sys.font, text); - return sys.font.yglyph; -} - -void gui_render_player(gui_t *elem, int value) { - elem.t_dirty = 1; - if(!value) - gui_render_grad(elem, 0, 0, elem.size_x, elem.size_y, sys.style.field_btm, sys.style.field_top); - if(snd.mid_visual ^ 1) - return; - pthread_mutex_lock(&sgt.lock); - if(!sgt.chip || !sgt.bank) { - pthread_mutex_unlock(&sgt.lock); - return; - } - OPLChip chip = sgt.chip; - bank_handle *bank = sgt.bank; - int nch = chip.n_voices; - int bx = elem.size_x / 2 - (nch * 6 + 2) / 2; - int by = elem.size_y / 2 - (698 + 20 * 4) / 2; - int x = bx; - int y = by; - if(value) { - x = bx - 84; - sprintf(&sys.work_buf[str_time(sys.work_buf, sgt.mid_time)], "\n%c%c%c%c %c", - (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 0)) ? '*' : '.', - (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 1)) ? '*' : '.', - (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 2)) ? '*' : '.', - (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 3)) ? '*' : '.', - plr_wheel[(sgt.mid_tick >> 5) & 3]); - gui_render_text(elem, x, y + 20, 0xffffff, sys.work_buf); - sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d", STR_OPL_TICK, sgt.mid_tick); - gui_render_text(elem, x, y + 60, 0xffffff, sys.work_buf); - sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d / %d", STR_OPL_ACTIVE, bank.v_used, bank.voices.length); - gui_render_text(elem, x, y + 100, 0xffffff, sys.work_buf); - sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d +%dQ", STR_OPL_TEMPO, sgt.mid.uspb ? (60000000 / sgt.mid.uspb) : 0, sgt.mid.tpqn); - gui_render_text(elem, x, y + 140, 0xffffff, sys.work_buf); - x = bx; - pthread_mutex_unlock(&sgt.lock); - y += 3; - gui_render_text(elem, x, y, 0xffffff, STR_OPL_CHANNEL); - gui_render_text(elem, x, y + 20 + 226, 0xffffff, STR_OPL_MODULATOR); - gui_render_text(elem, x, y + 40 + 226 + 232, 0xffffff, STR_OPL_CARRIER); - gui_render_text(elem, x, y + 60 + 226 + 232 * 2, 0xffffff, STR_OPL_POINTER); - y -= 3; - // x -= 86; - x += nch * 6 + 2 + 1; - y += 20; - gui_render_text(elem, x, y + 0, 0xffffff, STR_OPL_OUTPUT); - gui_render_text(elem, x, y + 70, 0xffffff, STR_OPL_MODE); - gui_render_text(elem, x, y + 84, 0xffffff, STR_OPL_FEEDBACK); - gui_render_text(elem, x, y + 98, 0xffffff, STR_OPL_FREQUENCY); - y += 226 + 20; - for(int o = 0; o < 2; o++) { - gui_render_text(elem, x, y + 6, 0xffffff, STR_OPL_FLAGS); - gui_render_text(elem, x, y + 24, 0xffffff, STR_OPL_MULTIPLIER); - gui_render_text(elem, x, y + 42, 0xffffff, STR_OPL_LEVEL); - gui_render_text(elem, x, y + 96, 0xffffff, STR_OPL_KEYSCALE); - gui_render_text(elem, x, y + 110, 0xffffff, STR_OPL_WAVEFORM); - gui_render_text(elem, x, y + 124, 0xffffff, STR_OPL_ATTACK); - gui_render_text(elem, x, y + 142, 0xffffff, STR_OPL_DECAY); - gui_render_text(elem, x, y + 160, 0xffffff, STR_OPL_SUSTAIN); - gui_render_text(elem, x, y + 178, 0xffffff, STR_OPL_RELEASE); - gui_render_text(elem, x, y + 196, 0xffffff, STR_OPL_ENVELOPE); - y += 232 + 20; - } - return; - } - y += 20; - y += gui_render_rect(elem, x, y, nch * 6 + 2, 226, 0x3f0000) + 20; - y += gui_render_rect(elem, x, y, nch * 6 + 2, 232, 0x003f00) + 20; - y += gui_render_rect(elem, x, y, nch * 6 + 2, 232, 0x00003f) + 20; - y += gui_render_rect(elem, x, y, nch * 6 + 2, 8, 0x2f2f2f); - for(int c = 0; c < nch; c++) { - OPLChannel channel = &chip.channel[c]; - x = bx + 2 + 6 * c; - y = by + 2; - short **out = channel.out; - short accm = *out[0] + *out[1] + *out[2] + *out[3]; - int chnlvl = 0; - for(int n = 0; n < 2; n++) { - chnlvl += (short)((accm * channel.level[n]) >> 16); - } - chnlvl = chnlvl < 0 ? (-chnlvl) : chnlvl; - chnlvl = (chnlvl * 16) / 2048; - chnlvl = chnlvl > 64 ? 64 : chnlvl; - int freq = (int)((((float)channel.f_num * 49716.0f) / powf(2.0f, 20.0f - (float)channel.block)) / 6210.0f * 128.0f); - y += 20; - y += gui_render_bar(elem, x, y, 4, 64, 0xff0000, 0x00ff00, 0x000000, chnlvl) + 2; - y += gui_render_rect(elem, x, y, 4, 4, ((channel.slots[0].eg_out <= 0x100) || (channel.slots[1].eg_out <= 0x100)) ? 0x00ff00 : 0x000000) + 2; - y += gui_render_rect(elem, x - (c & 1), y, 5, 4, channel.chtype != ch_2op ? 0xff00ff : 0x000000) + 2; - y += gui_render_grad(elem, x, y, 4, 4, channel.con ? 0x00ff00 : 0x808080, 0x0000ff) + 2; - y += gui_render_bar(elem, x, y, 4, 8, 0x00ff00, 0xffff00, 0x000000, channel.fb) + 2; - y += gui_render_bar(elem, x, y, 4, 128, 0x707070, 0x505050, 0x000000, freq) + 2; - gui_render_rect(elem, x, y - 130 + (127 - freq), 4, 1, 0xff0000); - for(int o = 0; o < 2; o++) { - opl3_slot *slot = channel.slots[o]; - y += 2; - y += 20; - y += gui_render_rect(elem, x, y, 4, 4, slot.key ? 0x00ff00 : 0x000000) + 2; - y += gui_render_rect(elem, x, y, 4, 4, (slot.trem != (byte*)&slot.chip.zeromod) ? 0x5fdf00 : 0x000000); - y += gui_render_rect(elem, x, y, 4, 4, slot.reg_vib ? 0xffff00 : 0x000000); - y += gui_render_rect(elem, x, y, 4, 4, slot.reg_type ? 0xff0000 : 0x000000); - y += gui_render_rect(elem, x, y, 4, 4, slot.reg_ksr ? 0x5f00bf : 0x000000) + 2; - y += gui_render_bar(elem, x, y, 4, 16, 0xff0000, 0xffff00, 0x000000, slot.reg_mult) + 2; - y += gui_render_bar(elem, x, y, 4, 64, 0xff0000, 0x00ff00, 0x000000, 63 - slot.reg_tl) + 2; - y += gui_render_bar(elem, x, y, 4, 4, 0x7f00ff, 0x3f00ff, 0x000000, slot.reg_ksl) + 2; - y += gui_render_rect(elem, x, y, 4, 8, 0x000000) + 2; - gui_render_rect(elem, x, y - 10 + (7 - slot.reg_wf), 4, 1, plr_waveforms[slot.reg_wf]); - - y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 0 ? 0xff0000 : 0xaf0000, slot.eg_gen == 0 ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_ar) + 2; - y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 1 ? 0xff0000 : 0xaf0000, slot.eg_gen == 1 ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_dr) + 2; - y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 2 ? 0xff0000 : 0xaf0000, slot.eg_gen == 2 ? 0x00ffff : 0x00afaf, 0x000000, (slot.reg_sl > 15) ? 0 : (15 - slot.reg_sl)) + 2; - y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 3 ? 0xff0000 : 0xaf0000, slot.eg_gen == 3 ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_rr) + 2; - y += gui_render_bar(elem, x, y, 4, 32, 0xff0000, 0x0000ff, 0x000000, (0x1ff - slot.eg_rout) / 16) + 2; - } - y += 2; - y += 20; - gui_render_rect(elem, x, y, 4, 4, bank.voiceindex == c ? 0x00ffff : 0x000000); - } - pthread_mutex_unlock(&sgt.lock); -} - -byte gui_init_player(window_t *win, int frame_x, int frame_y, byte open) { - gui_add_fill(win, 0, 0, 696, 24, STR_TITLE_PLR_FULL); - - gui_add_field(win, 0, 24, 720, frame_y - 316, snd.mid_queue ? snd.mid_list : "", snd.mid_queue ? (strlen(snd.mid_list) + 1) : 0, NULL, 0, 0); - - gui_add_button(win, 0, frame_y - 24, 24, 24, SYM_PLAY, gui_fnc_plr_start); - gui_add_button(win, 24, frame_y - 24, 24, 24, SYM_STOP, gui_fnc_plr_stop); - gui_add_button(win, 48, frame_y - 24, 24, 24, SYM_PAUSE, gui_fnc_plr_pause); - gui_add_enum(win, 72, frame_y - 24, 24, 24, STR_PLR_MODE, gui_fnc_plr_mode, gui_plr_modes, 4, 0, snd.mid_repeat).format = gui_fmt_enums; - - gui_add_button(win, 120, frame_y - 24, 24, 24, SYM_PREV, gui_fnc_plr_prev); - gui_add_button(win, 144, frame_y - 24, 24, 24, SYM_NEXT, gui_fnc_plr_next); - gui_add_button(win, 168, frame_y - 24, 24, 24, SYM_PRANDOM, gui_fnc_plr_rand); - gui_add_field(win, 192, frame_y - 24, 48, 24, SYM_JUMPTO "#", 0, gui_fnc_plr_jump, 1, 1); - - gui_add_button(win, 264, frame_y - 24, 24, 24, SYM_DELETE, gui_fnc_plr_clear); - cvar_t *cv = cvar_get("mid_opl_bank"); - gui_t *elem = gui_add_dropup(win, 288, frame_y - 24, 192, 24, STR_MID_BANK, gui_fnc_cvar_bool, snd_banknames, cv.max, cv.def, cv.value); - elem.cv_data = cv; - elem = elem + 1; - elem.capacity = GUI_AUX_STR; - elem.text = win.str_aux; - elem.format = gui_fmt_bankdrop; - elem.cv_data = cv; - gui_add_field(win, 480, frame_y - 24, 216, 24, "", 0, gui_fnc_plr_load, 1, 1); - gui_add_button(win, 696, frame_y - 24, 24, 24, SYM_FOLDER, gui_fnc_plr_open); - - gui_add_field(win, 0, frame_y - 268, 720, 120, snd.mid_info, 6 * SND_INFO, NULL, 0, 0); - gui_add_field(win, 0, frame_y - 124, 720, 100, snd.mid_klogger, SND_KLOG * SND_KAR, NULL, 0, 0); - - gui_add_fill(win, 0, frame_y - 292, 720, 24, STR_PLR_INFO); - gui_add_fill(win, 96, frame_y - 24, 24, 24, ""); - gui_add_fill(win, 240, frame_y - 24, 24, 24, ""); - gui_add_fill(win, 0, frame_y - 148, 720, 24, STR_PLR_KARAOKE); - - gui_add_custom(win, 720, 0, frame_x - 720, frame_y, gui_render_player); - - gui_add_cvtoggle(win, 696, 0, 24, 24, "V", "mid_visualizer").format = gui_fmt_keep; - - // gui_add_nbutton(win, 0, 0, 160, 24, STR_BACK, GUI_MENU); - gui_plr_update(win); - // gui_reformat(); - return 0; -} -*/ private void push() { for(int z = 0; z < 2 * 2; z++) { diff --git a/client/src/main/java/client/audio/MidiDecoder.java b/client/src/main/java/client/audio/MidiDecoder.java index 5e2f0d3c..e54029cf 100644 --- a/client/src/main/java/client/audio/MidiDecoder.java +++ b/client/src/main/java/client/audio/MidiDecoder.java @@ -226,13 +226,16 @@ public class MidiDecoder { this.playing = true; } - public MidiDecoder(int voices, MidiBank bank, boolean keep, boolean useunkn, int velofunc, int start) { + public MidiDecoder(MidiBank bank, int start, int end, int delay, int note) { this.tracks = null; - this.tpqn = 0; + this.tpqn = note; this.nowait = false; - this.chip = new OPLChip(48000, voices, velofunc, 0, false, false); - this.bank = new MidiHandle(this.chip, bank.getData(), keep, useunkn); + this.chip = new OPLChip(48000, 16, 0, 0, false, false); + this.bank = new MidiHandle(this.chip, bank.getData(), false, true); this.ticktime = start; + this.uspb = end; + this.time = (long)delay * 1000000L; + this.debug = true; } private void setTempo(int tempo) { @@ -488,16 +491,17 @@ public class MidiDecoder { public long process() { if(this.tracks == null) { - this.bank.progchange(0, this.ticktime < 128 ? this.ticktime : 0); + int pos = this.ticktime + (this.tick % (this.uspb + 1 - this.ticktime)); + this.bank.progchange(0, pos < 128 ? pos : 0); this.bank.progchange(9, 0); - Log.SOUND.user("MIDI-Test %s%d", this.ticktime < 128 ? "#" : "P", this.ticktime < 128 ? this.ticktime : this.ticktime - 128); - this.bank.noteon(this.ticktime < 128 ? 0 : 9, this.ticktime < 128 ? 36 : this.ticktime - 128, 127); - this.ticktime++; - if(this.ticktime == 128) - this.ticktime = 128 + 35; - else if(this.ticktime == 128 + 82) - this.ticktime = 0; - return 500000000L; + Log.SOUND.user("MIDI-Test %s%d", pos < 128 ? "#" : "P", pos < 128 ? pos : pos - 128); + this.bank.noteon(pos < 128 ? 0 : 9, pos < 128 ? this.tpqn : pos - 128, 127); + pos++; + if(pos == 128) + pos = 128 + 35; + else if(pos == 128 + 82) + pos = 0; + return this.time; } if(!this.playing && (this.nowait || !this.chip.isPlaying())) { @@ -515,6 +519,7 @@ public class MidiDecoder { } public void setDebug(boolean debug) { - this.debug = debug; + if(this.tracks != null) + this.debug = debug; } } diff --git a/client/src/main/java/client/gui/GuiMenu.java b/client/src/main/java/client/gui/GuiMenu.java index cf5ef2bc..01d7a6a8 100644 --- a/client/src/main/java/client/gui/GuiMenu.java +++ b/client/src/main/java/client/gui/GuiMenu.java @@ -1,9 +1,6 @@ package client.gui; -import java.io.File; - import client.Client; -import client.Client.FileMode; import client.gui.character.GuiChar; import client.gui.character.GuiCharacters; import client.gui.element.ActButton; @@ -78,8 +75,9 @@ public class GuiMenu extends Gui { GuiMenu.this.gm.show(GuiServer.INSTANCE); } }, "Schnellverbindung")); - this.add(new NavButton(0, 40, 180, 0, GuiOptions.getPage(), "Einstellungen")); - this.infoButton = this.add(new ActButton(0, 60, 180, 0, new ButtonCallback() { + this.add(new NavButton(0, 40, 180, 0, GuiPlayer.INSTANCE, "MIDI-Player")); + this.add(new NavButton(0, 60, 180, 0, GuiOptions.getPage(), "Einstellungen")); + this.infoButton = this.add(new ActButton(0, 80, 180, 0, new ButtonCallback() { public void use(ActButton elem, PressType action) { GuiMenu.this.gm.show(GuiMenu.this.hacked == 10 ? GuiInfo.HAX : GuiInfo.INSTANCE); } @@ -102,30 +100,11 @@ public class GuiMenu extends Gui { } } }); - this.add(new ActButton(0, 90, 180, 0, new ButtonCallback() { + this.add(new ActButton(0, 110, 180, 0, new ButtonCallback() { public void use(ActButton elem, PressType action) { GuiMenu.this.gm.interrupted = true; } }, "Client schließen")); - this.add(new ActButton(0, 110, 180, 0, new ButtonCallback() { - public void use(ActButton elem, PressType action) { - GuiMenu.this.gm.showFileDialog(FileMode.FILE_LOAD, "MIDI laden", null, new FileCallback() { - public void selected(File file) { - GuiMenu.this.gm.playMidi(file); - } - }); - } - }, "MIDI-Player")); - this.add(new ActButton(0, 130, 180, 0, new ButtonCallback() { - public void use(ActButton elem, PressType action) { - GuiMenu.this.gm.testMidi(0); - } - }, "MIDI-Bank testen")); - this.add(new ActButton(0, 150, 180, 0, new ButtonCallback() { - public void use(ActButton elem, PressType action) { - GuiMenu.this.gm.stopMidi(); - } - }, "MIDI stoppen")); this.shift(); this.add(new Label(4, 4, 200, 0, Color.VIOLET + Client.VERSION, true)); this.splashLabel = this.add(new Label(0, 100, width, 0, "")); @@ -133,24 +112,16 @@ public class GuiMenu extends Gui { } else { this.add(new NavButton(0, 0, 180, 0, this.gm.charEditor ? GuiChar.INSTANCE : null, this.gm.charEditor ? "Zurück zum Editor" : "Zurück zum Spiel")); - this.add(new NavButton(0, 20, 180, 0, GuiOptions.getPage(), "Einstellungen")); + this.add(new NavButton(0, 20, 180, 0, GuiPlayer.INSTANCE, "MIDI-Player")); + this.add(new NavButton(0, 40, 180, 0, GuiOptions.getPage(), "Einstellungen")); if(!this.gm.charEditor) - this.add(new NavButton(0, 40, 180, 0, GuiCharacters.INSTANCE, "Charakter")).enabled = !(this.gm.player instanceof EntityCameraHolder); - this.add(new ActButton(0, this.gm.charEditor ? 50 : 70, 180, 0, new ButtonCallback() { + this.add(new NavButton(0, 60, 180, 0, GuiCharacters.INSTANCE, "Charakter")).enabled = !(this.gm.player instanceof EntityCameraHolder); + this.add(new ActButton(0, this.gm.charEditor ? 70 : 90, 180, 0, new ButtonCallback() { public void use(ActButton elem, PressType action) { GuiMenu.this.gm.unload(true); // GuiMenu.this.gm.displayGuiScreen(INSTANCE); } }, "Server verlassen")); - this.add(new ActButton(0, this.gm.charEditor ? 70 : 90, 180, 0, new ButtonCallback() { - public void use(ActButton elem, PressType action) { - GuiMenu.this.gm.showFileDialog(FileMode.FILE_LOAD, "MIDI laden", null, new FileCallback() { - public void selected(File file) { - GuiMenu.this.gm.playMidi(file); - } - }); - } - }, "MIDI-Player")); this.shift(); } } diff --git a/client/src/main/java/client/gui/GuiPlayer.java b/client/src/main/java/client/gui/GuiPlayer.java new file mode 100644 index 00000000..d0eea7fe --- /dev/null +++ b/client/src/main/java/client/gui/GuiPlayer.java @@ -0,0 +1,570 @@ +package client.gui; + +import java.io.File; +import java.nio.file.Files; + +import client.Client.FileMode; +import client.audio.MidiDecoder; +import client.gui.element.ActButton; +import client.gui.element.ButtonCallback; +import client.gui.element.Fill; +import client.gui.element.GuiList; +import client.gui.element.ListEntry; +import client.gui.element.NavButton; +import client.gui.element.PressType; +import client.renderer.Drawing; +import common.log.Log; +import common.rng.Random; + +public class GuiPlayer extends GuiList { + protected class SongEntry implements ListEntry { + private final File file; + + protected SongEntry(File file) { + this.file = file; + } + + public void draw(int x, int y, int width, int height, int mouseX, int mouseY, boolean hovered) { + Drawing.drawText(this.file.getName(), x + 3, y, GuiPlayer.this.playing && GuiPlayer.this.entry == this ? (GuiPlayer.this.paused != null ? 0xffffff00 : 0xff00ff00) : 0xffffffff); + } + + public void select(boolean dclick, int mx, int my) { + if(dclick) + GuiPlayer.this.select(); + } + } + + public static enum RepeatMode { + REPEAT_OFF("N"), + REPEAT_SINGLE("L"), + REPEAT_ALL("A"), + REPEAT_SHUFFLE("R"); + + private final String display; + + private RepeatMode(String display) { + this.display = display; + } + }; + + public static final GuiPlayer INSTANCE = new GuiPlayer(); + + private final Random rand = new Random(); + private MidiDecoder paused; + private int position = -1; + private SongEntry entry; + private boolean playing; + private RepeatMode mode = RepeatMode.REPEAT_OFF; + private ActButton playButton; + private ActButton stopButton; + private ActButton modeButton; + + private GuiPlayer() { + } + + private void updateDisplay() { + if(this.gm.open != this) + return; + this.playButton.setText(!this.elements.isEmpty() && this.playing && this.paused == null ? "=" : "*"); + this.modeButton.setText(this.mode.display); + } + + public void playMidi(int index) { + this.paused = null; + this.playing = true; + this.entry = this.getListEntry(this.position = index); + this.updateDisplay(); + File file = this.entry.file; + byte[] data; + try { + data = Files.readAllBytes(file.toPath()); + } + catch(Throwable e) { + Log.SOUND.error(e, "Konnte Datei '%s' nicht laden", file); + return; + } + MidiDecoder midi; + try { + midi = new MidiDecoder(data, this.gm.midiNoWait, this.gm.midiVoices, this.gm.midiBank, this.gm.midiKeep, this.gm.midiUnknown, this.gm.midiVelocity); + } + catch(Throwable e) { + Log.SOUND.error(e, "Konnte MIDI '%s' nicht laden", file); + return; + } + midi.setDebug(this.gm.midiDebug); + this.gm.getAudioInterface().alMidi(midi); + } + + public void test(int start, int end, int delay, int note) { + this.paused = null; + this.playing = false; + this.position = -1; + this.gm.getAudioInterface().alMidi(new MidiDecoder(this.gm.midiBank, start, end, delay, note)); + this.updateDisplay(); + } + + public void clear() { + this.stop(); + this.elements.clear(); + this.setSelected(-1); + this.updateDisplay(); + } + + public void remove() { + if(this.selectedElement >= 0) { + this.elements.remove(this.selectedElement); + if(this.playing && this.position == this.selectedElement) { + if(this.position == this.elements.size()) + this.stop(); + else + this.playMidi(this.position); + } + if(this.elements.isEmpty()) + this.setSelected(-1); + else if(this.selectedElement >= this.elements.size()) + this.setSelected(this.elements.size() - 1); + this.updateDisplay(); + } + } + + public void select() { + if(this.selectedElement >= 0) + this.playMidi(this.selectedElement); + } + + public void random() { + if(!this.elements.isEmpty()) + this.playMidi(this.rand.zrange(this.elements.size())); + } + + public void prev() { + if(!this.elements.isEmpty()) + this.playMidi(this.position <= 0 ? this.elements.size() - 1 : this.position - 1); + } + + public void next() { + if(!this.elements.isEmpty()) + this.playMidi(this.position >= this.elements.size() - 1 ? 0 : this.position + 1); + } + + public void mode(int dir) { + this.mode = dir == 0 ? RepeatMode.REPEAT_OFF : RepeatMode.values()[(RepeatMode.values().length + this.mode.ordinal() + dir) % RepeatMode.values().length]; + this.updateDisplay(); + } + + private static boolean isMidiFile(File file) { + String name = file.getName().toLowerCase(); + return name.endsWith(".mid") || name.endsWith(".midi") || name.endsWith(".kar"); + } + + public void add(File file) { + if(file.isDirectory()) { + File[] files = file.listFiles(sub -> sub.isDirectory() || GuiPlayer.isMidiFile(sub)); + if(files != null) { + for(File sub : files) { + this.add(sub); + } + } + } + else if(isMidiFile(file)) { + this.elements.add(new SongEntry(file)); + } + } + + public void stop() { + this.paused = null; + this.playing = false; + this.position = -1; + this.gm.getAudioInterface().alMidi(null); + this.updateDisplay(); + } + + public void play() { + MidiDecoder midi = this.gm.getAudioInterface().alGetMidi(); + if(midi != null) { + this.gm.getAudioInterface().alMidi(null); + this.paused = midi; + } + else { + this.playing = true; + if(this.paused != null) { + this.paused.setDebug(this.gm.midiDebug); + this.gm.getAudioInterface().alMidi(this.paused); + } + this.paused = null; + } + this.updateDisplay(); + } + + public void updatePlayer() { + if(!this.elements.isEmpty() && this.playing && this.paused == null && this.gm.getAudioInterface().alGetMidi() == null) { + if(this.position >= 0) { + switch(this.mode) { + case REPEAT_OFF: + this.position += 1; + break; + case REPEAT_SINGLE: + break; + case REPEAT_ALL: + if((this.position += 1) >= this.elements.size()) + this.position = 0; + break; + case REPEAT_SHUFFLE: + this.position = this.rand.zrange(this.elements.size()); + break; + } + } + else { + this.position = 0; + } + if(this.position >= this.elements.size()) { + this.playing = false; + this.position = -1; + this.updateDisplay(); + } + else { + this.playMidi(this.position); + } + } + } + + public void init(int width, int height) { + super.init(width, height); + this.setDimensions(320, height, 18, height - 18); + + this.add(new NavButton(0, 0, 60, 18, GuiMenu.INSTANCE, "Zurück")); + this.add(new Fill(60, 0, 242, 18, "SKC OPL MIDI Player v 0.0.1 (~ Sen)", true)); + this.addSelector("mid_visualizer", 302, 0, 18, 18); + + this.playButton = this.add(new ActButton(0, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.play(); + } + }, "*")); + this.stopButton = this.add(new ActButton(18, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.stop(); + } + }, "#")); + this.modeButton = this.add(new ActButton(36, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.mode(action == PressType.TERTIARY ? 0 : (action == PressType.SECONDARY ? -1 : 1)); + } + }, "")); + this.add(new ActButton(54, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.prev(); + } + }, "<")); + this.add(new ActButton(72, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.next(); + } + }, ">")); + this.add(new ActButton(90, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.random(); + } + }, "?")); + this.add(new ActButton(108, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.select(); + } + }, "~")); + this.add(new ActButton(126, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.remove(); + } + }, "-")); + this.add(new ActButton(144, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.clear(); + } + }, "X")); + + this.addSelector("mid_opl_bank", 162, height - 18, 122, -18); + this.add(new ActButton(284, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.gm.showFileDialog(FileMode.FILE_LOAD_MULTI, "MIDIs laden", null, new FileCallback() { + public void selected(File file) { + GuiPlayer.this.add(file); + } + }); + } + }, "+")); + this.add(new ActButton(302, height - 18, 18, 18, new ButtonCallback() { + public void use(ActButton elem, PressType action) { + GuiPlayer.this.gm.showFileDialog(FileMode.DIRECTORY_LOAD, "MIDIs laden", null, new FileCallback() { + public void selected(File file) { + GuiPlayer.this.add(file); + } + }); + } + }, "^")); +// this.add(new ActButton(0, 130, 180, 0, new ButtonCallback() { +// public void use(ActButton elem, PressType action) { +// GuiPlayer.this.test(0, 255, 500, 36); +// } +// }, "MIDI-Bank testen")); + +// gui_add_custom(win, 720, 0, frame_x - 720, frame_y, gui_render_player); + + this.updateDisplay(); + } + + public String getTitle() { + return "MIDI-Player"; + } + + public int getSlotHeight() { + return 20; + } + + /* +STR(OPL_CHANNEL, "", "Kanal") +STR(OPL_MODULATOR, "", "Operator 1 + 3 / Modulator") +STR(OPL_CARRIER, "", "Operator 2 + 4 / Träger") +STR(OPL_POINTER, "", "Stimmen-Zeiger") +STR(OPL_OUTPUT, "", "Pegel") +STR(OPL_MODE, "", "Modus/Al.") +STR(OPL_FEEDBACK, "", "Feedback") +STR(OPL_FREQUENCY, "", "Frequenz") +STR(OPL_FLAGS, "", "T-V-S-K") +STR(OPL_MULTIPLIER, "", "Frq.-Mult.") +STR(OPL_LEVEL, "", "Op.-Pegel") +STR(OPL_KEYSCALE, "", "Tst.-Skale") +STR(OPL_WAVEFORM, "", "Wellenf.") +STR(OPL_ATTACK, "", "Attack") +STR(OPL_DECAY, "", "Decay") +STR(OPL_SUSTAIN, "", "Sustain") +STR(OPL_RELEASE, "", "Release") +STR(OPL_ENVELOPE, "", "Hüllkurve") +STR(OPL_TICK, "", "Tick/Pos.") +STR(OPL_ACTIVE, "", "Aktiv") +STR(OPL_TEMPO, "", "Tempo BPM") + +STR(MID_PLAY, "s", "Spiele MIDI '$1'") +STR(CMD_PLAY_QUEUED, "d", "$1 MIDIs werden abgespielt") +STR(CMD_PLAY_STOPPED, "", "Wiedergabe ist angehalten") +STR(CMD_PLAY_PLAYING, "d", "$1 MIDIs sind in der Liste") +STR(CMD_PLAY_ENDED, "", "Wiedergabe gestoppt") +STR(CMD_PLAY_BANKID, "d", "Bank-ID: $1") + +STR(PLR_MODE_NORM, "", "Normal") +STR(PLR_MODE_REPEAT, "", "Wiederholen") +STR(PLR_MODE_LOOP, "", "Schleife") +STR(PLR_MODE_RAND, "", "Zufällig") +STR(PLR_START, "", "Start") +STR(PLR_STOP, "", "Stop") +STR(PLR_PAUSE, "", "Pause") +STR(PLR_MODE, "", "Modus") +STR(PLR_PREV, "", "Vorheriger") +STR(PLR_NEXT, "", "Nächster") +STR(PLR_RANDOM, "", "Zufälliger") +STR(PLR_JUMP, "", "Springe zu") + + +#define SYM_PLAY "\U00100000" +#define SYM_STOP "\U00100001" +#define SYM_PAUSE "\U00100002" +#define SYM_NEXT "\U00100003" +#define SYM_PREV "\U00100004" +#define SYM_FFORWARD "\U00100005" +#define SYM_FREVERSE "\U00100006" +#define SYM_CONTINUOS "\U00100007" +#define SYM_REPEAT "\U00100008" +#define SYM_LOOPED "\U00100009" +#define SYM_SHUFFLE "\U0010000a" +#define SYM_PRANDOM "\U0010000b" +#define SYM_JUMPTO "\U0010000c" +#define SYM_FOLDER "\U0010000d" +#define SYM_DELETE "\U0010000e" +#define SYM_SAVEDISK "\U0010000f" + + +static const char plr_wheel[] = { '/', '-', '\\', '|'}; + +void gui_fmt_velofunc(gui_t *elem, int value) { + snprintf(elem.text, elem.capacity, "%s %d: %s", elem.format_text, value, (value ? (value == -128 ? STR_MID_VELO_ONE : (value < 0 ? STR_MID_VELO_ATTN : STR_MID_VELO_LOG)) : STR_MID_VELO_LIN)); +} + +void gui_plr_update_text(window_t *win) { + gui_t *elem = gui_get(win, 17); + const char *name = ""; + int pos = (snd.mid_queue && (snd.mid_playpos != INT_MIN)) ? ((snd.mid_playpos < -1) ? (-(snd.mid_playpos) - 3) : snd.mid_playpos) : -1; + if(pos >= 0) { + if(pos != (snd.mid_queued - 1)) + snd.mid_queue[pos+1][-1] = 0; + if(name = strrchr(&(snd.mid_queue[pos])[6], '/')) + name += 1; + else + name = &(snd.mid_queue[pos])[6]; + snprintf(elem.text, elem.capacity, "%s: %d/%d - %s", STR_PLR_INFO, pos + 1, snd.mid_queued, name); + if(pos != (snd.mid_queued - 1)) + snd.mid_queue[pos+1][-1] = '\n'; + } + else { + snprintf(elem.text, elem.capacity, "%s", STR_PLR_INFO); + } + gui_update_text(elem); +} + +void gui_plr_update(window_t *win) { + gui_t *elem = gui_get(win, 2); + snprintf(elem.text, elem.capacity, snd.mid_queue && (snd.mid_playpos >= -1) ? COL_GREEN SYM_PLAY : SYM_PLAY); + gui_update_text(elem); + elem = gui_get(win, 3); + snprintf(elem.text, elem.capacity, !snd.mid_queue || (snd.mid_playpos == INT_MIN) ? COL_RED SYM_STOP : SYM_STOP); + gui_update_text(elem); + elem = gui_get(win, 4); + snprintf(elem.text, elem.capacity, snd.mid_queue && (snd.mid_playpos != INT_MIN) && (snd.mid_playpos < -1) ? COL_YELLOW SYM_PAUSE : SYM_PAUSE); + gui_update_text(elem); + gui_plr_update_text(win); +} + +static const uint plr_waveforms[] = {0xff00ff00, 0xffff0000, 0xff0000ff, 0xff00ffff, 0xffff00ff, 0xffffff00, 0xff80ff00, 0xff00ff80}; + +int gui_render_bar(gui_t *elem, int x, int y, int w, int h, uint top, uint bottom, uint bg, int v) { + v = (v < 0) ? 0 : v; + gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h, 0, 0, 0xff000000 | top, 0xff000000 | bottom, 0, 0); + if(++v < h) + gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h - v, 0, 0, 0xff000000 | bg, 0xff000000 | bg, 0, 0); + return h; +} + +int gui_render_grad(gui_t *elem, int x, int y, int w, int h, uint top, uint bottom) { + gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h, 0, 0, 0xff000000 | top, 0xff000000 | bottom, 0, 0); + return h; +} + +int gui_render_rect(gui_t *elem, int x, int y, int w, int h, uint color) { + gfx_draw_rect(elem.pos_x + x, elem.pos_y + y, w, h, 0, 0, 0xff000000 | color, 0xff000000 | color, 0, 0); + return h; +} + +int gui_render_text(gui_t *elem, int x, int y, uint color, const char *text) { + txt_draw(elem.pos_x + x, elem.pos_y + y, 0, sys.font.yglyph, sys.font.yglyph, elem.pos_x + x, elem.pos_y + y, elem.pos_x + elem.size_x, elem.pos_y + elem.size_y, + 0xff000000 | color, 0x00000000, &sys.font, text); + return sys.font.yglyph; +} + +void gui_render_player(gui_t *elem, int value) { + elem.t_dirty = 1; + if(!value) + gui_render_grad(elem, 0, 0, elem.size_x, elem.size_y, sys.style.field_btm, sys.style.field_top); + if(snd.mid_visual ^ 1) + return; + pthread_mutex_lock(&sgt.lock); + if(!sgt.chip || !sgt.bank) { + pthread_mutex_unlock(&sgt.lock); + return; + } + OPLChip chip = sgt.chip; + bank_handle *bank = sgt.bank; + int nch = chip.n_voices; + int bx = elem.size_x / 2 - (nch * 6 + 2) / 2; + int by = elem.size_y / 2 - (698 + 20 * 4) / 2; + int x = bx; + int y = by; + if(value) { + x = bx - 84; + sprintf(&sys.work_buf[str_time(sys.work_buf, sgt.mid_time)], "\n%c%c%c%c %c", + (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 0)) ? '*' : '.', + (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 1)) ? '*' : '.', + (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 2)) ? '*' : '.', + (sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 3)) ? '*' : '.', + plr_wheel[(sgt.mid_tick >> 5) & 3]); + gui_render_text(elem, x, y + 20, 0xffffff, sys.work_buf); + sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d", STR_OPL_TICK, sgt.mid_tick); + gui_render_text(elem, x, y + 60, 0xffffff, sys.work_buf); + sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d / %d", STR_OPL_ACTIVE, bank.v_used, bank.voices.length); + gui_render_text(elem, x, y + 100, 0xffffff, sys.work_buf); + sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d +%dQ", STR_OPL_TEMPO, sgt.mid.uspb ? (60000000 / sgt.mid.uspb) : 0, sgt.mid.tpqn); + gui_render_text(elem, x, y + 140, 0xffffff, sys.work_buf); + x = bx; + pthread_mutex_unlock(&sgt.lock); + y += 3; + gui_render_text(elem, x, y, 0xffffff, STR_OPL_CHANNEL); + gui_render_text(elem, x, y + 20 + 226, 0xffffff, STR_OPL_MODULATOR); + gui_render_text(elem, x, y + 40 + 226 + 232, 0xffffff, STR_OPL_CARRIER); + gui_render_text(elem, x, y + 60 + 226 + 232 * 2, 0xffffff, STR_OPL_POINTER); + y -= 3; + // x -= 86; + x += nch * 6 + 2 + 1; + y += 20; + gui_render_text(elem, x, y + 0, 0xffffff, STR_OPL_OUTPUT); + gui_render_text(elem, x, y + 70, 0xffffff, STR_OPL_MODE); + gui_render_text(elem, x, y + 84, 0xffffff, STR_OPL_FEEDBACK); + gui_render_text(elem, x, y + 98, 0xffffff, STR_OPL_FREQUENCY); + y += 226 + 20; + for(int o = 0; o < 2; o++) { + gui_render_text(elem, x, y + 6, 0xffffff, STR_OPL_FLAGS); + gui_render_text(elem, x, y + 24, 0xffffff, STR_OPL_MULTIPLIER); + gui_render_text(elem, x, y + 42, 0xffffff, STR_OPL_LEVEL); + gui_render_text(elem, x, y + 96, 0xffffff, STR_OPL_KEYSCALE); + gui_render_text(elem, x, y + 110, 0xffffff, STR_OPL_WAVEFORM); + gui_render_text(elem, x, y + 124, 0xffffff, STR_OPL_ATTACK); + gui_render_text(elem, x, y + 142, 0xffffff, STR_OPL_DECAY); + gui_render_text(elem, x, y + 160, 0xffffff, STR_OPL_SUSTAIN); + gui_render_text(elem, x, y + 178, 0xffffff, STR_OPL_RELEASE); + gui_render_text(elem, x, y + 196, 0xffffff, STR_OPL_ENVELOPE); + y += 232 + 20; + } + return; + } + y += 20; + y += gui_render_rect(elem, x, y, nch * 6 + 2, 226, 0x3f0000) + 20; + y += gui_render_rect(elem, x, y, nch * 6 + 2, 232, 0x003f00) + 20; + y += gui_render_rect(elem, x, y, nch * 6 + 2, 232, 0x00003f) + 20; + y += gui_render_rect(elem, x, y, nch * 6 + 2, 8, 0x2f2f2f); + for(int c = 0; c < nch; c++) { + OPLChannel channel = &chip.channel[c]; + x = bx + 2 + 6 * c; + y = by + 2; + short **out = channel.out; + short accm = *out[0] + *out[1] + *out[2] + *out[3]; + int chnlvl = 0; + for(int n = 0; n < 2; n++) { + chnlvl += (short)((accm * channel.level[n]) >> 16); + } + chnlvl = chnlvl < 0 ? (-chnlvl) : chnlvl; + chnlvl = (chnlvl * 16) / 2048; + chnlvl = chnlvl > 64 ? 64 : chnlvl; + int freq = (int)((((float)channel.f_num * 49716.0f) / powf(2.0f, 20.0f - (float)channel.block)) / 6210.0f * 128.0f); + y += 20; + y += gui_render_bar(elem, x, y, 4, 64, 0xff0000, 0x00ff00, 0x000000, chnlvl) + 2; + y += gui_render_rect(elem, x, y, 4, 4, ((channel.slots[0].eg_out <= 0x100) || (channel.slots[1].eg_out <= 0x100)) ? 0x00ff00 : 0x000000) + 2; + y += gui_render_rect(elem, x - (c & 1), y, 5, 4, channel.chtype != ch_2op ? 0xff00ff : 0x000000) + 2; + y += gui_render_grad(elem, x, y, 4, 4, channel.con ? 0x00ff00 : 0x808080, 0x0000ff) + 2; + y += gui_render_bar(elem, x, y, 4, 8, 0x00ff00, 0xffff00, 0x000000, channel.fb) + 2; + y += gui_render_bar(elem, x, y, 4, 128, 0x707070, 0x505050, 0x000000, freq) + 2; + gui_render_rect(elem, x, y - 130 + (127 - freq), 4, 1, 0xff0000); + for(int o = 0; o < 2; o++) { + opl3_slot *slot = channel.slots[o]; + y += 2; + y += 20; + y += gui_render_rect(elem, x, y, 4, 4, slot.key ? 0x00ff00 : 0x000000) + 2; + y += gui_render_rect(elem, x, y, 4, 4, (slot.trem != (byte*)&slot.chip.zeromod) ? 0x5fdf00 : 0x000000); + y += gui_render_rect(elem, x, y, 4, 4, slot.reg_vib ? 0xffff00 : 0x000000); + y += gui_render_rect(elem, x, y, 4, 4, slot.reg_type ? 0xff0000 : 0x000000); + y += gui_render_rect(elem, x, y, 4, 4, slot.reg_ksr ? 0x5f00bf : 0x000000) + 2; + y += gui_render_bar(elem, x, y, 4, 16, 0xff0000, 0xffff00, 0x000000, slot.reg_mult) + 2; + y += gui_render_bar(elem, x, y, 4, 64, 0xff0000, 0x00ff00, 0x000000, 63 - slot.reg_tl) + 2; + y += gui_render_bar(elem, x, y, 4, 4, 0x7f00ff, 0x3f00ff, 0x000000, slot.reg_ksl) + 2; + y += gui_render_rect(elem, x, y, 4, 8, 0x000000) + 2; + gui_render_rect(elem, x, y - 10 + (7 - slot.reg_wf), 4, 1, plr_waveforms[slot.reg_wf]); + + y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 0 ? 0xff0000 : 0xaf0000, slot.eg_gen == 0 ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_ar) + 2; + y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 1 ? 0xff0000 : 0xaf0000, slot.eg_gen == 1 ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_dr) + 2; + y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 2 ? 0xff0000 : 0xaf0000, slot.eg_gen == 2 ? 0x00ffff : 0x00afaf, 0x000000, (slot.reg_sl > 15) ? 0 : (15 - slot.reg_sl)) + 2; + y += gui_render_bar(elem, x, y, 4, 16, slot.eg_gen == 3 ? 0xff0000 : 0xaf0000, slot.eg_gen == 3 ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_rr) + 2; + y += gui_render_bar(elem, x, y, 4, 32, 0xff0000, 0x0000ff, 0x000000, (0x1ff - slot.eg_rout) / 16) + 2; + } + y += 2; + y += 20; + gui_render_rect(elem, x, y, 4, 4, bank.voiceindex == c ? 0x00ffff : 0x000000); + } + pthread_mutex_unlock(&sgt.lock); +} +*/ +} diff --git a/client/src/main/java/client/vars/EnumVar.java b/client/src/main/java/client/vars/EnumVar.java index e46eee7f..bb2345dd 100644 --- a/client/src/main/java/client/vars/EnumVar.java +++ b/client/src/main/java/client/vars/EnumVar.java @@ -81,7 +81,7 @@ public class EnumVar extends BaseVar { if(this.useSwitch) return this.switcher(x, y, w, h); try { - return new Dropdown(x, y, w, h, false, (T[])this.field.getType().getEnumConstants(), this.def, (T)this.field.get(this.object), new DropdownCallback() { + return new Dropdown(x, y, w, h < 0 ? -h : h, h < 0, (T[])this.field.getType().getEnumConstants(), this.def, (T)this.field.get(this.object), new DropdownCallback() { public void use(Dropdown elem, T value) { EnumVar.this.parse(value instanceof Identifyable ? ((Identifyable)value).getName() : value.toString()); }