modmusic.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2015 Damien P. George
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include "py/mphal.h"
  27. #if MICROPY_PY_MUSIC
  28. // #include "microbitobj.h"
  29. // #include "microbitmusic.h"
  30. #include "py/obj.h"
  31. #include "py/runtime.h"
  32. #include "py/objstr.h"
  33. #include "modmusic.h"
  34. #include "musictunes.h"
  35. #include "softpwm.h"
  36. #include "ticker.h"
  37. #include "pin.h"
  38. #include "genhdr/pins.h"
  39. #define DEFAULT_BPM 120
  40. #define DEFAULT_TICKS 4 // i.e. 4 ticks per beat
  41. #define DEFAULT_OCTAVE 4 // C4 is middle C
  42. #define DEFAULT_DURATION 4 // Crotchet
  43. #define ARTICULATION_MS 10 // articulation between notes in milliseconds
  44. typedef struct _music_data_t {
  45. uint16_t bpm;
  46. uint16_t ticks;
  47. // store these to simplify the writing process
  48. uint8_t last_octave;
  49. uint8_t last_duration;
  50. // Asynchronous parts.
  51. volatile uint8_t async_state;
  52. bool async_loop;
  53. uint32_t async_wait_ticks;
  54. uint16_t async_notes_len;
  55. uint16_t async_notes_index;
  56. const pin_obj_t *async_pin;
  57. mp_obj_t async_note;
  58. } music_data_t;
  59. enum {
  60. ASYNC_MUSIC_STATE_IDLE,
  61. ASYNC_MUSIC_STATE_NEXT_NOTE,
  62. ASYNC_MUSIC_STATE_ARTICULATE,
  63. };
  64. #define music_data MP_STATE_PORT(music_data)
  65. extern volatile uint32_t ticks;
  66. STATIC uint32_t start_note(const char *note_str, size_t note_len, const pin_obj_t *pin);
  67. void microbit_music_init0(void) {
  68. ticker_register_low_pri_callback(microbit_music_tick);
  69. }
  70. void microbit_music_tick(void) {
  71. if (music_data == NULL) {
  72. // music module not yet imported
  73. return;
  74. }
  75. if (music_data->async_state == ASYNC_MUSIC_STATE_IDLE) {
  76. // nothing to do
  77. return;
  78. }
  79. if (ticks < music_data->async_wait_ticks) {
  80. // need to wait for timeout to expire
  81. return;
  82. }
  83. if (music_data->async_state == ASYNC_MUSIC_STATE_ARTICULATE) {
  84. // turn off output and rest
  85. pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting.
  86. music_data->async_wait_ticks = ticks + ARTICULATION_MS;
  87. music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE;
  88. } else if (music_data->async_state == ASYNC_MUSIC_STATE_NEXT_NOTE) {
  89. // play next note
  90. if (music_data->async_notes_index >= music_data->async_notes_len) {
  91. if (music_data->async_loop) {
  92. music_data->async_notes_index = 0;
  93. } else {
  94. music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
  95. // TODO: microbit_obj_pin_free(music_data->async_pin);
  96. music_data->async_pin = NULL;
  97. return;
  98. }
  99. }
  100. mp_obj_t note;
  101. if (music_data->async_notes_len == 1) {
  102. note = music_data->async_note;
  103. } else {
  104. note = ((mp_obj_t*)music_data->async_note)[music_data->async_notes_index];
  105. }
  106. if (note == mp_const_none) {
  107. // a rest (is this even used anymore?)
  108. pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting.
  109. music_data->async_wait_ticks = 60000 / music_data->bpm;
  110. music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE;
  111. } else {
  112. // a note
  113. mp_uint_t note_len;
  114. const char *note_str = mp_obj_str_get_data(note, &note_len);
  115. uint32_t delay_on = start_note(note_str, note_len, music_data->async_pin);
  116. music_data->async_wait_ticks = ticks + delay_on;
  117. music_data->async_notes_index += 1;
  118. music_data->async_state = ASYNC_MUSIC_STATE_ARTICULATE;
  119. }
  120. }
  121. }
  122. STATIC void wait_async_music_idle(void) {
  123. // wait for the async music state to become idle
  124. while (music_data->async_state != ASYNC_MUSIC_STATE_IDLE) {
  125. // allow CTRL-C to stop the music
  126. if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
  127. music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
  128. pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting.
  129. break;
  130. }
  131. }
  132. }
  133. STATIC uint32_t start_note(const char *note_str, size_t note_len, const pin_obj_t *pin) {
  134. pwm_set_duty_cycle(pin->pin, 128); // TODO: remove pin setting.
  135. // [NOTE](#|b)(octave)(:length)
  136. // technically, c4 is middle c, so we'll go with that...
  137. // if we define A as 0 and G as 7, then we can use the following
  138. // array of us periods
  139. // these are the periods of note4 (the octave ascending from middle c) from A->B then C->G
  140. STATIC uint16_t periods_us[] = {2273, 2025, 3822, 3405, 3034, 2863, 2551};
  141. // A#, -, C#, D#, -, F#, G#
  142. STATIC uint16_t periods_sharps_us[] = {2145, 0, 3608, 3214, 0, 2703, 2408};
  143. // we'll represent the note as an integer (A=0, G=6)
  144. // TODO: validate the note
  145. uint8_t note_index = (note_str[0] & 0x1f) - 1;
  146. // TODO: the duration and bpm should be persistent between notes
  147. uint32_t ms_per_tick = (60000 / music_data->bpm) / music_data->ticks;
  148. int8_t octave = 0;
  149. bool sharp = false;
  150. size_t current_position = 1;
  151. // parse sharp or flat
  152. if (current_position < note_len && (note_str[current_position] == '#' || note_str[current_position] == 'b')) {
  153. if (note_str[current_position] == 'b') {
  154. // make sure we handle wrapping round gracefully
  155. if (note_index == 0) {
  156. note_index = 6;
  157. } else {
  158. note_index--;
  159. }
  160. // handle the unusual edge case of Cb
  161. if (note_index == 1) {
  162. octave--;
  163. }
  164. }
  165. sharp = true;
  166. current_position++;
  167. }
  168. // parse the octave
  169. if (current_position < note_len && note_str[current_position] != ':') {
  170. // currently this will only work with a one digit number
  171. // use +=, since the sharp/flat code changes octave to compensate.
  172. music_data->last_octave = (note_str[current_position] & 0xf);
  173. current_position++;
  174. }
  175. octave += music_data->last_octave;
  176. // parse the duration
  177. if (current_position < note_len && note_str[current_position] == ':') {
  178. // I'll make this handle up to two digits for the time being.
  179. current_position++;
  180. if (current_position < note_len) {
  181. music_data->last_duration = note_str[current_position] & 0xf;
  182. current_position++;
  183. if (current_position < note_len) {
  184. music_data->last_duration *= 10;
  185. music_data->last_duration += note_str[current_position] & 0xf;
  186. }
  187. } else {
  188. // technically, this should be a syntax error, since this means
  189. // that no duration has been specified. For the time being,
  190. // we'll let you off :D
  191. }
  192. }
  193. // play the note!
  194. // make the octave relative to octave 4
  195. octave -= 4;
  196. // 18 is 'r' or 'R'
  197. if (note_index < 10) {
  198. uint32_t period;
  199. if (sharp) {
  200. if (octave >= 0) {
  201. period = periods_sharps_us[note_index] >> octave;
  202. }
  203. else {
  204. period = periods_sharps_us[note_index] << -octave;
  205. }
  206. } else {
  207. if (octave >= 0) {
  208. period = periods_us[note_index] >> octave;
  209. }
  210. else {
  211. period = periods_us[note_index] << -octave;
  212. }
  213. }
  214. pwm_set_period_us(period);
  215. } else {
  216. pwm_set_duty_cycle(pin->pin, 0); // TODO: remove pin setting.
  217. }
  218. // Cut off a short time from end of note so we hear articulation.
  219. mp_int_t gap_ms = (ms_per_tick * music_data->last_duration) - ARTICULATION_MS;
  220. if (gap_ms < ARTICULATION_MS) {
  221. gap_ms = ARTICULATION_MS;
  222. }
  223. return gap_ms;
  224. }
  225. STATIC mp_obj_t microbit_music_reset(void) {
  226. music_data->bpm = DEFAULT_BPM;
  227. music_data->ticks = DEFAULT_TICKS;
  228. music_data->last_octave = DEFAULT_OCTAVE;
  229. music_data->last_duration = DEFAULT_DURATION;
  230. return mp_const_none;
  231. }
  232. MP_DEFINE_CONST_FUN_OBJ_0(microbit_music_reset_obj, microbit_music_reset);
  233. STATIC mp_obj_t microbit_music_get_tempo(void) {
  234. mp_obj_t tempo_tuple[2];
  235. tempo_tuple[0] = mp_obj_new_int(music_data->bpm);
  236. tempo_tuple[1] = mp_obj_new_int(music_data->ticks);
  237. return mp_obj_new_tuple(2, tempo_tuple);
  238. }
  239. MP_DEFINE_CONST_FUN_OBJ_0(microbit_music_get_tempo_obj, microbit_music_get_tempo);
  240. STATIC mp_obj_t microbit_music_stop(mp_uint_t n_args, const mp_obj_t *args) {
  241. const pin_obj_t *pin;
  242. if (n_args == 0) {
  243. #ifdef MICROPY_HW_MUSIC_PIN
  244. pin = mp_hal_get_pin_obj(MP_OBJ_NEW_SMALL_INT(MICROPY_HW_MUSIC_PIN));
  245. #else
  246. mp_raise_ValueError("pin parameter not given");
  247. #endif
  248. } else {
  249. pin = (pin_obj_t *)args[0];
  250. }
  251. (void)pin;
  252. // Raise exception if the pin we are trying to stop is not in a compatible mode.
  253. // TODO: microbit_obj_pin_acquire(pin, microbit_pin_mode_music);
  254. pwm_set_duty_cycle(pin->pin, 0); // TODO: remove pin setting.
  255. // TODO: microbit_obj_pin_free(pin);
  256. music_data->async_pin = NULL;
  257. music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
  258. return mp_const_none;
  259. }
  260. MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_music_stop_obj, 0, 1, microbit_music_stop);
  261. STATIC mp_obj_t microbit_music_play(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
  262. static const mp_arg_t allowed_args[] = {
  263. { MP_QSTR_music, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  264. { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  265. { MP_QSTR_wait, MP_ARG_BOOL, {.u_bool = true} },
  266. { MP_QSTR_loop, MP_ARG_BOOL, {.u_bool = false} },
  267. };
  268. // parse args
  269. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  270. mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
  271. // reset octave and duration so tunes always play the same
  272. music_data->last_octave = DEFAULT_OCTAVE;
  273. music_data->last_duration = DEFAULT_DURATION;
  274. // get either a single note or a list of notes
  275. mp_uint_t len;
  276. mp_obj_t *items;
  277. if (MP_OBJ_IS_STR_OR_BYTES(args[0].u_obj)) {
  278. len = 1;
  279. items = &args[0].u_obj;
  280. } else {
  281. mp_obj_get_array(args[0].u_obj, &len, &items);
  282. }
  283. // Release the previous pin
  284. // TODO: microbit_obj_pin_free(music_data->async_pin);
  285. music_data->async_pin = NULL;
  286. // get the pin to play on
  287. const pin_obj_t *pin;
  288. if (args[1].u_obj == MP_OBJ_NULL) {
  289. #ifdef MICROPY_HW_MUSIC_PIN
  290. pin = mp_hal_get_pin_obj(MP_OBJ_NEW_SMALL_INT(MICROPY_HW_MUSIC_PIN));
  291. #else
  292. mp_raise_ValueError("pin parameter not given");
  293. #endif
  294. } else {
  295. pin = (pin_obj_t *)args[1].u_obj;
  296. }
  297. // TODO: microbit_obj_pin_acquire(pin, microbit_pin_mode_music);
  298. // start the tune running in the background
  299. music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
  300. music_data->async_wait_ticks = ticks;
  301. music_data->async_loop = args[3].u_bool;
  302. music_data->async_notes_len = len;
  303. music_data->async_notes_index = 0;
  304. if (len == 1) {
  305. // If a string was passed as a single note then we can't store a pointer
  306. // to args[0].u_obj, so instead store the single string directly (also
  307. // works if a tuple/list of one element was passed).
  308. music_data->async_note = items[0];
  309. } else {
  310. music_data->async_note = items;
  311. }
  312. music_data->async_pin = pin;
  313. music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE;
  314. if (args[2].u_bool) {
  315. // wait for tune to finish
  316. wait_async_music_idle();
  317. }
  318. return mp_const_none;
  319. }
  320. MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_play_obj, 0, microbit_music_play);
  321. STATIC mp_obj_t microbit_music_pitch(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
  322. static const mp_arg_t allowed_args[] = {
  323. { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
  324. { MP_QSTR_duration, MP_ARG_INT, {.u_int = -1} },
  325. { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  326. { MP_QSTR_wait, MP_ARG_BOOL, {.u_bool = true} },
  327. };
  328. // parse args
  329. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  330. mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
  331. // get the parameters
  332. mp_uint_t frequency = args[0].u_int;
  333. mp_int_t duration = args[1].u_int;
  334. // get the pin to play on
  335. const pin_obj_t *pin;
  336. if (args[2].u_obj == MP_OBJ_NULL) {
  337. #ifdef MICROPY_HW_MUSIC_PIN
  338. pin = mp_hal_get_pin_obj(MP_OBJ_NEW_SMALL_INT(MICROPY_HW_MUSIC_PIN));
  339. #else
  340. mp_raise_ValueError("pin parameter not given");
  341. #endif
  342. } else {
  343. pin = (pin_obj_t *)args[2].u_obj;
  344. }
  345. // Update pin modes
  346. //TODO: microbit_obj_pin_free(music_data->async_pin);
  347. music_data->async_pin = NULL;
  348. //TODO: microbit_obj_pin_acquire(pin, microbit_pin_mode_music);
  349. bool wait = args[3].u_bool;
  350. pwm_set_duty_cycle(pin->pin, 128); // TODO: remove pin setting.
  351. if (frequency == 0) {
  352. //TODO: pwm_release(pin->name);
  353. } else if (pwm_set_period_us(1000000/frequency)) {
  354. pwm_release(pin->pin); // TODO: remove pin setting.
  355. mp_raise_ValueError("invalid pitch");
  356. }
  357. if (duration >= 0) {
  358. // use async machinery to stop the pitch after the duration
  359. music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
  360. music_data->async_wait_ticks = ticks + duration;
  361. music_data->async_loop = false;
  362. music_data->async_notes_len = 0;
  363. music_data->async_notes_index = 0;
  364. music_data->async_note = NULL;
  365. music_data->async_pin = pin;
  366. music_data->async_state = ASYNC_MUSIC_STATE_ARTICULATE;
  367. if (wait) {
  368. // wait for the pitch to finish
  369. wait_async_music_idle();
  370. }
  371. } else {
  372. // don't block here, since there's no reason to leave a pitch forever in a blocking C function
  373. }
  374. return mp_const_none;
  375. }
  376. MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_pitch_obj, 0, microbit_music_pitch);
  377. STATIC mp_obj_t microbit_music_set_tempo(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
  378. static const mp_arg_t allowed_args[] = {
  379. { MP_QSTR_ticks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
  380. { MP_QSTR_bpm, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
  381. };
  382. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  383. mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
  384. if (args[0].u_int != 0) {
  385. // set ticks
  386. music_data->ticks = args[0].u_int;
  387. }
  388. if (args[1].u_int != 0) {
  389. music_data->bpm = args[1].u_int;
  390. }
  391. return mp_const_none;
  392. }
  393. MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_set_tempo_obj, 0, microbit_music_set_tempo);
  394. static mp_obj_t music_init(void) {
  395. music_data = m_new_obj(music_data_t);
  396. music_data->bpm = DEFAULT_BPM;
  397. music_data->ticks = DEFAULT_TICKS;
  398. music_data->last_octave = DEFAULT_OCTAVE;
  399. music_data->last_duration = DEFAULT_DURATION;
  400. music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
  401. music_data->async_pin = NULL;
  402. music_data->async_note = NULL;
  403. return mp_const_none;
  404. }
  405. MP_DEFINE_CONST_FUN_OBJ_0(music___init___obj, music_init);
  406. STATIC const mp_rom_map_elem_t microbit_music_locals_dict_table[] = {
  407. { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&music___init___obj) },
  408. { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&microbit_music_reset_obj) },
  409. { MP_ROM_QSTR(MP_QSTR_set_tempo), MP_ROM_PTR(&microbit_music_set_tempo_obj) },
  410. { MP_ROM_QSTR(MP_QSTR_get_tempo), MP_ROM_PTR(&microbit_music_get_tempo_obj) },
  411. { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&microbit_music_play_obj) },
  412. { MP_ROM_QSTR(MP_QSTR_pitch), MP_ROM_PTR(&microbit_music_pitch_obj) },
  413. { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&microbit_music_stop_obj) },
  414. { MP_ROM_QSTR(MP_QSTR_DADADADUM), MP_ROM_PTR(&microbit_music_tune_dadadadum_obj) },
  415. { MP_ROM_QSTR(MP_QSTR_ENTERTAINER), MP_ROM_PTR(&microbit_music_tune_entertainer_obj) },
  416. { MP_ROM_QSTR(MP_QSTR_PRELUDE), MP_ROM_PTR(&microbit_music_tune_prelude_obj) },
  417. { MP_ROM_QSTR(MP_QSTR_ODE), MP_ROM_PTR(&microbit_music_tune_ode_obj) },
  418. { MP_ROM_QSTR(MP_QSTR_NYAN), MP_ROM_PTR(&microbit_music_tune_nyan_obj) },
  419. { MP_ROM_QSTR(MP_QSTR_RINGTONE), MP_ROM_PTR(&microbit_music_tune_ringtone_obj) },
  420. { MP_ROM_QSTR(MP_QSTR_FUNK), MP_ROM_PTR(&microbit_music_tune_funk_obj) },
  421. { MP_ROM_QSTR(MP_QSTR_BLUES), MP_ROM_PTR(&microbit_music_tune_blues_obj) },
  422. { MP_ROM_QSTR(MP_QSTR_BIRTHDAY), MP_ROM_PTR(&microbit_music_tune_birthday_obj) },
  423. { MP_ROM_QSTR(MP_QSTR_WEDDING), MP_ROM_PTR(&microbit_music_tune_wedding_obj) },
  424. { MP_ROM_QSTR(MP_QSTR_FUNERAL), MP_ROM_PTR(&microbit_music_tune_funeral_obj) },
  425. { MP_ROM_QSTR(MP_QSTR_PUNCHLINE), MP_ROM_PTR(&microbit_music_tune_punchline_obj) },
  426. { MP_ROM_QSTR(MP_QSTR_PYTHON), MP_ROM_PTR(&microbit_music_tune_python_obj) },
  427. { MP_ROM_QSTR(MP_QSTR_BADDY), MP_ROM_PTR(&microbit_music_tune_baddy_obj) },
  428. { MP_ROM_QSTR(MP_QSTR_CHASE), MP_ROM_PTR(&microbit_music_tune_chase_obj) },
  429. { MP_ROM_QSTR(MP_QSTR_BA_DING), MP_ROM_PTR(&microbit_music_tune_ba_ding_obj) },
  430. { MP_ROM_QSTR(MP_QSTR_WAWAWAWAA), MP_ROM_PTR(&microbit_music_tune_wawawawaa_obj) },
  431. { MP_ROM_QSTR(MP_QSTR_JUMP_UP), MP_ROM_PTR(&microbit_music_tune_jump_up_obj) },
  432. { MP_ROM_QSTR(MP_QSTR_JUMP_DOWN), MP_ROM_PTR(&microbit_music_tune_jump_down_obj) },
  433. { MP_ROM_QSTR(MP_QSTR_POWER_UP), MP_ROM_PTR(&microbit_music_tune_power_up_obj) },
  434. { MP_ROM_QSTR(MP_QSTR_POWER_DOWN), MP_ROM_PTR(&microbit_music_tune_power_down_obj) },
  435. };
  436. STATIC MP_DEFINE_CONST_DICT(microbit_music_locals_dict, microbit_music_locals_dict_table);
  437. const mp_obj_module_t music_module = {
  438. .base = { &mp_type_module },
  439. .globals = (mp_obj_dict_t*)&microbit_music_locals_dict,
  440. };
  441. #endif // MICROPY_PY_MUSIC