add note preview feature
This commit is contained in:
parent
0479650597
commit
be3b4da834
|
@ -1542,12 +1542,14 @@ int DivEngine::calcFreq(int base, int pitch, bool period) {
|
||||||
|
|
||||||
void DivEngine::play() {
|
void DivEngine::play() {
|
||||||
isBusy.lock();
|
isBusy.lock();
|
||||||
|
freelance=false;
|
||||||
playSub(false);
|
playSub(false);
|
||||||
isBusy.unlock();
|
isBusy.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivEngine::stop() {
|
void DivEngine::stop() {
|
||||||
isBusy.lock();
|
isBusy.lock();
|
||||||
|
freelance=false;
|
||||||
playing=false;
|
playing=false;
|
||||||
extValuePresent=false;
|
extValuePresent=false;
|
||||||
isBusy.unlock();
|
isBusy.unlock();
|
||||||
|
@ -1693,7 +1695,7 @@ unsigned char DivEngine::getExtValue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivEngine::isPlaying() {
|
bool DivEngine::isPlaying() {
|
||||||
return playing;
|
return (playing && !freelance);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivEngine::isChannelMuted(int chan) {
|
bool DivEngine::isChannelMuted(int chan) {
|
||||||
|
@ -1902,7 +1904,7 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
||||||
}
|
}
|
||||||
song.ordersLen++;
|
song.ordersLen++;
|
||||||
curOrder++;
|
curOrder++;
|
||||||
if (playing) {
|
if (playing && !freelance) {
|
||||||
playSub(false);
|
playSub(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1919,7 +1921,7 @@ void DivEngine::deleteOrder() {
|
||||||
}
|
}
|
||||||
song.ordersLen--;
|
song.ordersLen--;
|
||||||
if (curOrder>=song.ordersLen) curOrder=song.ordersLen-1;
|
if (curOrder>=song.ordersLen) curOrder=song.ordersLen-1;
|
||||||
if (playing) {
|
if (playing && !freelance) {
|
||||||
playSub(false);
|
playSub(false);
|
||||||
}
|
}
|
||||||
isBusy.unlock();
|
isBusy.unlock();
|
||||||
|
@ -1937,7 +1939,7 @@ void DivEngine::moveOrderUp() {
|
||||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder-1];
|
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder-1];
|
||||||
}
|
}
|
||||||
curOrder--;
|
curOrder--;
|
||||||
if (playing) {
|
if (playing && !freelance) {
|
||||||
playSub(false);
|
playSub(false);
|
||||||
}
|
}
|
||||||
isBusy.unlock();
|
isBusy.unlock();
|
||||||
|
@ -1955,17 +1957,39 @@ void DivEngine::moveOrderDown() {
|
||||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder+1];
|
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder+1];
|
||||||
}
|
}
|
||||||
curOrder++;
|
curOrder++;
|
||||||
if (playing) {
|
if (playing && !freelance) {
|
||||||
playSub(false);
|
playSub(false);
|
||||||
}
|
}
|
||||||
isBusy.unlock();
|
isBusy.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivEngine::noteOn(int chan, int ins, int note, int vol) {
|
||||||
|
isBusy.lock();
|
||||||
|
pendingNotes.push(DivNoteEvent(chan,ins,note,vol,true));
|
||||||
|
if (!playing) {
|
||||||
|
reset();
|
||||||
|
freelance=true;
|
||||||
|
playing=true;
|
||||||
|
}
|
||||||
|
isBusy.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivEngine::noteOff(int chan) {
|
||||||
|
isBusy.lock();
|
||||||
|
pendingNotes.push(DivNoteEvent(chan,-1,-1,-1,false));
|
||||||
|
if (!playing) {
|
||||||
|
reset();
|
||||||
|
freelance=true;
|
||||||
|
playing=true;
|
||||||
|
}
|
||||||
|
isBusy.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void DivEngine::setOrder(unsigned char order) {
|
void DivEngine::setOrder(unsigned char order) {
|
||||||
isBusy.lock();
|
isBusy.lock();
|
||||||
curOrder=order;
|
curOrder=order;
|
||||||
if (order>=song.ordersLen) curOrder=0;
|
if (order>=song.ordersLen) curOrder=0;
|
||||||
if (playing) {
|
if (playing && !freelance) {
|
||||||
playSub(false);
|
playSub(false);
|
||||||
}
|
}
|
||||||
isBusy.unlock();
|
isBusy.unlock();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "blip_buf.h"
|
#include "blip_buf.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#define DIV_VERSION "0.1"
|
#define DIV_VERSION "0.1"
|
||||||
#define DIV_ENGINE_VERSION 11
|
#define DIV_ENGINE_VERSION 11
|
||||||
|
@ -67,6 +68,17 @@ struct DivChannelState {
|
||||||
inPorta(false) {}
|
inPorta(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DivNoteEvent {
|
||||||
|
int channel, ins, note, volume;
|
||||||
|
bool on;
|
||||||
|
DivNoteEvent(int c, int i, int n, int v, bool o):
|
||||||
|
channel(c),
|
||||||
|
ins(i),
|
||||||
|
note(n),
|
||||||
|
volume(v),
|
||||||
|
on(o) {}
|
||||||
|
};
|
||||||
|
|
||||||
class DivEngine {
|
class DivEngine {
|
||||||
DivDispatch* dispatch;
|
DivDispatch* dispatch;
|
||||||
TAAudio* output;
|
TAAudio* output;
|
||||||
|
@ -74,6 +86,7 @@ class DivEngine {
|
||||||
int chans;
|
int chans;
|
||||||
bool active;
|
bool active;
|
||||||
bool playing;
|
bool playing;
|
||||||
|
bool freelance;
|
||||||
bool speedAB;
|
bool speedAB;
|
||||||
bool endOfSong;
|
bool endOfSong;
|
||||||
bool consoleMode;
|
bool consoleMode;
|
||||||
|
@ -87,6 +100,7 @@ class DivEngine {
|
||||||
DivChannelState chan[17];
|
DivChannelState chan[17];
|
||||||
DivAudioEngines audioEngine;
|
DivAudioEngines audioEngine;
|
||||||
std::map<String,String> conf;
|
std::map<String,String> conf;
|
||||||
|
std::queue<DivNoteEvent> pendingNotes;
|
||||||
bool isMuted[17];
|
bool isMuted[17];
|
||||||
std::mutex isBusy;
|
std::mutex isBusy;
|
||||||
String configPath;
|
String configPath;
|
||||||
|
@ -302,6 +316,12 @@ class DivEngine {
|
||||||
// move order down
|
// move order down
|
||||||
void moveOrderDown();
|
void moveOrderDown();
|
||||||
|
|
||||||
|
// play note
|
||||||
|
void noteOn(int chan, int ins, int note, int vol=-1);
|
||||||
|
|
||||||
|
// stop note
|
||||||
|
void noteOff(int chan);
|
||||||
|
|
||||||
// go to order
|
// go to order
|
||||||
void setOrder(unsigned char order);
|
void setOrder(unsigned char order);
|
||||||
|
|
||||||
|
@ -347,6 +367,7 @@ class DivEngine {
|
||||||
chans(0),
|
chans(0),
|
||||||
active(false),
|
active(false),
|
||||||
playing(false),
|
playing(false),
|
||||||
|
freelance(false),
|
||||||
speedAB(false),
|
speedAB(false),
|
||||||
endOfSong(false),
|
endOfSong(false),
|
||||||
consoleMode(false),
|
consoleMode(false),
|
||||||
|
|
|
@ -705,108 +705,123 @@ bool DivEngine::nextTick(bool noAccum) {
|
||||||
cycles++;
|
cycles++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (--ticks<=0) {
|
while (!pendingNotes.empty()) {
|
||||||
ret=endOfSong;
|
DivNoteEvent& note=pendingNotes.front();
|
||||||
if (endOfSong) {
|
if (note.on) {
|
||||||
playSub(true);
|
dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins));
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,note.channel,note.note));
|
||||||
|
} else {
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel));
|
||||||
}
|
}
|
||||||
endOfSong=false;
|
pendingNotes.pop();
|
||||||
nextRow();
|
|
||||||
}
|
}
|
||||||
// process stuff
|
|
||||||
for (int i=0; i<chans; i++) {
|
if (!freelance) {
|
||||||
if (chan[i].rowDelay>0) {
|
if (--ticks<=0) {
|
||||||
if (--chan[i].rowDelay==0) {
|
ret=endOfSong;
|
||||||
processRow(i,true);
|
if (endOfSong) {
|
||||||
|
playSub(true);
|
||||||
}
|
}
|
||||||
|
endOfSong=false;
|
||||||
|
nextRow();
|
||||||
}
|
}
|
||||||
if (chan[i].volSpeed!=0) {
|
// process stuff
|
||||||
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
for (int i=0; i<chans; i++) {
|
||||||
chan[i].volume+=chan[i].volSpeed;
|
if (chan[i].rowDelay>0) {
|
||||||
if (chan[i].volume>chan[i].volMax) {
|
if (--chan[i].rowDelay==0) {
|
||||||
chan[i].volume=chan[i].volMax;
|
processRow(i,true);
|
||||||
chan[i].volSpeed=0;
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
|
||||||
} else if (chan[i].volume<0) {
|
|
||||||
chan[i].volSpeed=0;
|
|
||||||
chan[i].volume=chan[i].volMax+1;
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
|
||||||
} else {
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chan[i].vibratoDepth>0) {
|
|
||||||
chan[i].vibratoPos+=chan[i].vibratoRate;
|
|
||||||
if (chan[i].vibratoPos>=64) chan[i].vibratoPos-=64;
|
|
||||||
switch (chan[i].vibratoDir) {
|
|
||||||
case 1: // up
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MAX(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
|
||||||
break;
|
|
||||||
case 2: // down
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MIN(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
|
||||||
break;
|
|
||||||
default: // both
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (chan[i].portaSpeed>0) {
|
|
||||||
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed,chan[i].portaNote))==2 && chan[i].portaStop) {
|
|
||||||
chan[i].portaSpeed=0;
|
|
||||||
chan[i].oldNote=chan[i].note;
|
|
||||||
chan[i].note=chan[i].portaNote;
|
|
||||||
chan[i].inPorta=false;
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chan[i].cut>0) {
|
|
||||||
if (--chan[i].cut<1) {
|
|
||||||
chan[i].oldNote=chan[i].note;
|
|
||||||
chan[i].note=-1;
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chan[i].arp!=0 && !chan[i].arpYield && chan[i].portaSpeed<1) {
|
|
||||||
if (--chan[i].arpTicks<1) {
|
|
||||||
chan[i].arpTicks=song.arpLen;
|
|
||||||
chan[i].arpStage++;
|
|
||||||
if (chan[i].arpStage>2) chan[i].arpStage=0;
|
|
||||||
switch (chan[i].arpStage) {
|
|
||||||
case 0:
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note+(chan[i].arp>>4)));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note+(chan[i].arp&15)));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
if (chan[i].volSpeed!=0) {
|
||||||
chan[i].arpYield=false;
|
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
||||||
|
chan[i].volume+=chan[i].volSpeed;
|
||||||
|
if (chan[i].volume>chan[i].volMax) {
|
||||||
|
chan[i].volume=chan[i].volMax;
|
||||||
|
chan[i].volSpeed=0;
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
|
} else if (chan[i].volume<0) {
|
||||||
|
chan[i].volSpeed=0;
|
||||||
|
chan[i].volume=chan[i].volMax+1;
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
|
} else {
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].vibratoDepth>0) {
|
||||||
|
chan[i].vibratoPos+=chan[i].vibratoRate;
|
||||||
|
if (chan[i].vibratoPos>=64) chan[i].vibratoPos-=64;
|
||||||
|
switch (chan[i].vibratoDir) {
|
||||||
|
case 1: // up
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MAX(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
||||||
|
break;
|
||||||
|
case 2: // down
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MIN(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
||||||
|
break;
|
||||||
|
default: // both
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (chan[i].portaSpeed>0) {
|
||||||
|
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed,chan[i].portaNote))==2 && chan[i].portaStop) {
|
||||||
|
chan[i].portaSpeed=0;
|
||||||
|
chan[i].oldNote=chan[i].note;
|
||||||
|
chan[i].note=chan[i].portaNote;
|
||||||
|
chan[i].inPorta=false;
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].cut>0) {
|
||||||
|
if (--chan[i].cut<1) {
|
||||||
|
chan[i].oldNote=chan[i].note;
|
||||||
|
chan[i].note=-1;
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].arp!=0 && !chan[i].arpYield && chan[i].portaSpeed<1) {
|
||||||
|
if (--chan[i].arpTicks<1) {
|
||||||
|
chan[i].arpTicks=song.arpLen;
|
||||||
|
chan[i].arpStage++;
|
||||||
|
if (chan[i].arpStage>2) chan[i].arpStage=0;
|
||||||
|
switch (chan[i].arpStage) {
|
||||||
|
case 0:
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note+(chan[i].arp>>4)));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note+(chan[i].arp&15)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[i].arpYield=false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// system tick
|
// system tick
|
||||||
dispatch->tick();
|
dispatch->tick();
|
||||||
|
|
||||||
if (!noAccum) totalTicks++;
|
if (!freelance) {
|
||||||
|
if (!noAccum) totalTicks++;
|
||||||
|
|
||||||
int hz;
|
int hz;
|
||||||
if (song.customTempo) {
|
if (song.customTempo) {
|
||||||
hz=song.hz;
|
hz=song.hz;
|
||||||
} else if (song.pal) {
|
} else if (song.pal) {
|
||||||
hz=60;
|
hz=60;
|
||||||
} else {
|
} else {
|
||||||
hz=50;
|
hz=50;
|
||||||
}
|
}
|
||||||
if (consoleMode) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalTicks/(hz*3600),(totalTicks/(hz*60))%60,(totalTicks/hz)%60,totalTicks%hz,curOrder,song.ordersLen,curRow,song.patLen,cmdsPerSecond);
|
if (consoleMode) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalTicks/(hz*3600),(totalTicks/(hz*60))%60,(totalTicks/hz)%60,totalTicks%hz,curOrder,song.ordersLen,curRow,song.patLen,cmdsPerSecond);
|
||||||
|
|
||||||
if ((totalTicks%hz)==0) {
|
if ((totalTicks%hz)==0) {
|
||||||
cmdsPerSecond=totalCmds-lastCmds;
|
cmdsPerSecond=totalCmds-lastCmds;
|
||||||
lastCmds=totalCmds;
|
lastCmds=totalCmds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -124,7 +124,7 @@ struct DivSong {
|
||||||
speed1(6),
|
speed1(6),
|
||||||
speed2(6),
|
speed2(6),
|
||||||
arpLen(1),
|
arpLen(1),
|
||||||
pal(false),
|
pal(true),
|
||||||
customTempo(false),
|
customTempo(false),
|
||||||
hz(60),
|
hz(60),
|
||||||
patLen(64),
|
patLen(64),
|
||||||
|
|
136
src/gui/gui.cpp
136
src/gui/gui.cpp
|
@ -270,6 +270,8 @@ void FurnaceGUI::drawEditControls() {
|
||||||
if (ImGui::Button(ICON_FA_STOP "##Stop")) {
|
if (ImGui::Button(ICON_FA_STOP "##Stop")) {
|
||||||
e->stop();
|
e->stop();
|
||||||
}
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("Edit",&edit);
|
||||||
|
|
||||||
ImGui::Text("Follow");
|
ImGui::Text("Follow");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -2083,6 +2085,9 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
||||||
} else if (ev.key.keysym.mod&KMOD_ALT) {
|
} else if (ev.key.keysym.mod&KMOD_ALT) {
|
||||||
// nothing. prevents accidental OFF note.
|
// nothing. prevents accidental OFF note.
|
||||||
} else switch (ev.key.keysym.sym) {
|
} else switch (ev.key.keysym.sym) {
|
||||||
|
case SDLK_SPACE:
|
||||||
|
edit=!edit;
|
||||||
|
break;
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
moveCursor(0,-1);
|
moveCursor(0,-1);
|
||||||
break;
|
break;
|
||||||
|
@ -2111,66 +2116,80 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
||||||
doInsert();
|
doInsert();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (cursor.xFine==0) { // note
|
if (!ev.key.repeat) {
|
||||||
try {
|
if (cursor.xFine==0) { // note
|
||||||
int key=noteKeys.at(ev.key.keysym.sym);
|
try {
|
||||||
int num=12*curOctave+key;
|
int key=noteKeys.at(ev.key.keysym.sym);
|
||||||
DivPattern* pat=e->song.pat[cursor.xCoarse].getPattern(e->song.orders.ord[cursor.xCoarse][e->getOrder()],true);
|
int num=12*curOctave+key;
|
||||||
|
|
||||||
prepareUndo(GUI_ACTION_PATTERN_EDIT);
|
|
||||||
|
|
||||||
if (key==100) { // note off
|
if (edit) {
|
||||||
pat->data[cursor.y][0]=100;
|
DivPattern* pat=e->song.pat[cursor.xCoarse].getPattern(e->song.orders.ord[cursor.xCoarse][e->getOrder()],true);
|
||||||
pat->data[cursor.y][1]=0;
|
|
||||||
} else {
|
prepareUndo(GUI_ACTION_PATTERN_EDIT);
|
||||||
pat->data[cursor.y][0]=num%12;
|
|
||||||
pat->data[cursor.y][1]=num/12;
|
if (key==100) { // note off
|
||||||
if (pat->data[cursor.y][0]==0) {
|
pat->data[cursor.y][0]=100;
|
||||||
pat->data[cursor.y][0]=12;
|
pat->data[cursor.y][1]=0;
|
||||||
pat->data[cursor.y][1]--;
|
} else {
|
||||||
}
|
pat->data[cursor.y][0]=num%12;
|
||||||
pat->data[cursor.y][2]=curIns;
|
pat->data[cursor.y][1]=num/12;
|
||||||
}
|
if (pat->data[cursor.y][0]==0) {
|
||||||
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
pat->data[cursor.y][0]=12;
|
||||||
editAdvance();
|
pat->data[cursor.y][1]--;
|
||||||
curNibble=false;
|
}
|
||||||
} catch (std::out_of_range& e) {
|
pat->data[cursor.y][2]=curIns;
|
||||||
}
|
e->noteOn(cursor.xCoarse,curIns,num);
|
||||||
} else { // value
|
noteOffOnRelease=true;
|
||||||
try {
|
noteOffOnReleaseKey=ev.key.keysym.sym;
|
||||||
int num=valueKeys.at(ev.key.keysym.sym);
|
noteOffOnReleaseChan=cursor.xCoarse;
|
||||||
DivPattern* pat=e->song.pat[cursor.xCoarse].getPattern(e->song.orders.ord[cursor.xCoarse][e->getOrder()],true);
|
}
|
||||||
prepareUndo(GUI_ACTION_PATTERN_EDIT);
|
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
||||||
if (pat->data[cursor.y][cursor.xFine+1]==-1) pat->data[cursor.y][cursor.xFine+1]=0;
|
|
||||||
pat->data[cursor.y][cursor.xFine+1]=((pat->data[cursor.y][cursor.xFine+1]<<4)|num)&0xff;
|
|
||||||
if (cursor.xFine==1) { // instrument
|
|
||||||
if (pat->data[cursor.y][cursor.xFine+1]>=(int)e->song.ins.size()) {
|
|
||||||
pat->data[cursor.y][cursor.xFine+1]=(int)e->song.ins.size()-1;
|
|
||||||
}
|
|
||||||
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
|
||||||
if (e->song.ins.size()<16) {
|
|
||||||
curNibble=false;
|
|
||||||
editAdvance();
|
editAdvance();
|
||||||
|
curNibble=false;
|
||||||
} else {
|
} else {
|
||||||
|
e->noteOn(cursor.xCoarse,curIns,num);
|
||||||
|
noteOffOnRelease=true;
|
||||||
|
noteOffOnReleaseKey=ev.key.keysym.sym;
|
||||||
|
noteOffOnReleaseChan=cursor.xCoarse;
|
||||||
|
}
|
||||||
|
} catch (std::out_of_range& e) {
|
||||||
|
}
|
||||||
|
} else if (edit) { // value
|
||||||
|
try {
|
||||||
|
int num=valueKeys.at(ev.key.keysym.sym);
|
||||||
|
DivPattern* pat=e->song.pat[cursor.xCoarse].getPattern(e->song.orders.ord[cursor.xCoarse][e->getOrder()],true);
|
||||||
|
prepareUndo(GUI_ACTION_PATTERN_EDIT);
|
||||||
|
if (pat->data[cursor.y][cursor.xFine+1]==-1) pat->data[cursor.y][cursor.xFine+1]=0;
|
||||||
|
pat->data[cursor.y][cursor.xFine+1]=((pat->data[cursor.y][cursor.xFine+1]<<4)|num)&0xff;
|
||||||
|
if (cursor.xFine==1) { // instrument
|
||||||
|
if (pat->data[cursor.y][cursor.xFine+1]>=(int)e->song.ins.size()) {
|
||||||
|
pat->data[cursor.y][cursor.xFine+1]=(int)e->song.ins.size()-1;
|
||||||
|
}
|
||||||
|
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
||||||
|
if (e->song.ins.size()<16) {
|
||||||
|
curNibble=false;
|
||||||
|
editAdvance();
|
||||||
|
} else {
|
||||||
|
curNibble=!curNibble;
|
||||||
|
if (!curNibble) editAdvance();
|
||||||
|
}
|
||||||
|
} else if (cursor.xFine==2) { // volume
|
||||||
|
pat->data[cursor.y][cursor.xFine+1]&=e->getMaxVolumeChan(cursor.xCoarse);
|
||||||
|
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
||||||
|
if (e->getMaxVolumeChan(cursor.xCoarse)<16) {
|
||||||
|
curNibble=false;
|
||||||
|
editAdvance();
|
||||||
|
} else {
|
||||||
|
curNibble=!curNibble;
|
||||||
|
if (!curNibble) editAdvance();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
||||||
curNibble=!curNibble;
|
curNibble=!curNibble;
|
||||||
if (!curNibble) editAdvance();
|
if (!curNibble) editAdvance();
|
||||||
}
|
}
|
||||||
} else if (cursor.xFine==2) { // volume
|
} catch (std::out_of_range& e) {
|
||||||
pat->data[cursor.y][cursor.xFine+1]&=e->getMaxVolumeChan(cursor.xCoarse);
|
|
||||||
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
|
||||||
if (e->getMaxVolumeChan(cursor.xCoarse)<16) {
|
|
||||||
curNibble=false;
|
|
||||||
editAdvance();
|
|
||||||
} else {
|
|
||||||
curNibble=!curNibble;
|
|
||||||
if (!curNibble) editAdvance();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
makeUndo(GUI_ACTION_PATTERN_EDIT);
|
|
||||||
curNibble=!curNibble;
|
|
||||||
if (!curNibble) editAdvance();
|
|
||||||
}
|
}
|
||||||
} catch (std::out_of_range& e) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2183,7 +2202,12 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FurnaceGUI::keyUp(SDL_Event& ev) {
|
void FurnaceGUI::keyUp(SDL_Event& ev) {
|
||||||
|
if (noteOffOnRelease) {
|
||||||
|
if (ev.key.keysym.sym==noteOffOnReleaseKey) {
|
||||||
|
noteOffOnRelease=false;
|
||||||
|
e->noteOff(noteOffOnReleaseChan);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||||
|
@ -2739,6 +2763,7 @@ FurnaceGUI::FurnaceGUI():
|
||||||
e(NULL),
|
e(NULL),
|
||||||
quit(false),
|
quit(false),
|
||||||
willCommit(false),
|
willCommit(false),
|
||||||
|
edit(false),
|
||||||
curFileDialog(GUI_FILE_OPEN),
|
curFileDialog(GUI_FILE_OPEN),
|
||||||
scrW(1280),
|
scrW(1280),
|
||||||
scrH(800),
|
scrH(800),
|
||||||
|
@ -2776,6 +2801,9 @@ FurnaceGUI::FurnaceGUI():
|
||||||
followPattern(true),
|
followPattern(true),
|
||||||
changeAllOrders(false),
|
changeAllOrders(false),
|
||||||
curWindow(GUI_WINDOW_NOTHING),
|
curWindow(GUI_WINDOW_NOTHING),
|
||||||
|
noteOffOnRelease(false),
|
||||||
|
noteOffOnReleaseKey(0),
|
||||||
|
noteOffOnReleaseChan(0),
|
||||||
arpMacroScroll(0),
|
arpMacroScroll(0),
|
||||||
macroDragStart(0,0),
|
macroDragStart(0,0),
|
||||||
macroDragAreaSize(0,0),
|
macroDragAreaSize(0,0),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "../engine/engine.h"
|
#include "../engine/engine.h"
|
||||||
|
#include "SDL_keycode.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imgui_impl_sdl.h"
|
#include "imgui_impl_sdl.h"
|
||||||
#include "imgui_impl_sdlrenderer.h"
|
#include "imgui_impl_sdlrenderer.h"
|
||||||
|
@ -130,7 +131,7 @@ class FurnaceGUI {
|
||||||
|
|
||||||
String workingDir, fileName, clipboard, errorString, lastError;
|
String workingDir, fileName, clipboard, errorString, lastError;
|
||||||
|
|
||||||
bool quit, willCommit;
|
bool quit, willCommit, edit;
|
||||||
|
|
||||||
FurnaceGUIFileDialogs curFileDialog;
|
FurnaceGUIFileDialogs curFileDialog;
|
||||||
|
|
||||||
|
@ -160,6 +161,10 @@ class FurnaceGUI {
|
||||||
bool selecting, curNibble, extraChannelButtons, followOrders, followPattern, changeAllOrders;
|
bool selecting, curNibble, extraChannelButtons, followOrders, followPattern, changeAllOrders;
|
||||||
FurnaceGUIWindows curWindow;
|
FurnaceGUIWindows curWindow;
|
||||||
|
|
||||||
|
bool noteOffOnRelease;
|
||||||
|
SDL_Keycode noteOffOnReleaseKey;
|
||||||
|
int noteOffOnReleaseChan;
|
||||||
|
|
||||||
std::map<SDL_Keycode,int> noteKeys;
|
std::map<SDL_Keycode,int> noteKeys;
|
||||||
std::map<SDL_Keycode,int> valueKeys;
|
std::map<SDL_Keycode,int> valueKeys;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue