1c23a095ea
if (key != EOF) ~~~ ^ ~~~ Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
450 lines
12 KiB
C
450 lines
12 KiB
C
/****************************************************************************
|
|
* apps/examples/fmsynth/keyboard_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 <nuttx/config.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <sched.h>
|
|
#include <limits.h>
|
|
|
|
#include <nuttx/audio/audio.h>
|
|
#include <audioutils/fmsynth.h>
|
|
#include <audioutils/nxaudio.h>
|
|
|
|
#include "operator_algorithm.h"
|
|
#include "music_scale.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor
|
|
****************************************************************************/
|
|
|
|
#define APP_FS (48000)
|
|
#define APP_BPS (16)
|
|
#define APP_CHNUM (2)
|
|
|
|
#define APP_DEFAULT_VOL (400)
|
|
|
|
/****************************************************************************
|
|
* Private Data Type
|
|
****************************************************************************/
|
|
|
|
struct app_options
|
|
{
|
|
int volume;
|
|
int mode;
|
|
};
|
|
|
|
struct kbd_s
|
|
{
|
|
struct nxaudio_s nxaudio;
|
|
|
|
FAR fmsynth_sound_t *sound;
|
|
FAR fmsynth_op_t *carrier;
|
|
|
|
volatile int request_scale;
|
|
};
|
|
|
|
struct key_convert_s
|
|
{
|
|
int key;
|
|
char key_str;
|
|
FAR const char *dispstr;
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
extern int board_external_amp_mute_control(bool en);
|
|
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 kbd_s g_kbd;
|
|
|
|
static struct nxaudio_callbacks_s cbs =
|
|
{
|
|
app_dequeue_cb,
|
|
app_complete_cb,
|
|
app_user_cb
|
|
};
|
|
|
|
static struct key_convert_s key_convert[] =
|
|
{
|
|
{ OCTAVE(4, MUSIC_SCALE_C), 'a', "O4C" },
|
|
{ OCTAVE(4, MUSIC_SCALE_CS), 'w', "O4C+" },
|
|
{ OCTAVE(4, MUSIC_SCALE_D), 's', "O4D" },
|
|
{ OCTAVE(4, MUSIC_SCALE_DS), 'e', "O4D+" },
|
|
{ OCTAVE(4, MUSIC_SCALE_E), 'd', "O4E" },
|
|
{ OCTAVE(4, MUSIC_SCALE_F), 'f', "O4F" },
|
|
{ OCTAVE(4, MUSIC_SCALE_FS), 't', "O4F+" },
|
|
{ OCTAVE(4, MUSIC_SCALE_G), 'g', "O4G" },
|
|
{ OCTAVE(4, MUSIC_SCALE_GS), 'y', "O4G+" },
|
|
{ OCTAVE(4, MUSIC_SCALE_A), 'h', "O4A" },
|
|
{ OCTAVE(4, MUSIC_SCALE_AS), 'u', "O4A+" },
|
|
{ OCTAVE(4, MUSIC_SCALE_B), 'j', "O4B" },
|
|
{ OCTAVE(5, MUSIC_SCALE_C), 'k', "O5C" },
|
|
{ OCTAVE(5, MUSIC_SCALE_CS), 'o', "O5C+" },
|
|
{ OCTAVE(5, MUSIC_SCALE_D), 'l', "O5D" },
|
|
{ OCTAVE(5, MUSIC_SCALE_DS), 'p', "O5D+" },
|
|
{ OCTAVE(5, MUSIC_SCALE_E), ';', "O5E" },
|
|
};
|
|
|
|
#define MAX_KEYCONVERT (sizeof(key_convert)/sizeof(key_convert[0]))
|
|
|
|
/****************************************************************************
|
|
* Private functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* name: convert_key2idx
|
|
****************************************************************************/
|
|
|
|
static int convert_key2idx(char key)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_KEYCONVERT; i++)
|
|
{
|
|
if (key == key_convert[i].key_str)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: tick_callback
|
|
****************************************************************************/
|
|
|
|
static void tick_callback(unsigned long arg)
|
|
{
|
|
FAR struct kbd_s *kbd = (FAR struct kbd_s *)(uintptr_t)arg;
|
|
int scale = kbd->request_scale;
|
|
|
|
if (scale != -1)
|
|
{
|
|
fmsynthsnd_set_soundfreq(kbd->sound,
|
|
musical_scale[scale]);
|
|
kbd->request_scale = -1;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: app_dequeue_cb
|
|
****************************************************************************/
|
|
|
|
static void app_dequeue_cb(unsigned long arg,
|
|
FAR struct ap_buffer_s *apb)
|
|
{
|
|
FAR struct kbd_s *kbd = (FAR struct kbd_s *)(uintptr_t)arg;
|
|
|
|
apb->curbyte = 0;
|
|
apb->flags = 0;
|
|
|
|
if (kbd->request_scale != -1)
|
|
{
|
|
apb->nbytes = fmsynth_rendering(kbd->sound,
|
|
(FAR int16_t *)apb->samp,
|
|
apb->nmaxbytes / sizeof(int16_t),
|
|
kbd->nxaudio.chnum,
|
|
tick_callback, (unsigned long)kbd);
|
|
}
|
|
else
|
|
{
|
|
apb->nbytes = fmsynth_rendering(kbd->sound,
|
|
(FAR int16_t *)apb->samp,
|
|
apb->nmaxbytes / sizeof(int16_t),
|
|
kbd->nxaudio.chnum,
|
|
NULL, 0);
|
|
}
|
|
|
|
nxaudio_enqbuffer(&kbd->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: audio_loop_thread
|
|
****************************************************************************/
|
|
|
|
static FAR void *audio_loop_thread(pthread_addr_t arg)
|
|
{
|
|
FAR struct kbd_s *kbd = (FAR struct kbd_s *)arg;
|
|
|
|
nxaudio_start(&kbd->nxaudio);
|
|
nxaudio_msgloop(&kbd->nxaudio, &cbs, (unsigned long)kbd);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: create_audio_thread
|
|
****************************************************************************/
|
|
|
|
static pthread_t create_audio_thread(FAR struct kbd_s *kbd)
|
|
{
|
|
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)kbd);
|
|
pthread_setname_np(pid, "musickeyboard_thread");
|
|
|
|
return pid;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: init_fmmusi_soundsc
|
|
****************************************************************************/
|
|
|
|
static int init_keyboard_sound(FAR struct kbd_s *kbd, int fs, int mode)
|
|
{
|
|
int ret = ERROR;
|
|
|
|
fmsynth_initialize(fs);
|
|
|
|
kbd->sound = fmsynthsnd_create();
|
|
if (kbd->sound)
|
|
{
|
|
kbd->carrier = mode == 0 ? fmsynthutil_algorithm0() :
|
|
mode == 1 ? fmsynthutil_algorithm1() :
|
|
mode == 2 ? fmsynthutil_algorithm2() :
|
|
NULL;
|
|
if (!kbd->carrier)
|
|
{
|
|
fmsynthsnd_delete(kbd->sound);
|
|
return ret;
|
|
}
|
|
|
|
fmsynthsnd_set_operator(kbd->sound, kbd->carrier);
|
|
kbd->request_scale = -1;
|
|
ret = OK;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: fin_keyboard
|
|
****************************************************************************/
|
|
|
|
static void fin_keyboard(FAR struct kbd_s *kbd)
|
|
{
|
|
fin_nxaudio(&kbd->nxaudio);
|
|
fmsynthutil_delete_ops(kbd->carrier);
|
|
fmsynthsnd_delete(kbd->sound);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: print_help
|
|
****************************************************************************/
|
|
|
|
static void print_help(FAR char *name)
|
|
{
|
|
printf("nsh> %s ([-v (volume from 0 to 100)]) ([-m (mode 0, 1 or 2)])\n",
|
|
name);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: configure_option
|
|
****************************************************************************/
|
|
|
|
static int configure_option(FAR struct app_options *option,
|
|
int argc, FAR 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;
|
|
|
|
default:
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* name: print_keyusage()
|
|
****************************************************************************/
|
|
|
|
static void print_keyusage(void)
|
|
{
|
|
int i;
|
|
|
|
printf("press any key below to make a sound.\n");
|
|
for (i = 0; i < MAX_KEYCONVERT; i++)
|
|
{
|
|
printf(" [KEY]: %c, [CODE]: %s\n",
|
|
key_convert[i].key_str,
|
|
key_convert[i].dispstr);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
/****************************************************************************
|
|
* 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;
|
|
int key_idx;
|
|
|
|
if (configure_option(&appopt, argc, argv) != OK)
|
|
{
|
|
print_help(argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
ret = init_nxaudio(&g_kbd.nxaudio, APP_FS, APP_BPS, APP_CHNUM);
|
|
if (ret < 0)
|
|
{
|
|
printf("init_nxaoud() returned with error!!\n");
|
|
return -1;
|
|
}
|
|
|
|
nxaudio_setvolume(&g_kbd.nxaudio, appopt.volume);
|
|
|
|
ret = init_keyboard_sound(&g_kbd, APP_FS, appopt.mode);
|
|
if (ret != OK)
|
|
{
|
|
fin_nxaudio(&g_kbd.nxaudio);
|
|
printf("init_keyboard_sound() error!!\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Render audio samples in audio buffers */
|
|
|
|
for (i = 0; i < g_kbd.nxaudio.abufnum; i++)
|
|
{
|
|
app_dequeue_cb((unsigned long)&g_kbd,
|
|
g_kbd.nxaudio.abufs[i]);
|
|
}
|
|
|
|
pid = create_audio_thread(&g_kbd);
|
|
|
|
printf("Start %s\n", argv[0]);
|
|
print_keyusage();
|
|
|
|
while (running)
|
|
{
|
|
key = getchar();
|
|
if (key != EOF)
|
|
{
|
|
switch (key)
|
|
{
|
|
case 'q':
|
|
running = false;
|
|
break;
|
|
|
|
default:
|
|
key_idx = convert_key2idx(key);
|
|
if (key_idx >= 0)
|
|
{
|
|
g_kbd.request_scale = key_convert[key_idx].key;
|
|
printf("%s \n", key_convert[key_idx].dispstr);
|
|
fflush(stdout);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
board_external_amp_mute_control(true);
|
|
|
|
nxaudio_stop(&g_kbd.nxaudio);
|
|
pthread_join(pid, NULL);
|
|
|
|
fin_keyboard(&g_kbd);
|
|
|
|
return ret;
|
|
}
|