Merge branch '#174' into tic_0.46.0
This commit is contained in:
commit
7dba6b4edc
268
src/music.c
268
src/music.c
|
@ -376,36 +376,6 @@ static tic_track_pattern* getChannelPattern(Music* music)
|
||||||
return getPattern(music, channel);
|
return getPattern(music, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resetCol(Music* music)
|
|
||||||
{
|
|
||||||
|
|
||||||
tic_track_pattern* pattern = getChannelPattern(music);
|
|
||||||
s32 col = music->tracker.col % CHANNEL_COLS;
|
|
||||||
|
|
||||||
switch (col)
|
|
||||||
{
|
|
||||||
case ColumnNote:
|
|
||||||
case ColumnSemitone:
|
|
||||||
case ColumnOctave:
|
|
||||||
memset(&pattern->rows[music->tracker.row], 0, sizeof(pattern->rows[music->tracker.row]));
|
|
||||||
break;
|
|
||||||
case ColumnSfxHi:
|
|
||||||
case ColumnSfxLow:
|
|
||||||
pattern->rows[music->tracker.row].sfxhi = 0;
|
|
||||||
pattern->rows[music->tracker.row].sfxlow = 0;
|
|
||||||
break;
|
|
||||||
case ColumnVolume:
|
|
||||||
pattern->rows[music->tracker.row].volume = 0;
|
|
||||||
case ColumnEffect:
|
|
||||||
case ColumnParameter:
|
|
||||||
pattern->rows[music->tracker.row].effect = 0;
|
|
||||||
pattern->rows[music->tracker.row].param = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
history_add(music->history);
|
|
||||||
}
|
|
||||||
|
|
||||||
static s32 getNote(Music* music)
|
static s32 getNote(Music* music)
|
||||||
{
|
{
|
||||||
tic_track_pattern* pattern = getChannelPattern(music);
|
tic_track_pattern* pattern = getChannelPattern(music);
|
||||||
|
@ -537,39 +507,118 @@ static void stopTrack(Music* music)
|
||||||
music->tic->api.music(music->tic, -1, -1, -1, false);
|
music->tic->api.music(music->tic, -1, -1, -1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyToClipboard(Music* music)
|
static void resetSelection(Music* music)
|
||||||
{
|
{
|
||||||
tic_track_pattern* pattern = getChannelPattern(music);
|
music->tracker.select.start = (SDL_Point){-1, -1};
|
||||||
|
music->tracker.select.rect = (SDL_Rect){0, 0, 0, 0};
|
||||||
toClipboard(pattern, sizeof(tic_track_pattern), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resetPattern(Music* music)
|
static void deleteSelection(Music* music)
|
||||||
{
|
{
|
||||||
tic_track_pattern* pattern = getChannelPattern(music);
|
tic_track_pattern* pattern = getChannelPattern(music);
|
||||||
|
|
||||||
if(pattern)
|
if(pattern)
|
||||||
{
|
{
|
||||||
memset(pattern, 0, sizeof(tic_track_pattern));
|
SDL_Rect rect = music->tracker.select.rect;
|
||||||
|
|
||||||
|
if(rect.h <= 0)
|
||||||
|
{
|
||||||
|
rect.y = music->tracker.row;
|
||||||
|
rect.h = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum{RowSize = sizeof(tic_track_pattern) / MUSIC_PATTERN_ROWS};
|
||||||
|
SDL_memset(&pattern->rows[rect.y], 0, RowSize * rect.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u8 size;
|
||||||
|
} ClipboardHeader;
|
||||||
|
|
||||||
|
static void copyToClipboard(Music* music, bool cut)
|
||||||
|
{
|
||||||
|
tic_track_pattern* pattern = getChannelPattern(music);
|
||||||
|
|
||||||
|
if(pattern)
|
||||||
|
{
|
||||||
|
SDL_Rect rect = music->tracker.select.rect;
|
||||||
|
|
||||||
|
if(rect.h <= 0)
|
||||||
|
{
|
||||||
|
rect.y = music->tracker.row;
|
||||||
|
rect.h = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardHeader header = {rect.h};
|
||||||
|
|
||||||
|
enum{RowSize = sizeof(tic_track_pattern) / MUSIC_PATTERN_ROWS, HeaderSize = sizeof(ClipboardHeader)};
|
||||||
|
|
||||||
|
s32 size = rect.h * RowSize + HeaderSize;
|
||||||
|
u8* data = SDL_malloc(size);
|
||||||
|
|
||||||
|
if(data)
|
||||||
|
{
|
||||||
|
SDL_memcpy(data, &header, HeaderSize);
|
||||||
|
SDL_memcpy(data + HeaderSize, &pattern->rows[rect.y], RowSize * rect.h);
|
||||||
|
|
||||||
|
toClipboard(data, size, true);
|
||||||
|
|
||||||
|
SDL_free(data);
|
||||||
|
|
||||||
|
if(cut)
|
||||||
|
{
|
||||||
|
deleteSelection(music);
|
||||||
history_add(music->history);
|
history_add(music->history);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void cutToClipboard(Music* music)
|
resetSelection(music);
|
||||||
{
|
}
|
||||||
copyToClipboard(music);
|
}
|
||||||
resetPattern(music);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyFromClipboard(Music* music)
|
static void copyFromClipboard(Music* music)
|
||||||
{
|
{
|
||||||
tic_track_pattern* pattern = getChannelPattern(music);
|
tic_track_pattern* pattern = getChannelPattern(music);
|
||||||
|
|
||||||
if(fromClipboard(pattern, sizeof(tic_track_pattern), true))
|
if(pattern && SDL_HasClipboardText())
|
||||||
|
{
|
||||||
|
char* clipboard = SDL_GetClipboardText();
|
||||||
|
|
||||||
|
if(clipboard)
|
||||||
|
{
|
||||||
|
s32 size = strlen(clipboard)/2;
|
||||||
|
|
||||||
|
enum{RowSize = sizeof(tic_track_pattern) / MUSIC_PATTERN_ROWS, HeaderSize = sizeof(ClipboardHeader)};
|
||||||
|
|
||||||
|
if(size > HeaderSize)
|
||||||
|
{
|
||||||
|
u8* data = SDL_malloc(size);
|
||||||
|
|
||||||
|
str2buf(clipboard, data, true);
|
||||||
|
|
||||||
|
ClipboardHeader header = {0};
|
||||||
|
|
||||||
|
SDL_memcpy(&header, data, HeaderSize);
|
||||||
|
|
||||||
|
if(header.size * RowSize == size - HeaderSize)
|
||||||
|
{
|
||||||
|
if(header.size + music->tracker.row > MUSIC_PATTERN_ROWS)
|
||||||
|
header.size = MUSIC_PATTERN_ROWS - music->tracker.row;
|
||||||
|
|
||||||
|
SDL_memcpy(&pattern->rows[music->tracker.row], data + HeaderSize, header.size * RowSize);
|
||||||
history_add(music->history);
|
history_add(music->history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(clipboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void setChannelPatternValue(Music* music, s32 patternId, s32 channel)
|
static void setChannelPatternValue(Music* music, s32 patternId, s32 channel)
|
||||||
{
|
{
|
||||||
tic_track* track = getTrack(music);
|
tic_track* track = getTrack(music);
|
||||||
|
@ -629,11 +678,53 @@ static void patternColRight(Music* music)
|
||||||
else nextPattern(music);
|
else nextPattern(music);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void checkSelection(Music* music)
|
||||||
|
{
|
||||||
|
if(music->tracker.select.start.x < 0 || music->tracker.select.start.y < 0)
|
||||||
|
{
|
||||||
|
music->tracker.select.start.x = music->tracker.col;
|
||||||
|
music->tracker.select.start.y = music->tracker.row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateSelection(Music* music)
|
||||||
|
{
|
||||||
|
s32 rl = SDL_min(music->tracker.col, music->tracker.select.start.x);
|
||||||
|
s32 rt = SDL_min(music->tracker.row, music->tracker.select.start.y);
|
||||||
|
s32 rr = SDL_max(music->tracker.col, music->tracker.select.start.x);
|
||||||
|
s32 rb = SDL_max(music->tracker.row, music->tracker.select.start.y);
|
||||||
|
|
||||||
|
SDL_Rect* rect = &music->tracker.select.rect;
|
||||||
|
*rect = (SDL_Rect){rl, rt, rr - rl + 1, rb - rt + 1};
|
||||||
|
|
||||||
|
if(rect->x % CHANNEL_COLS + rect->w > CHANNEL_COLS)
|
||||||
|
resetSelection(music);
|
||||||
|
}
|
||||||
|
|
||||||
static void processTrackerKeydown(Music* music, SDL_Keysym* keysum)
|
static void processTrackerKeydown(Music* music, SDL_Keysym* keysum)
|
||||||
{
|
{
|
||||||
SDL_Keycode keycode = keysum->sym;
|
SDL_Keycode keycode = keysum->sym;
|
||||||
SDL_Scancode scancode = keysum->scancode;
|
SDL_Scancode scancode = keysum->scancode;
|
||||||
|
|
||||||
|
bool shift = SDL_GetModState() & KMOD_SHIFT;
|
||||||
|
|
||||||
|
if(shift)
|
||||||
|
{
|
||||||
|
switch (keycode)
|
||||||
|
{
|
||||||
|
case SDLK_UP:
|
||||||
|
case SDLK_DOWN:
|
||||||
|
case SDLK_LEFT:
|
||||||
|
case SDLK_RIGHT:
|
||||||
|
case SDLK_HOME:
|
||||||
|
case SDLK_END:
|
||||||
|
case SDLK_PAGEUP:
|
||||||
|
case SDLK_PAGEDOWN:
|
||||||
|
case SDLK_TAB:
|
||||||
|
checkSelection(music);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (keycode)
|
switch (keycode)
|
||||||
{
|
{
|
||||||
case SDLK_UP: upRow(music); break;
|
case SDLK_UP: upRow(music); break;
|
||||||
|
@ -646,7 +737,8 @@ static void processTrackerKeydown(Music* music, SDL_Keysym* keysum)
|
||||||
case SDLK_PAGEDOWN: pageDown(music); break;
|
case SDLK_PAGEDOWN: pageDown(music); break;
|
||||||
case SDLK_TAB: doTab(music); break;
|
case SDLK_TAB: doTab(music); break;
|
||||||
case SDLK_DELETE:
|
case SDLK_DELETE:
|
||||||
resetCol(music);
|
deleteSelection(music);
|
||||||
|
history_add(music->history);
|
||||||
downRow(music);
|
downRow(music);
|
||||||
break;
|
break;
|
||||||
case SDLK_SPACE: playNote(music); break;
|
case SDLK_SPACE: playNote(music); break;
|
||||||
|
@ -655,12 +747,30 @@ static void processTrackerKeydown(Music* music, SDL_Keysym* keysum)
|
||||||
{
|
{
|
||||||
const tic_music_pos* pos = getMusicPos(music);
|
const tic_music_pos* pos = getMusicPos(music);
|
||||||
pos->track < 0
|
pos->track < 0
|
||||||
? (SDL_GetModState() & KMOD_SHIFT ? playFrameRow(music) : playFrame(music))
|
? (shift ? playFrameRow(music) : playFrame(music))
|
||||||
: stopTrack(music);
|
: stopTrack(music);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(shift)
|
||||||
|
{
|
||||||
|
switch (keycode)
|
||||||
|
{
|
||||||
|
case SDLK_UP:
|
||||||
|
case SDLK_DOWN:
|
||||||
|
case SDLK_LEFT:
|
||||||
|
case SDLK_RIGHT:
|
||||||
|
case SDLK_HOME:
|
||||||
|
case SDLK_END:
|
||||||
|
case SDLK_PAGEUP:
|
||||||
|
case SDLK_PAGEDOWN:
|
||||||
|
case SDLK_TAB:
|
||||||
|
updateSelection(music);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else resetSelection(music);
|
||||||
|
|
||||||
static const SDL_Scancode Piano[] =
|
static const SDL_Scancode Piano[] =
|
||||||
{
|
{
|
||||||
SDL_SCANCODE_Z,
|
SDL_SCANCODE_Z,
|
||||||
|
@ -825,18 +935,30 @@ static void processPatternKeydown(Music* music, SDL_Keysym* keysum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void selectAll(Music* music)
|
||||||
|
{
|
||||||
|
resetSelection(music);
|
||||||
|
|
||||||
|
s32 col = music->tracker.col - music->tracker.col % CHANNEL_COLS;
|
||||||
|
|
||||||
|
music->tracker.select.start = (SDL_Point){col, 0};
|
||||||
|
music->tracker.col = col + CHANNEL_COLS-1;
|
||||||
|
music->tracker.row = MUSIC_PATTERN_ROWS-1;
|
||||||
|
|
||||||
|
updateSelection(music);
|
||||||
|
}
|
||||||
|
|
||||||
static void processKeydown(Music* music, SDL_Keysym* keysum)
|
static void processKeydown(Music* music, SDL_Keysym* keysum)
|
||||||
{
|
{
|
||||||
SDL_Keycode keycode = keysum->sym;
|
SDL_Keycode keycode = keysum->sym;
|
||||||
|
|
||||||
switch(getClipboardEvent(keycode))
|
switch(getClipboardEvent(keycode))
|
||||||
{
|
{
|
||||||
case TIC_CLIPBOARD_CUT: cutToClipboard(music); break;
|
case TIC_CLIPBOARD_CUT: copyToClipboard(music, true); break;
|
||||||
case TIC_CLIPBOARD_COPY: copyToClipboard(music); break;
|
case TIC_CLIPBOARD_COPY: copyToClipboard(music, false); break;
|
||||||
case TIC_CLIPBOARD_PASTE: copyFromClipboard(music); break;
|
case TIC_CLIPBOARD_PASTE: copyFromClipboard(music); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
@ -847,6 +969,7 @@ static void processKeydown(Music* music, SDL_Keysym* keysum)
|
||||||
{
|
{
|
||||||
switch (keycode)
|
switch (keycode)
|
||||||
{
|
{
|
||||||
|
case SDLK_a: selectAll(music); break;
|
||||||
case SDLK_z: undo(music); break;
|
case SDLK_z: undo(music); break;
|
||||||
case SDLK_y: redo(music); break;
|
case SDLK_y: redo(music); break;
|
||||||
case SDLK_UP: upFrame(music); break;
|
case SDLK_UP: upFrame(music); break;
|
||||||
|
@ -1029,6 +1152,8 @@ static void setChannelPattern(Music* music, s32 delta, s32 channel)
|
||||||
|
|
||||||
static void drawTrackerChannel(Music* music, s32 x, s32 y, s32 channel)
|
static void drawTrackerChannel(Music* music, s32 x, s32 y, s32 channel)
|
||||||
{
|
{
|
||||||
|
tic_mem* tic = music->tic;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Border = 1,
|
Border = 1,
|
||||||
|
@ -1047,8 +1172,29 @@ static void drawTrackerChannel(Music* music, s32 x, s32 y, s32 channel)
|
||||||
s32 mx = getMouseX() - rect.x - Border;
|
s32 mx = getMouseX() - rect.x - Border;
|
||||||
s32 my = getMouseY() - rect.y - Border;
|
s32 my = getMouseY() - rect.y - Border;
|
||||||
|
|
||||||
music->tracker.col = channel * CHANNEL_COLS + mx / TIC_FONT_WIDTH;
|
s32 col = music->tracker.col = channel * CHANNEL_COLS + mx / TIC_FONT_WIDTH;
|
||||||
music->tracker.row = my / TIC_FONT_HEIGHT + music->tracker.scroll;
|
s32 row = music->tracker.row = my / TIC_FONT_HEIGHT + music->tracker.scroll;
|
||||||
|
|
||||||
|
if(music->tracker.select.drag)
|
||||||
|
{
|
||||||
|
updateSelection(music);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resetSelection(music);
|
||||||
|
music->tracker.select.start = (SDL_Point){col, row};
|
||||||
|
|
||||||
|
music->tracker.select.drag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(music->tracker.select.drag)
|
||||||
|
{
|
||||||
|
SDL_Rect rect = {0, 0, TIC80_WIDTH, TIC80_HEIGHT};
|
||||||
|
if(!checkMouseDown(&rect, SDL_BUTTON_LEFT))
|
||||||
|
{
|
||||||
|
music->tracker.select.drag = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,6 +1202,7 @@ static void drawTrackerChannel(Music* music, s32 x, s32 y, s32 channel)
|
||||||
|
|
||||||
s32 start = music->tracker.scroll;
|
s32 start = music->tracker.scroll;
|
||||||
s32 end = start + Rows;
|
s32 end = start + Rows;
|
||||||
|
bool selectedChannel = music->tracker.select.rect.x / CHANNEL_COLS == channel;
|
||||||
|
|
||||||
tic_track_pattern* pattern = getPattern(music, channel);
|
tic_track_pattern* pattern = getPattern(music, channel);
|
||||||
|
|
||||||
|
@ -1068,6 +1215,17 @@ static void drawTrackerChannel(Music* music, s32 x, s32 y, s32 channel)
|
||||||
music->tic->api.rect(music->tic, x - 1, rowy - 1, Width, TIC_FONT_HEIGHT + 1, systemColor(tic_color_dark_red));
|
music->tic->api.rect(music->tic, x - 1, rowy - 1, Width, TIC_FONT_HEIGHT + 1, systemColor(tic_color_dark_red));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw selection
|
||||||
|
if (selectedChannel)
|
||||||
|
{
|
||||||
|
SDL_Rect rect = music->tracker.select.rect;
|
||||||
|
if (rect.h > 1 && i >= rect.y && i < rect.y + rect.h)
|
||||||
|
{
|
||||||
|
s32 sx = x - 1;
|
||||||
|
tic->api.rect(tic, sx, rowy - 1, CHANNEL_COLS * TIC_FONT_WIDTH + 1, TIC_FONT_HEIGHT + 1, systemColor(tic_color_yellow));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (checkPlayRow(music, i))
|
if (checkPlayRow(music, i))
|
||||||
{
|
{
|
||||||
music->tic->api.rect(music->tic, x - 1, rowy - 1, Width, TIC_FONT_HEIGHT + 1, systemColor(tic_color_white));
|
music->tic->api.rect(music->tic, x - 1, rowy - 1, Width, TIC_FONT_HEIGHT + 1, systemColor(tic_color_white));
|
||||||
|
@ -1388,8 +1546,8 @@ static void onStudioEvent(Music* music, StudioEvent event)
|
||||||
{
|
{
|
||||||
switch (event)
|
switch (event)
|
||||||
{
|
{
|
||||||
case TIC_TOOLBAR_CUT: cutToClipboard(music); break;
|
case TIC_TOOLBAR_CUT: copyToClipboard(music, true); break;
|
||||||
case TIC_TOOLBAR_COPY: copyToClipboard(music); break;
|
case TIC_TOOLBAR_COPY: copyToClipboard(music, false); break;
|
||||||
case TIC_TOOLBAR_PASTE: copyFromClipboard(music); break;
|
case TIC_TOOLBAR_PASTE: copyFromClipboard(music); break;
|
||||||
case TIC_TOOLBAR_UNDO: undo(music); break;
|
case TIC_TOOLBAR_UNDO: undo(music); break;
|
||||||
case TIC_TOOLBAR_REDO: redo(music); break;
|
case TIC_TOOLBAR_REDO: redo(music); break;
|
||||||
|
@ -1423,10 +1581,18 @@ void initMusic(Music* music, tic_mem* tic)
|
||||||
},
|
},
|
||||||
|
|
||||||
.patterns = {true, true, true, true},
|
.patterns = {true, true, true, true},
|
||||||
|
.select =
|
||||||
|
{
|
||||||
|
.start = {0, 0},
|
||||||
|
.rect = {0, 0, 0, 0},
|
||||||
|
.drag = false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
.tab = MUSIC_TRACKER_TAB,
|
.tab = MUSIC_TRACKER_TAB,
|
||||||
.history = history_create(&tic->cart.sound.music, sizeof tic->cart.sound.music),
|
.history = history_create(&tic->cart.sound.music, sizeof tic->cart.sound.music),
|
||||||
.event = onStudioEvent,
|
.event = onStudioEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
resetSelection(music);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,13 @@ struct Music
|
||||||
s32 volume;
|
s32 volume;
|
||||||
} last;
|
} last;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SDL_Point start;
|
||||||
|
SDL_Rect rect;
|
||||||
|
bool drag;
|
||||||
|
} select;
|
||||||
|
|
||||||
bool patterns[TIC_SOUND_CHANNELS];
|
bool patterns[TIC_SOUND_CHANNELS];
|
||||||
|
|
||||||
} tracker;
|
} tracker;
|
||||||
|
|
Loading…
Reference in New Issue