/**************************************************************************** * apps/examples/fmsynth/mmlplayer_main.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "operator_algorithm.h" #include "music_scale.h" #include "mmlplayer_score.h" /**************************************************************************** * Pre-processor ****************************************************************************/ #define APP_FS (48000) #define APP_BPS (16) #define APP_CHNUM (2) #define CARRIER_LEVEL (25.f / 100.f) #define APP_DEFAULT_VOL (1000) /**************************************************************************** * Private Data Type ****************************************************************************/ struct app_options { int volume; int mode; }; struct mmlplayer_s { struct nxaudio_s nxaudio; /* Right hand sound */ FAR fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */ FAR fmsynth_op_t *rop[2]; /* Need 2 sounds for CHORD */ int rtick; FAR char *rscore; struct music_macro_lang_s rmml; /* Left hand sound */ FAR fmsynth_sound_t *lsound; FAR fmsynth_op_t *lop; int ltick; FAR char *lscore; struct music_macro_lang_s lmml; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void app_dequeue_cb(unsigned long arg, FAR struct ap_buffer_s *apb); static void app_complete_cb(unsigned long arg); static void app_user_cb(unsigned long arg, FAR struct audio_msg_s *msg, FAR bool *running); /**************************************************************************** * Private Data ****************************************************************************/ static struct mmlplayer_s g_mmlplayer; static struct nxaudio_callbacks_s cbs = { app_dequeue_cb, app_complete_cb, app_user_cb }; /**************************************************************************** * Private functions ****************************************************************************/ /**************************************************************************** * name: print_note ****************************************************************************/ static void print_note(bool LR, int index, int length) { printf("%c: O%d%c : %d\n", LR ? 'R' : 'L', index / 12, "CcDdEFfGgAaB"[index % 12], length); } /**************************************************************************** * name: print_chord ****************************************************************************/ static void print_chord(bool LR, int index1, int index2, int length) { printf("%c: [O%d%c, O%d%c] : %d\n", LR ? 'R' : 'L', index1 / 12, "CcDdEFfGgAaB"[index1 % 12], index2 / 12, "CcDdEFfGgAaB"[index2 % 12], length); } /**************************************************************************** * name: update_righthand_note ****************************************************************************/ static void update_righthand_note(FAR struct mmlplayer_s *fmmsc) { int mml_ret; struct mml_result_s mml_result; fmmsc->rtick = 0; do { mml_ret = parse_mml(&fmmsc->rmml, &fmmsc->rscore, &mml_result); switch (mml_ret) { case MML_TYPE_NOTE: fmmsc->rtick = mml_result.length; fmsynthsnd_set_soundfreq(fmmsc->rsound[0], musical_scale[mml_result.note_idx[0]]); fmsynthsnd_set_volume(fmmsc->rsound[0], CARRIER_LEVEL); fmsynthsnd_set_volume(fmmsc->rsound[1], 0.f); print_note(1, mml_result.note_idx[0], mml_result.length); break; case MML_TYPE_CHORD: fmmsc->rtick = mml_result.length; fmsynthsnd_set_soundfreq(fmmsc->rsound[0], musical_scale[mml_result.note_idx[0]]); fmsynthsnd_set_soundfreq(fmmsc->rsound[1], musical_scale[mml_result.note_idx[1]]); fmsynthsnd_set_volume(fmmsc->rsound[0], CARRIER_LEVEL); fmsynthsnd_set_volume(fmmsc->rsound[1], CARRIER_LEVEL); print_chord(1, mml_result.note_idx[0], mml_result.note_idx[1], mml_result.length); break; case MML_TYPE_REST: fmmsc->rtick = mml_result.length; fmsynthsnd_set_volume(fmmsc->rsound[0], 0.f); fmsynthsnd_set_volume(fmmsc->rsound[1], 0.f); printf("R: Rest : %d\n", mml_result.length); break; default: /* Do nothing */ break; } } while (!fmmsc->rtick && mml_ret != MML_TYPE_EOF); } /**************************************************************************** * name: update_lefthand_note ****************************************************************************/ static void update_lefthand_note(FAR struct mmlplayer_s *fmmsc) { int mml_ret; struct mml_result_s mml_result; fmmsc->ltick = 0; do { mml_ret = parse_mml(&fmmsc->lmml, &fmmsc->lscore, &mml_result); switch (mml_ret) { case MML_TYPE_NOTE: fmmsc->ltick = mml_result.length; fmsynthsnd_set_soundfreq(fmmsc->lsound, musical_scale[mml_result.note_idx[0]]); fmsynthsnd_set_volume(fmmsc->lsound, CARRIER_LEVEL); print_note(0, mml_result.note_idx[0], mml_result.length); break; case MML_TYPE_REST: fmmsc->ltick = mml_result.length; fmsynthsnd_set_volume(fmmsc->lsound, 0.f); printf("L: Rest : %d\n", mml_result.length); break; default: /* Do nothing */ break; } } while (!fmmsc->ltick && mml_ret != MML_TYPE_EOF); } /**************************************************************************** * name: tick_callback ****************************************************************************/ static void tick_callback(unsigned long arg) { FAR struct mmlplayer_s *fmmsc = (FAR struct mmlplayer_s *)(uintptr_t)arg; fmmsc->rtick--; fmmsc->ltick--; if (fmmsc->rtick <= 0) { update_righthand_note(fmmsc); } if (fmmsc->ltick <= 0) { update_lefthand_note(fmmsc); } } /**************************************************************************** * name: app_dequeue_cb ****************************************************************************/ static void app_dequeue_cb(unsigned long arg, FAR struct ap_buffer_s *apb) { FAR struct mmlplayer_s *mmlplayer = (struct mmlplayer_s *)(uintptr_t)arg; apb->curbyte = 0; apb->flags = 0; apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (FAR int16_t *)apb->samp, apb->nmaxbytes / sizeof(int16_t), mmlplayer->nxaudio.chnum, tick_callback, (unsigned long)(uintptr_t)mmlplayer); nxaudio_enqbuffer(&mmlplayer->nxaudio, apb); } /**************************************************************************** * name: app_complete_cb ****************************************************************************/ static void app_complete_cb(unsigned long arg) { /* Do nothing.. */ printf("Audio loop is Done\n"); } /**************************************************************************** * name: app_user_cb ****************************************************************************/ static void app_user_cb(unsigned long arg, FAR struct audio_msg_s *msg, FAR bool *running) { /* Do nothing.. */ } /**************************************************************************** * name: autio_loop_thread ****************************************************************************/ static FAR void *audio_loop_thread(pthread_addr_t arg) { struct mmlplayer_s *mmlplayer = (FAR struct mmlplayer_s *)arg; nxaudio_start(&mmlplayer->nxaudio); nxaudio_msgloop(&mmlplayer->nxaudio, &cbs, (unsigned long)(uintptr_t)mmlplayer); return NULL; } /**************************************************************************** * name: create_audio_thread ****************************************************************************/ static pthread_t create_audio_thread(FAR struct mmlplayer_s *mmlplayer) { pthread_t pid; pthread_attr_t tattr; struct sched_param sparam; pthread_attr_init(&tattr); sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9; pthread_attr_setschedparam(&tattr, &sparam); pthread_attr_setstacksize(&tattr, 4096); pthread_create(&pid, &tattr, audio_loop_thread, (pthread_addr_t)mmlplayer); pthread_setname_np(pid, "mmlplayer_thread"); return pid; } /**************************************************************************** * name: delete_sounds ****************************************************************************/ static void delete_sounds(FAR struct mmlplayer_s *mmlplayer) { if (mmlplayer->rop[0]) { fmsynthutil_delete_ops(mmlplayer->rop[0]); } if (mmlplayer->rop[1]) { fmsynthutil_delete_ops(mmlplayer->rop[1]); } if (mmlplayer->lop) { fmsynthutil_delete_ops(mmlplayer->lop); } if (mmlplayer->rsound[0]) { fmsynthsnd_delete(mmlplayer->rsound[0]); } if (mmlplayer->rsound[1]) { fmsynthsnd_delete(mmlplayer->rsound[1]); } if (mmlplayer->lsound) { fmsynthsnd_delete(mmlplayer->lsound); } } /**************************************************************************** * name: init_fmmusi_soundsc ****************************************************************************/ static int init_mmlplayer_sound(FAR struct mmlplayer_s *mmlplayer, int fs, int mode) { CODE fmsynth_op_t *(*opfunc)(void); opfunc = mode == 0 ? fmsynthutil_algorithm0 : mode == 1 ? fmsynthutil_algorithm1 : mode == 2 ? fmsynthutil_algorithm2 : NULL; fmsynth_initialize(fs); mmlplayer->rop[0] = NULL; mmlplayer->rop[1] = NULL; mmlplayer->lop = NULL; mmlplayer->rsound[0] = fmsynthsnd_create(); mmlplayer->rsound[1] = fmsynthsnd_create(); mmlplayer->lsound = fmsynthsnd_create(); if (mmlplayer->rsound[0] && mmlplayer->rsound[1] && mmlplayer->lsound) { mmlplayer->rop[0] = opfunc(); mmlplayer->rop[1] = opfunc(); mmlplayer->lop = opfunc(); if (mmlplayer->rop[0] && mmlplayer->rop[1] && mmlplayer->lop) { fmsynthsnd_set_operator(mmlplayer->rsound[0], mmlplayer->rop[0]); fmsynthsnd_set_operator(mmlplayer->rsound[1], mmlplayer->rop[1]); fmsynthsnd_set_operator(mmlplayer->lsound, mmlplayer->lop); fmsynthsnd_set_operator(mmlplayer->lsound, mmlplayer->lop); fmsynthsnd_add_subsound(mmlplayer->lsound, mmlplayer->rsound[0]); fmsynthsnd_add_subsound(mmlplayer->lsound, mmlplayer->rsound[1]); } else { delete_sounds(mmlplayer); return ERROR; } } else { delete_sounds(mmlplayer); return ERROR; } mmlplayer->rtick = 0; mmlplayer->ltick = 0; init_mml(&mmlplayer->rmml, fs, 120, 4, 4); init_mml(&mmlplayer->lmml, fs, 120, 4, 3); mmlplayer->rscore = (FAR char *)floh_walzer_right; mmlplayer->lscore = (FAR char *)floh_walzer_left; return OK; } /**************************************************************************** * name: fin_mmlplayer ****************************************************************************/ static void fin_mmlplayer(FAR struct mmlplayer_s *mmlplayer) { fin_nxaudio(&mmlplayer->nxaudio); delete_sounds(mmlplayer); } /**************************************************************************** * name: print_help ****************************************************************************/ static void print_help(FAR char *name) { printf("nsh> %s ([-v (volume)]) ([-m (mode)])\n", name); } /**************************************************************************** * name: configure_option ****************************************************************************/ static int configure_option(FAR struct app_options *option, int argc, char **argv) { int opt; option->volume = APP_DEFAULT_VOL; option->mode = 0; while ((opt = getopt(argc, argv, "hv:m:")) != ERROR) { switch (opt) { case 'v': option->volume = atoi(optarg) * 10; if (option->volume < 0 || option->volume > 1000) { option->volume = 400; } break; case 'm': option->mode = atoi(optarg); if (option->mode < 0 || option->mode >= 3) { option->mode = 0; } break; case 'h': return ERROR; break; default: return ERROR; break; } } return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * name: main ****************************************************************************/ int main(int argc, FAR char *argv[]) { int i; int ret; int key; bool running = true; pthread_t pid; struct app_options appopt; printf("Start %s\n", argv[0]); if (configure_option(&appopt, argc, argv) != OK) { print_help(argv[0]); return -1; } ret = init_nxaudio(&g_mmlplayer.nxaudio, APP_FS, APP_BPS, APP_CHNUM); if (ret < 0) { printf("init_nxaoud() returned with error!!\n"); return -1; } nxaudio_setvolume(&g_mmlplayer.nxaudio, appopt.volume); ret = init_mmlplayer_sound(&g_mmlplayer, APP_FS, appopt.mode); if (ret != OK) { printf("init_mmlplayer_sound() returned error.\n"); fin_nxaudio(&g_mmlplayer.nxaudio); return -1; } for (i = 0; i < g_mmlplayer.nxaudio.abufnum; i++) { app_dequeue_cb((unsigned long)&g_mmlplayer, g_mmlplayer.nxaudio.abufs[i]); } pid = create_audio_thread(&g_mmlplayer); while (running) { key = getchar(); if (key != EOF) { switch (key) { case 'q': running = false; break; } } } nxaudio_stop(&g_mmlplayer.nxaudio); pthread_join(pid, NULL); fin_mmlplayer(&g_mmlplayer); return ret; }