Skip to content

Commit d8879a5

Browse files
committed
simple piano roll view
1 parent 47e041d commit d8879a5

File tree

11 files changed

+305
-33
lines changed

11 files changed

+305
-33
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#Set all your object files (the object files of all the .c files in your project, e.g. main.o my_sub_functions.o )
2-
OBJ = src/main.o src/serial.o src/slip.o src/command.o src/render.o src/ini.o src/config.o src/input.o src/gamecontrollers.o src/fx_cube.o src/usb.o src/audio.o src/usb_audio.o src/ringbuffer.o src/inprint2.o
2+
OBJ = src/main.o src/serial.o src/slip.o src/command.o src/render.o src/ini.o src/config.o src/input.o src/gamecontrollers.o src/fx_cube.o src/fx_piano.o src/usb.o src/audio.o src/usb_audio.o src/ringbuffer.o src/inprint2.o
33

44
#Set any dependant header files so that if they are edited they cause a complete re-compile (e.g. main.h some_subfunctions.h some_definitions_file.h ), or leave blank
5-
DEPS = src/serial.h src/slip.h src/command.h src/render.h src/ini.h src/config.h src/input.h src/gamecontrollers.h src/fx_cube.h src/audio.h src/ringbuffer.h src/inline_font.h
5+
DEPS = src/serial.h src/slip.h src/command.h src/render.h src/ini.h src/config.h src/input.h src/gamecontrollers.h src/fx_cube.h src/fx_piano.h src/audio.h src/ringbuffer.h src/inline_font.h
66

77
#Any special libraries you are using in your project (e.g. -lbcm2835 -lrt `pkg-config --libs gtk+-3.0` ), or leave blank
88
INCLUDES = $(shell pkg-config --libs sdl2 libserialport | sed 's/-mwindows//')

src/command.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,12 @@ int process_command(uint8_t *data, uint32_t size) {
152152
break;
153153
}
154154

155-
char *hwtype[4] = {"Headless", "Beta M8", "Production M8", "Production M8 Model:02"};
155+
const char *hw_type[4] = {"Headless", "Beta M8", "Production M8", "Production M8 Model:02"};
156156

157157
static int system_info_printed = 0;
158158

159159
if (system_info_printed == 0) {
160-
SDL_Log("** Hardware info ** Device type: %s, Firmware ver %d.%d.%d", hwtype[recv_buf[1]],
160+
SDL_Log("** Hardware info ** Device type: %s, Firmware ver %d.%d.%d", hw_type[recv_buf[1]],
161161
recv_buf[2], recv_buf[3], recv_buf[4]);
162162
system_info_printed = 1;
163163
}

src/config.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ config_params_s init_config() {
5252
c.key_jazz_inc_velocity = SDL_SCANCODE_KP_MINUS;
5353
c.key_jazz_dec_velocity = SDL_SCANCODE_KP_PLUS;
5454
c.key_toggle_audio = SDL_SCANCODE_F12;
55+
c.key_toggle_overlay_fx = SDL_SCANCODE_F11;
5556

5657
c.gamepad_up = SDL_CONTROLLER_BUTTON_DPAD_UP;
5758
c.gamepad_left = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
@@ -86,7 +87,7 @@ void write_config(const config_params_s *conf) {
8687

8788
SDL_Log("Writing config file to %s", config_path);
8889

89-
const unsigned int INI_LINE_COUNT = 50;
90+
const unsigned int INI_LINE_COUNT = 51;
9091
const unsigned int LINELEN = 50;
9192

9293
// Entries for the config file
@@ -132,6 +133,7 @@ void write_config(const config_params_s *conf) {
132133
snprintf(ini_values[initPointer++], LINELEN, "key_jazz_dec_velocity=%d\n",
133134
conf->key_jazz_dec_velocity);
134135
snprintf(ini_values[initPointer++], LINELEN, "key_toggle_audio=%d\n", conf->key_toggle_audio);
136+
snprintf(ini_values[initPointer++], LINELEN, "key_toggle_overlay_fx=%d\n", conf->key_toggle_overlay_fx);
135137
snprintf(ini_values[initPointer++], LINELEN, "[gamepad]\n");
136138
snprintf(ini_values[initPointer++], LINELEN, "gamepad_up=%d\n", conf->gamepad_up);
137139
snprintf(ini_values[initPointer++], LINELEN, "gamepad_left=%d\n", conf->gamepad_left);
@@ -281,6 +283,7 @@ void read_key_config(const ini_t *ini, config_params_s *conf) {
281283
const char *key_jazz_inc_velocity = ini_get(ini, "keyboard", "key_jazz_inc_velocity");
282284
const char *key_jazz_dec_velocity = ini_get(ini, "keyboard", "key_jazz_dec_velocity");
283285
const char *key_toggle_audio = ini_get(ini, "keyboard", "key_toggle_audio");
286+
const char *key_toggle_overlay_fx = ini_get(ini, "keyboard", "key_toggle_overlay_fx");
284287

285288
if (key_up)
286289
conf->key_up = SDL_atoi(key_up);
@@ -320,6 +323,8 @@ void read_key_config(const ini_t *ini, config_params_s *conf) {
320323
conf->key_jazz_dec_velocity = SDL_atoi(key_jazz_dec_velocity);
321324
if (key_toggle_audio)
322325
conf->key_jazz_dec_velocity = SDL_atoi(key_toggle_audio);
326+
if (key_toggle_overlay_fx)
327+
conf->key_jazz_dec_velocity = SDL_atoi(key_toggle_overlay_fx);
323328
}
324329

325330
void read_gamepad_config(const ini_t *ini, config_params_s *conf) {

src/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ typedef struct config_params_s {
3636
unsigned int key_jazz_inc_velocity;
3737
unsigned int key_jazz_dec_velocity;
3838
unsigned int key_toggle_audio;
39+
unsigned int key_toggle_overlay_fx;
3940

4041
int gamepad_up;
4142
int gamepad_left;

src/fx_piano.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//
2+
// Created by jonne on 9/8/24.
3+
//
4+
5+
#include "fx_piano.h"
6+
#include "render.h"
7+
#include "inline_font.h"
8+
#include <SDL2/SDL.h>
9+
10+
struct active_notes {
11+
uint8_t note;
12+
uint8_t sharp;
13+
uint8_t octave;
14+
};
15+
16+
static int width = 320;
17+
static int height = 240;
18+
static SDL_Texture *fx_texture;
19+
static uint32_t *framebuffer;
20+
struct active_notes active_notes[8] = {0};
21+
static int is_initialized = 0;
22+
23+
static const uint32_t bgcolor = 0xA0000000;
24+
25+
// Pastel Rainbow from https://colorkit.co/palettes/8-colors/
26+
uint32_t palette[8] = {0xEFFFADAD, 0xEFFFD6A5, 0xEFFDFFB6, 0xEFCAFFBF,
27+
0xEF9BF6FF, 0xEFA0C4FF, 0xEFBDB2FF, 0xEFFFC6FF};
28+
29+
static int get_active_note_from_channel(int ch) {
30+
if (ch >= 0 && ch < 8)
31+
return active_notes[ch].note + active_notes[ch].sharp + active_notes[ch].octave;
32+
else
33+
return 0;
34+
}
35+
36+
void fx_piano_init(SDL_Texture *output_texture) {
37+
fx_texture = output_texture;
38+
SDL_QueryTexture(fx_texture, NULL, NULL, &width, &height);
39+
framebuffer = SDL_malloc(sizeof(uint32_t) * width * height);
40+
SDL_memset4(framebuffer, bgcolor, width * height);
41+
is_initialized = 1;
42+
}
43+
44+
void fx_piano_update() {
45+
//Shift everything up by one row and clear bottom row
46+
for (int y = 1; y < height; y++) {
47+
for (int x = 0; x < width; x++) {
48+
int buffer_pos = x + (y * width);
49+
// Top rows have a fading alpha value
50+
if (y<60 && (framebuffer[buffer_pos] >> 24) > 0x04){
51+
framebuffer[buffer_pos-width] = framebuffer[buffer_pos]-((0x05 << 24));
52+
} else {
53+
framebuffer[buffer_pos-width] = framebuffer[buffer_pos];
54+
}
55+
}
56+
}
57+
58+
for (int x = 0; x < width; x++) {
59+
framebuffer[width*(height-1)+x] = bgcolor;
60+
framebuffer[x] = bgcolor;
61+
}
62+
63+
int notes[8];
64+
for (int i = 0; i < 8; i++) {
65+
notes[i] = get_active_note_from_channel(i);
66+
67+
int last_row = (height-1)*width;
68+
int spacing = width / 128;
69+
if (notes[i]>0) {
70+
int pos = last_row + (notes[i] * spacing);
71+
uint32_t color = (framebuffer[pos] + palette[i]) | (0xCF <<24);
72+
for (int bar_width = 0; bar_width < spacing; bar_width++) {
73+
framebuffer[pos++] = color;
74+
}
75+
framebuffer[pos] = color | (0x20 << 24);
76+
}
77+
}
78+
79+
SDL_UpdateTexture(fx_texture, NULL, framebuffer,
80+
width * sizeof(framebuffer[0]));
81+
};
82+
83+
void fx_piano_destroy() {
84+
if (is_initialized) {
85+
SDL_free(framebuffer);
86+
is_initialized = 0;
87+
}
88+
}
89+
90+
/* Converts the note characters displayed on M8 screen to hex values for use in
91+
* visualizers */
92+
int note_to_hex(int note_char) {
93+
switch (note_char) {
94+
case 45: // - = note off
95+
return 0x00;
96+
case 67: // C
97+
return 0x01;
98+
case 68: // D
99+
return 0x03;
100+
case 69: // E
101+
return 0x05;
102+
case 70: // F
103+
return 0x06;
104+
case 71: // G
105+
return 0x08;
106+
case 65: // A
107+
return 0x0A;
108+
case 66: // B
109+
return 0x0C;
110+
default:
111+
return 0x00;
112+
}
113+
}
114+
115+
// Updates the active notes information array with the current command's data
116+
void update_active_notes_data(struct draw_character_command *command, int font_mode) {
117+
118+
int line_spacing;
119+
int character_spacing;
120+
int playback_info_offset_x;
121+
122+
switch (font_mode) {
123+
case 1:
124+
case 4:
125+
// Note name sidebar not visible all the time on MK1 / MK2
126+
return;
127+
case 2:
128+
case 3:
129+
line_spacing = 14;
130+
character_spacing = 12;
131+
playback_info_offset_x = 432;
132+
break;
133+
default:
134+
line_spacing = 10;
135+
character_spacing = 8;
136+
playback_info_offset_x = 288;
137+
break;
138+
}
139+
140+
// Channels are 10 pixels apart, starting from y=70
141+
int channel_number = command->pos.y / line_spacing - 7;
142+
143+
144+
// Note playback information starts from X=288
145+
if (command->pos.x == playback_info_offset_x) {
146+
active_notes[channel_number].note = note_to_hex(command->c);
147+
}
148+
149+
// Sharp notes live at x = 296
150+
if (command->pos.x == playback_info_offset_x + character_spacing && !strcmp((char *)&command->c, "#"))
151+
active_notes[channel_number].sharp = 1;
152+
else
153+
active_notes[channel_number].sharp = 0;
154+
155+
// Note octave, x = 304
156+
if (command->pos.x == playback_info_offset_x + 2*character_spacing) {
157+
int8_t octave = command->c - 48;
158+
159+
// Octaves A-B
160+
if (octave == 17 || octave == 18)
161+
octave -= 7;
162+
163+
// If octave hasn't been applied to the note yet, do it
164+
if (octave > 0)
165+
active_notes[channel_number].octave = octave * 0x0C;
166+
else
167+
active_notes[channel_number].octave = 0;
168+
}
169+
}

src/fx_piano.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// Created by jonne on 9/8/24.
3+
//
4+
5+
#ifndef FX_PIANO_H
6+
#define FX_PIANO_H
7+
8+
#include "SDL_render.h"
9+
#include "command.h"
10+
11+
void fx_piano_init(SDL_Texture *output_texture);
12+
void fx_piano_update();
13+
void fx_piano_destroy();
14+
15+
void update_active_notes_data(struct draw_character_command *command, int font_mode);
16+
17+
#endif //FX_PIANO_H

src/input.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ static input_msg_s handle_normal_keys(const SDL_Event *event, const config_param
177177
key = (input_msg_s){special, msg_reset_display, 0, 0};
178178
} else if (event->key.keysym.scancode == conf->key_toggle_audio) {
179179
key = (input_msg_s){special, msg_toggle_audio, 0, 0};
180+
} else if (event->key.keysym.scancode == conf->key_toggle_overlay_fx) {
181+
key = (input_msg_s){special, msg_toggle_overlay_fx, 0, 0};
180182
} else {
181183
key.value = 0;
182184
}

src/input.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ typedef enum input_type_t { normal, keyjazz, special } input_type_t;
3636
typedef enum special_messages_t {
3737
msg_quit = 1,
3838
msg_reset_display = 2,
39-
msg_toggle_audio = 3
39+
msg_toggle_audio = 3,
40+
msg_toggle_overlay_fx = 4
4041
} special_messages_t;
4142

4243
typedef struct input_msg_s {

src/main.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
#include "audio.h"
1313
#include "command.h"
1414
#include "config.h"
15-
#include "input.h"
1615
#include "gamecontrollers.h"
16+
#include "input.h"
1717
#include "render.h"
1818
#include "serial.h"
1919
#include "slip.h"
@@ -220,6 +220,9 @@ int main(const int argc, char *argv[]) {
220220
case msg_toggle_audio:
221221
toggle_audio(conf.audio_buffer_size, conf.audio_device_name);
222222
break;
223+
case msg_toggle_overlay_fx:
224+
toggle_special_fx();
225+
break;
223226
default:
224227
break;
225228
}
@@ -284,9 +287,7 @@ int main(const int argc, char *argv[]) {
284287

285288
// exit, clean up
286289
SDL_Log("Shutting down\n");
287-
if (conf.audio_enabled == 1) {
288-
audio_destroy();
289-
}
290+
audio_destroy();
290291
gamecontrollers_close();
291292
close_renderer();
292293
close_serial_port();

0 commit comments

Comments
 (0)