scrolling and save/load
This commit is contained in:
32
.vscode/launch.json
vendored
Normal file
32
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/tracker/build/tracker",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/tracker",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9,9 +9,10 @@ OBJFILES := $(SRCFILES:%.c=$(BUILDDIR)/%.c.o)
|
||||
DEPFILES := $(SRCFILES:%.c=$(BUILDDIR)/%.c.d)
|
||||
|
||||
CC := gcc
|
||||
CFLAGS := -Wall -Wextra
|
||||
CFLAGS := -Wall -Wextra -g
|
||||
CPPFLAGS := -I src $(shell pkg-config --cflags sdl2)
|
||||
LDLIBS := $(shell pkg-config --libs sdl2)
|
||||
LDFLAGS := -g
|
||||
|
||||
.PHONY: $(TARGET) all clean
|
||||
all: $(TARGET)
|
||||
|
||||
BIN
tracker/disk.bin
Normal file
BIN
tracker/disk.bin
Normal file
Binary file not shown.
@@ -94,6 +94,18 @@ void serial_write(char c){
|
||||
write(STDOUT_FILENO, &c, 1);
|
||||
}
|
||||
|
||||
void disk_write(void * data, size_t len){
|
||||
FILE * f = fopen("disk.bin", "wb");
|
||||
fwrite(data, 1, len, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void disk_read(void * data, size_t len){
|
||||
FILE * f = fopen("disk.bin", "rb");
|
||||
fread(data, 1, len, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void audio_callback(void *userdata, Uint8 *stream, int len){
|
||||
AudioState *state = userdata;
|
||||
int16_t *output = (int16_t *)stream;
|
||||
|
||||
@@ -3,3 +3,5 @@
|
||||
|
||||
void psg_write(uint8_t value);
|
||||
void serial_write(char c);
|
||||
void disk_write(void * data, size_t len);
|
||||
void disk_read(void * data, size_t len);
|
||||
@@ -54,13 +54,11 @@ static void flush_psg(){
|
||||
static void process_row(){
|
||||
row_t * current = &pattern->rows[row];
|
||||
for(uint8_t chan=0; chan<3; chan++){
|
||||
if(current->channel[chan].note < 12 && current->channel[chan].note >= NR_NOTE_PERIODS+12){
|
||||
// Only turn off note if it isnt 0
|
||||
if(current->channel[chan].note != 0)
|
||||
psg_state.channel[chan].vol = 15;
|
||||
}else{
|
||||
if(current->channel[chan].note >= 12 && current->channel[chan].note < NR_NOTE_PERIODS+12){
|
||||
psg_state.channel[chan].tone = note_periods[current->channel[chan].note-12];
|
||||
psg_state.channel[chan].vol = 15-current->channel[chan].volume;
|
||||
psg_state.channel[chan].vol = 0;
|
||||
}else if(current->channel[chan].note == 0xff){
|
||||
psg_state.channel[chan].vol = 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,19 +101,10 @@ void player_main(){
|
||||
flush_psg();
|
||||
ui_init();
|
||||
|
||||
pattern_t p = {
|
||||
.speed = 12,
|
||||
.rows = {
|
||||
{.channel = {{60, 15}, {0, 0}, {0, 0}, {0, 0}}},
|
||||
{.channel = {{67, 15}, {0, 0}, {0, 0}, {0, 0}}},
|
||||
{.channel = {{69, 15}, {0, 0}, {0, 0}, {0, 0}}},
|
||||
{.channel = {{67, 15}, {0, 0}, {0, 0}, {0, 0}}},
|
||||
{.channel = {{60, 15}, {0, 0}, {0, 0}, {0, 0}}},
|
||||
}
|
||||
};
|
||||
pattern_t p = {};
|
||||
p.speed = 6;
|
||||
|
||||
pattern = &p;
|
||||
ui_set_pattern(&p);
|
||||
|
||||
for(;;){
|
||||
if(music_tick_interrupt_happened){
|
||||
@@ -126,7 +115,7 @@ void player_main(){
|
||||
input_interrupt_happened = 0;
|
||||
ui_input(input);
|
||||
}
|
||||
uint8_t action = do_ui();
|
||||
uint8_t action = do_ui(playing, pattern, row);
|
||||
if(action != ACTION_NONE){
|
||||
if(action == ACTION_PLAY_ONCE){
|
||||
tick = 0;
|
||||
@@ -156,3 +145,11 @@ void player_main(){
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void save(){
|
||||
disk_write(pattern, sizeof(pattern_t));
|
||||
}
|
||||
|
||||
void load(){
|
||||
disk_read(pattern, sizeof(pattern_t));
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define PSG_CLOCK 1000000
|
||||
#define PATTERN_ROWS 16
|
||||
#define PATTERN_ROWS 32
|
||||
|
||||
typedef struct{
|
||||
uint8_t note;
|
||||
uint8_t volume;
|
||||
} cell_t;
|
||||
|
||||
typedef struct{
|
||||
@@ -21,3 +20,5 @@ typedef struct{
|
||||
void player_main();
|
||||
void music_tick_interrupt();
|
||||
void input_interrupt(char input);
|
||||
void save();
|
||||
void load();
|
||||
119
tracker/src/ui.c
119
tracker/src/ui.c
@@ -11,6 +11,9 @@
|
||||
#define TRACK_ROWS 16
|
||||
#define CHANNELS 4
|
||||
|
||||
#define MODE_EDIT 0
|
||||
#define MODE_PLAYING 1
|
||||
|
||||
static uint8_t dirty = 1;
|
||||
static uint8_t clear = 1;
|
||||
|
||||
@@ -22,6 +25,9 @@ static uint8_t input_octave = 4;
|
||||
|
||||
static uint8_t do_action = ACTION_NONE;
|
||||
static pattern_t * pattern = NULL;
|
||||
static uint8_t start_row = 0;
|
||||
static uint8_t active_row = 0;
|
||||
static uint8_t mode = MODE_EDIT;
|
||||
|
||||
|
||||
static void serial_puts(char * s){
|
||||
@@ -173,7 +179,11 @@ static void draw_cell(uint8_t row, uint8_t channel){
|
||||
static void draw_row(uint8_t row){
|
||||
uint8_t channel;
|
||||
|
||||
if(row == active_row && mode == MODE_PLAYING){
|
||||
reverse_on();
|
||||
}
|
||||
print_hex_byte(row);
|
||||
reverse_off();
|
||||
serial_puts(" ");
|
||||
|
||||
for (channel = 0; channel < CHANNELS; channel++) {
|
||||
@@ -199,20 +209,36 @@ static void draw(void){
|
||||
cursor_hide();
|
||||
|
||||
serial_puts("Z80 TRACKER\r\n");
|
||||
serial_puts("O [");
|
||||
|
||||
serial_puts("O[");
|
||||
print_hex_digit(input_octave);
|
||||
serial_puts("]\r\n");
|
||||
serial_puts("] ");
|
||||
|
||||
if(mode == MODE_EDIT){
|
||||
serial_puts("E ");
|
||||
}else if(mode == MODE_PLAYING){
|
||||
serial_puts("P ");
|
||||
}else{
|
||||
serial_puts("x ");
|
||||
}
|
||||
|
||||
serial_puts("S[");
|
||||
print_hex_byte(pattern->speed);
|
||||
serial_puts("] ");
|
||||
|
||||
serial_puts("\r\n");
|
||||
|
||||
serial_puts(" CH1 CH2 CH3 NOISE\r\n");
|
||||
serial_puts(" ------- ------- ------- -------\r\n");
|
||||
|
||||
for (row = 0; row < TRACK_ROWS; row++) {
|
||||
for (row = start_row; row < TRACK_ROWS+start_row; row++) {
|
||||
draw_row(row);
|
||||
}
|
||||
|
||||
serial_puts("\r\n");
|
||||
serial_puts("Arrows: move A-K: notes X: clear Space: off\r\n");
|
||||
serial_puts("P: play O: stop Q: quit Numbers: oct\r\n");
|
||||
serial_puts("N: save M: load\r\n");
|
||||
|
||||
/*
|
||||
* Keep the real terminal cursor out of the tracker area.
|
||||
@@ -223,13 +249,19 @@ static void draw(void){
|
||||
static void move_up(void){
|
||||
if (cursor_row > 0)
|
||||
cursor_row--;
|
||||
while(cursor_row < start_row){
|
||||
start_row -= TRACK_ROWS;
|
||||
}
|
||||
|
||||
dirty = 1;
|
||||
}
|
||||
|
||||
static void move_down(void){
|
||||
if (cursor_row < TRACK_ROWS - 1)
|
||||
if (cursor_row < PATTERN_ROWS - 1)
|
||||
cursor_row++;
|
||||
while(cursor_row >= start_row+TRACK_ROWS){
|
||||
start_row += TRACK_ROWS;
|
||||
}
|
||||
|
||||
dirty = 1;
|
||||
}
|
||||
@@ -288,7 +320,6 @@ static void enter_note(uint8_t note){
|
||||
cell_t *cell = &pattern->rows[cursor_row].channel[cursor_channel];
|
||||
|
||||
cell->note = note;
|
||||
cell->volume = 15;
|
||||
|
||||
/*
|
||||
* Just give every entered note instrument 1 for now.
|
||||
@@ -299,8 +330,7 @@ static void enter_note(uint8_t note){
|
||||
/*
|
||||
* Tracker-style behavior: advance after entering a note.
|
||||
*/
|
||||
if (cursor_row < TRACK_ROWS - 1)
|
||||
cursor_row++;
|
||||
move_down();
|
||||
|
||||
dirty = 1;
|
||||
}
|
||||
@@ -375,6 +405,41 @@ void ui_input(char input){
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* , = dec speed
|
||||
*/
|
||||
if (input == ',') {
|
||||
pattern->speed--;
|
||||
dirty = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* . = inc speed
|
||||
*/
|
||||
if (input == '.') {
|
||||
pattern->speed++;
|
||||
dirty = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* N = save
|
||||
*/
|
||||
if (input == 'N' || input == 'n') {
|
||||
save();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* M = save
|
||||
*/
|
||||
if (input == 'M' || input == 'm') {
|
||||
load();
|
||||
dirty = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Piano keyboard.
|
||||
*/
|
||||
@@ -442,7 +507,37 @@ void ui_input(char input){
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t do_ui(){
|
||||
uint8_t do_ui(uint8_t _playing, pattern_t * _pattern, uint8_t _row){
|
||||
pattern = _pattern;
|
||||
|
||||
if(_playing){
|
||||
if(mode != MODE_PLAYING){
|
||||
dirty = 1;
|
||||
}
|
||||
mode = MODE_PLAYING;
|
||||
}else{
|
||||
if(mode != MODE_EDIT){
|
||||
dirty = 1;
|
||||
start_row = 0;
|
||||
}
|
||||
mode = MODE_EDIT;
|
||||
}
|
||||
|
||||
if(mode == MODE_PLAYING){
|
||||
while(_row>=start_row+TRACK_ROWS){
|
||||
start_row += TRACK_ROWS;
|
||||
dirty = 1;
|
||||
}
|
||||
while(_row<start_row){
|
||||
start_row -= TRACK_ROWS;
|
||||
dirty = 1;
|
||||
}
|
||||
if(_row != active_row){
|
||||
active_row = _row;
|
||||
dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(dirty){
|
||||
dirty = 0;
|
||||
draw();
|
||||
@@ -455,10 +550,6 @@ uint8_t do_ui(){
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
void ui_set_pattern(pattern_t * _pattern){
|
||||
pattern = _pattern;
|
||||
}
|
||||
|
||||
void ui_init(){
|
||||
uint8_t row;
|
||||
uint8_t channel;
|
||||
@@ -469,4 +560,8 @@ void ui_init(){
|
||||
cursor_row = 0;
|
||||
cursor_channel = 0;
|
||||
input_state = 0;
|
||||
|
||||
mode = MODE_EDIT;
|
||||
start_row = 0;
|
||||
active_row = 0;
|
||||
}
|
||||
@@ -8,6 +8,5 @@
|
||||
#define ACTION_QUIT 3
|
||||
|
||||
void ui_input(char input);
|
||||
uint8_t do_ui();
|
||||
uint8_t do_ui(uint8_t _playing, pattern_t * _pattern, uint8_t _row);
|
||||
void ui_init();
|
||||
void ui_set_pattern(pattern_t * _pattern);
|
||||
Reference in New Issue
Block a user