fix for parent folders with spaces (#403)
[jackhill/qmk/firmware.git] / quantum / quantum.c
CommitLineData
1a8c0dd2 1#include "quantum.h"
0428214b 2#include "timer.h"
1a8c0dd2
EZ
3
4__attribute__ ((weak))
5void matrix_init_kb(void) {}
6
7__attribute__ ((weak))
8void matrix_scan_kb(void) {}
9
10__attribute__ ((weak))
11bool process_action_kb(keyrecord_t *record) {
12 return true;
13}
14
17977a7e
JH
15__attribute__ ((weak))
16bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
17 return process_record_user(keycode, record);
18}
19
20__attribute__ ((weak))
21bool process_record_user(uint16_t keycode, keyrecord_t *record) {
22 return true;
23}
24
1a8c0dd2
EZ
25__attribute__ ((weak))
26void leader_start(void) {}
27
28__attribute__ ((weak))
29void leader_end(void) {}
30
0428214b
JH
31uint8_t starting_note = 0x0C;
32int offset = 7;
0275d444 33
12370259 34
1a8c0dd2 35#ifdef AUDIO_ENABLE
1a8c0dd2 36 bool music_activated = false;
b732b79b 37
287eb7ad
JH
38// music sequencer
39static bool music_sequence_recording = false;
40static bool music_sequence_playing = false;
41static float music_sequence[16] = {0};
42static uint8_t music_sequence_count = 0;
43static uint8_t music_sequence_position = 0;
b732b79b 44
287eb7ad
JH
45static uint16_t music_sequence_timer = 0;
46static uint16_t music_sequence_interval = 100;
b732b79b 47
1a8c0dd2
EZ
48#endif
49
fde477a9
JH
50#ifdef MIDI_ENABLE
51 bool midi_activated = false;
52#endif
53
1a8c0dd2
EZ
54// Leader key stuff
55bool leading = false;
56uint16_t leader_time = 0;
57
58uint16_t leader_sequence[3] = {0, 0, 0};
59uint8_t leader_sequence_size = 0;
60
61// Chording stuff
62#define CHORDING_MAX 4
63bool chording = false;
64
65uint8_t chord_keys[CHORDING_MAX] = {0};
66uint8_t chord_key_count = 0;
67uint8_t chord_key_down = 0;
68
b732b79b
JH
69#ifdef UNICODE_ENABLE
70 static uint8_t input_mode;
71#endif
72
8bc69afc 73static bool shift_interrupted[2] = {0, 0};
12370259 74
1a8c0dd2
EZ
75bool keys_chord(uint8_t keys[]) {
76 uint8_t keys_size = sizeof(keys)/sizeof(keys[0]);
77 bool pass = true;
78 uint8_t in = 0;
79 for (uint8_t i = 0; i < chord_key_count; i++) {
80 bool found = false;
81 for (uint8_t j = 0; j < keys_size; j++) {
82 if (chord_keys[i] == (keys[j] & 0xFF)) {
83 in++; // detects key in chord
84 found = true;
85 break;
86 }
87 }
88 if (found)
89 continue;
90 if (chord_keys[i] != 0) {
91 pass = false; // makes sure rest are blank
92 }
93 }
94 return (pass && (in == keys_size));
95}
96
b732b79b
JH
97#ifdef UNICODE_ENABLE
98
99uint16_t hex_to_keycode(uint8_t hex)
100{
101 if (hex == 0x0) {
102 return KC_0;
103 } else if (hex < 0xA) {
104 return KC_1 + (hex - 0x1);
105 } else {
106 return KC_A + (hex - 0xA);
107 }
108}
109
110void set_unicode_mode(uint8_t os_target)
111{
112 input_mode = os_target;
113}
15719f35 114
b732b79b 115#endif
15719f35 116
bf5c2cce 117bool process_record_quantum(keyrecord_t *record) {
1a8c0dd2
EZ
118
119 /* This gets the keycode from the key pressed */
120 keypos_t key = record->event.key;
121 uint16_t keycode;
122
123 #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
124 uint8_t layer;
125
126 if (record->event.pressed) {
127 layer = layer_switch_get_layer(key);
128 update_source_layers_cache(key, layer);
129 } else {
130 layer = read_source_layers_cache(key);
131 }
132 keycode = keymap_key_to_keycode(layer, key);
133 #else
134 keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
135 #endif
136
17977a7e
JH
137 if (!process_record_kb(keycode, record))
138 return false;
139
bf5c2cce
JH
140 // This is how you use actions here
141 // if (keycode == KC_LEAD) {
142 // action_t action;
143 // action.code = ACTION_DEFAULT_LAYER_SET(0);
144 // process_action(record, action);
145 // return false;
146 // }
147
fde477a9
JH
148 #ifdef MIDI_ENABLE
149 if (keycode == MI_ON && record->event.pressed) {
150 midi_activated = true;
287eb7ad 151 music_scale_user();
fde477a9
JH
152 return false;
153 }
154
155 if (keycode == MI_OFF && record->event.pressed) {
156 midi_activated = false;
157 midi_send_cc(&midi_device, 0, 0x7B, 0);
158 return false;
159 }
160
161 if (midi_activated) {
162 if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) {
163 if (record->event.pressed) {
164 starting_note++; // Change key
165 midi_send_cc(&midi_device, 0, 0x7B, 0);
166 // midi_send_cc(&midi_device, 1, 0x7B, 0);
167 // midi_send_cc(&midi_device, 2, 0x7B, 0);
168 // midi_send_cc(&midi_device, 3, 0x7B, 0);
169 // midi_send_cc(&midi_device, 4, 0x7B, 0);
170 }
171 return false;
172 }
173 if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) {
174 if (record->event.pressed) {
175 starting_note--; // Change key
176 midi_send_cc(&midi_device, 0, 0x7B, 0);
177 // midi_send_cc(&midi_device, 1, 0x7B, 0);
178 // midi_send_cc(&midi_device, 2, 0x7B, 0);
179 // midi_send_cc(&midi_device, 3, 0x7B, 0);
180 // midi_send_cc(&midi_device, 4, 0x7B, 0);
181 }
182 return false;
183 }
184 if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
185 offset++; // Change scale
186 midi_send_cc(&midi_device, 0, 0x7B, 0);
187 // midi_send_cc(&midi_device, 1, 0x7B, 0);
188 // midi_send_cc(&midi_device, 2, 0x7B, 0);
189 // midi_send_cc(&midi_device, 3, 0x7B, 0);
190 // midi_send_cc(&midi_device, 4, 0x7B, 0);
191 return false;
192 }
193 if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
194 offset--; // Change scale
195 midi_send_cc(&midi_device, 0, 0x7B, 0);
196 // midi_send_cc(&midi_device, 1, 0x7B, 0);
197 // midi_send_cc(&midi_device, 2, 0x7B, 0);
198 // midi_send_cc(&midi_device, 3, 0x7B, 0);
199 // midi_send_cc(&midi_device, 4, 0x7B, 0);
200 return false;
201 }
202 // basic
203 // uint8_t note = (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row);
204 // advanced
205 // uint8_t note = (starting_note + record->event.key.col + offset)+12*(MATRIX_ROWS - record->event.key.row);
206 // guitar
207 uint8_t note = (starting_note + record->event.key.col + offset)+5*(MATRIX_ROWS - record->event.key.row);
208 // violin
209 // uint8_t note = (starting_note + record->event.key.col + offset)+7*(MATRIX_ROWS - record->event.key.row);
210
211 if (record->event.pressed) {
212 // midi_send_noteon(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
213 midi_send_noteon(&midi_device, 0, note, 127);
214 } else {
215 // midi_send_noteoff(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
216 midi_send_noteoff(&midi_device, 0, note, 127);
217 }
218
219 if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
220 return false;
221 }
222 #endif
223
1a8c0dd2 224 #ifdef AUDIO_ENABLE
15719f35
JH
225 if (keycode == AU_ON && record->event.pressed) {
226 audio_on();
15719f35
JH
227 return false;
228 }
229
230 if (keycode == AU_OFF && record->event.pressed) {
231 audio_off();
232 return false;
233 }
234
0428214b
JH
235 if (keycode == AU_TOG && record->event.pressed) {
236 if (is_audio_on())
237 {
238 audio_off();
239 }
240 else
241 {
242 audio_on();
243 }
244 return false;
245 }
246
15719f35 247 if (keycode == MU_ON && record->event.pressed) {
287eb7ad
JH
248 music_on();
249 return false;
15719f35
JH
250 }
251
252 if (keycode == MU_OFF && record->event.pressed) {
287eb7ad
JH
253 music_off();
254 return false;
15719f35
JH
255 }
256
0428214b
JH
257 if (keycode == MU_TOG && record->event.pressed) {
258 if (music_activated)
259 {
287eb7ad 260 music_off();
0428214b
JH
261 }
262 else
263 {
287eb7ad 264 music_on();
0428214b
JH
265 }
266 return false;
267 }
268
15719f35 269 if (keycode == MUV_IN && record->event.pressed) {
287eb7ad
JH
270 voice_iterate();
271 music_scale_user();
272 return false;
15719f35
JH
273 }
274
275 if (keycode == MUV_DE && record->event.pressed) {
287eb7ad
JH
276 voice_deiterate();
277 music_scale_user();
278 return false;
15719f35
JH
279 }
280
0428214b 281 if (music_activated) {
15719f35
JH
282
283 if (keycode == KC_LCTL && record->event.pressed) { // Start recording
284 stop_all_notes();
285 music_sequence_recording = true;
286 music_sequence_playing = false;
287 music_sequence_count = 0;
288 return false;
289 }
794aed37 290
15719f35
JH
291 if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing
292 stop_all_notes();
293 music_sequence_recording = false;
294 music_sequence_playing = false;
295 return false;
296 }
794aed37 297
15719f35
JH
298 if (keycode == KC_LGUI && record->event.pressed) { // Start playing
299 stop_all_notes();
300 music_sequence_recording = false;
301 music_sequence_playing = true;
302 music_sequence_position = 0;
303 music_sequence_timer = 0;
304 return false;
305 }
306
307 if (keycode == KC_UP) {
308 if (record->event.pressed)
287eb7ad 309 music_sequence_interval-=10;
15719f35
JH
310 return false;
311 }
794aed37 312
15719f35
JH
313 if (keycode == KC_DOWN) {
314 if (record->event.pressed)
287eb7ad 315 music_sequence_interval+=10;
15719f35
JH
316 return false;
317 }
318
fde477a9 319 float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row));
1a8c0dd2 320 if (record->event.pressed) {
15719f35
JH
321 play_note(freq, 0xF);
322 if (music_sequence_recording) {
323 music_sequence[music_sequence_count] = freq;
324 music_sequence_count++;
325 }
1a8c0dd2 326 } else {
15719f35 327 stop_note(freq);
0428214b 328 }
15719f35 329
1a8c0dd2
EZ
330 if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
331 return false;
332 }
333 #endif
334
1a8c0dd2
EZ
335#ifndef DISABLE_LEADER
336 // Leader key set-up
337 if (record->event.pressed) {
338 if (!leading && keycode == KC_LEAD) {
339 leader_start();
340 leading = true;
341 leader_time = timer_read();
342 leader_sequence_size = 0;
343 leader_sequence[0] = 0;
344 leader_sequence[1] = 0;
345 leader_sequence[2] = 0;
346 return false;
347 }
348 if (leading && timer_elapsed(leader_time) < LEADER_TIMEOUT) {
349 leader_sequence[leader_sequence_size] = keycode;
350 leader_sequence_size++;
351 return false;
352 }
353 }
354#endif
355
356#define DISABLE_CHORDING
357#ifndef DISABLE_CHORDING
358
359 if (keycode >= 0x5700 && keycode <= 0x57FF) {
360 if (record->event.pressed) {
361 if (!chording) {
362 chording = true;
363 for (uint8_t i = 0; i < CHORDING_MAX; i++)
364 chord_keys[i] = 0;
365 chord_key_count = 0;
366 chord_key_down = 0;
367 }
368 chord_keys[chord_key_count] = (keycode & 0xFF);
369 chord_key_count++;
370 chord_key_down++;
371 return false;
372 } else {
373 if (chording) {
374 chord_key_down--;
375 if (chord_key_down == 0) {
376 chording = false;
377 // Chord Dictionary
378 if (keys_chord((uint8_t[]){KC_ENTER, KC_SPACE})) {
379 register_code(KC_A);
380 unregister_code(KC_A);
381 return false;
382 }
383 for (uint8_t i = 0; i < chord_key_count; i++) {
384 register_code(chord_keys[i]);
385 unregister_code(chord_keys[i]);
386 return false;
387 }
388 }
389 }
390 }
391 }
392
393#endif
394
b732b79b
JH
395#ifdef UNICODE_ENABLE
396
397 if (keycode > UNICODE(0) && record->event.pressed) {
398 uint16_t unicode = keycode & 0x7FFF;
399 switch(input_mode) {
400 case UC_OSX:
401 register_code(KC_LALT);
402 break;
403 case UC_LNX:
404 register_code(KC_LCTL);
405 register_code(KC_LSFT);
406 register_code(KC_U);
407 unregister_code(KC_U);
408 break;
409 case UC_WIN:
410 register_code(KC_LALT);
411 register_code(KC_PPLS);
412 unregister_code(KC_PPLS);
413 break;
414 }
415 for(int i = 3; i >= 0; i--) {
416 uint8_t digit = ((unicode >> (i*4)) & 0xF);
417 register_code(hex_to_keycode(digit));
418 unregister_code(hex_to_keycode(digit));
419 }
420 switch(input_mode) {
421 case UC_OSX:
422 case UC_WIN:
423 unregister_code(KC_LALT);
424 break;
425 case UC_LNX:
426 unregister_code(KC_LCTL);
427 unregister_code(KC_LSFT);
428 break;
429 }
430 }
431
432#endif
1a8c0dd2 433
12370259
EZ
434 switch(keycode) {
435 case KC_LSPO: {
436 if (record->event.pressed) {
437 shift_interrupted[0] = false;
438 register_mods(MOD_BIT(KC_LSFT));
439 }
440 else {
441 if (!shift_interrupted[0]) {
442 register_code(KC_9);
443 unregister_code(KC_9);
444 }
445 unregister_mods(MOD_BIT(KC_LSFT));
446 }
447 return false;
448 break;
449 }
450
451 case KC_RSPC: {
452 if (record->event.pressed) {
453 shift_interrupted[1] = false;
454 register_mods(MOD_BIT(KC_RSFT));
455 }
456 else {
457 if (!shift_interrupted[1]) {
458 register_code(KC_0);
459 unregister_code(KC_0);
460 }
461 unregister_mods(MOD_BIT(KC_RSFT));
462 }
463 return false;
464 break;
465 }
466 default: {
467 shift_interrupted[0] = true;
468 shift_interrupted[1] = true;
469 break;
470 }
471 }
472
1a8c0dd2
EZ
473 return process_action_kb(record);
474}
475
794aed37
ET
476const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = {
477 0, 0, 0, 0, 0, 0, 0, 0,
478 0, 0, 0, 0, 0, 0, 0, 0,
479 0, 0, 0, 0, 0, 0, 0, 0,
480 0, 0, 0, 0, 0, 0, 0, 0,
481 0, 1, 1, 1, 1, 1, 1, 0,
482 1, 1, 1, 1, 0, 0, 0, 0,
483 0, 0, 0, 0, 0, 0, 0, 0,
484 0, 0, 1, 0, 1, 0, 1, 1,
485 1, 1, 1, 1, 1, 1, 1, 1,
486 1, 1, 1, 1, 1, 1, 1, 1,
487 1, 1, 1, 1, 1, 1, 1, 1,
488 1, 1, 1, 0, 0, 0, 1, 1,
489 0, 0, 0, 0, 0, 0, 0, 0,
490 0, 0, 0, 0, 0, 0, 0, 0,
491 0, 0, 0, 0, 0, 0, 0, 0,
492 0, 0, 0, 1, 1, 1, 1, 0
1c9f33c0
JH
493};
494
794aed37
ET
495const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = {
496 0, 0, 0, 0, 0, 0, 0, 0,
497 KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
498 0, 0, 0, 0, 0, 0, 0, 0,
499 0, 0, 0, KC_ESC, 0, 0, 0, 0,
500 KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
501 KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
502 KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
503 KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
504 KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
505 KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
506 KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
507 KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
508 KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
509 KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
510 KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
511 KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
1c9f33c0
JH
512};
513
794aed37
ET
514/* for users whose OSes are set to Colemak */
515#if 0
516#include "keymap_colemak.h"
517
518const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = {
519 0, 0, 0, 0, 0, 0, 0, 0,
520 0, 0, 0, 0, 0, 0, 0, 0,
521 0, 0, 0, 0, 0, 0, 0, 0,
522 0, 0, 0, 0, 0, 0, 0, 0,
523 0, 1, 1, 1, 1, 1, 1, 0,
524 1, 1, 1, 1, 0, 0, 0, 0,
525 0, 0, 0, 0, 0, 0, 0, 0,
526 0, 0, 1, 0, 1, 0, 1, 1,
527 1, 1, 1, 1, 1, 1, 1, 1,
528 1, 1, 1, 1, 1, 1, 1, 1,
529 1, 1, 1, 1, 1, 1, 1, 1,
530 1, 1, 1, 0, 0, 0, 1, 1,
531 0, 0, 0, 0, 0, 0, 0, 0,
532 0, 0, 0, 0, 0, 0, 0, 0,
533 0, 0, 0, 0, 0, 0, 0, 0,
534 0, 0, 0, 1, 1, 1, 1, 0
535};
536
537const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = {
538 0, 0, 0, 0, 0, 0, 0, 0,
539 KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
540 0, 0, 0, 0, 0, 0, 0, 0,
541 0, 0, 0, KC_ESC, 0, 0, 0, 0,
542 KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
543 KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
544 KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
545 KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
546 KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
547 CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
548 CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
549 CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
550 KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
551 CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
552 CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
553 CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
554};
555
556#endif
557
558void send_string(const char *str) {
559 while (1) {
560 uint8_t keycode;
561 uint8_t ascii_code = pgm_read_byte(str);
562 if (!ascii_code) break;
563 keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]);
564 if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) {
565 register_code(KC_LSFT);
566 register_code(keycode);
567 unregister_code(keycode);
568 unregister_code(KC_LSFT);
569 }
570 else {
571 register_code(keycode);
572 unregister_code(keycode);
573 }
574 ++str;
1c9f33c0 575 }
1c9f33c0
JH
576}
577
578
1a8c0dd2
EZ
579void matrix_init_quantum() {
580 matrix_init_kb();
581}
582
583void matrix_scan_quantum() {
15719f35
JH
584 #ifdef AUDIO_ENABLE
585 if (music_sequence_playing) {
586 if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) {
587 music_sequence_timer = timer_read();
588 stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]);
589 play_note(music_sequence[music_sequence_position], 0xF);
590 music_sequence_position = (music_sequence_position + 1) % music_sequence_count;
591 }
592 }
593
594 #endif
fde477a9 595
1a8c0dd2 596 matrix_scan_kb();
0428214b 597}
0275d444 598#ifdef AUDIO_ENABLE
599 bool is_music_on(void) {
600 return (music_activated != 0);
601 }
0428214b 602
0275d444 603 void music_toggle(void) {
604 if (!music_activated) {
605 music_on();
606 } else {
607 music_off();
608 }
609 }
0428214b 610
0275d444 611 void music_on(void) {
612 music_activated = 1;
613 music_on_user();
614 }
0428214b 615
0275d444 616 void music_off(void) {
617 music_activated = 0;
618 stop_all_notes();
619 }
0428214b 620
0275d444 621#endif
287eb7ad
JH
622
623//------------------------------------------------------------------------------
794aed37 624// Override these functions in your keymap file to play different tunes on
287eb7ad
JH
625// different events such as startup and bootloader jump
626
627__attribute__ ((weak))
628void startup_user() {}
629
630__attribute__ ((weak))
631void shutdown_user() {}
632
0428214b 633__attribute__ ((weak))
0275d444 634void music_on_user() {}
287eb7ad
JH
635
636__attribute__ ((weak))
637void audio_on_user() {}
638
639__attribute__ ((weak))
640void music_scale_user() {}
641
12370259 642//------------------------------------------------------------------------------