mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
examples/fmsynth: Add examples for FM synthesizer lib
Add examples to show how to use fmsynth library. There are 2 samples. One is a music keyboard, and the other is music player decording MML.
This commit is contained in:
parent
80eb94da8a
commit
4d86c69a22
10 changed files with 1565 additions and 0 deletions
42
examples/fmsynth/Kconfig
Normal file
42
examples/fmsynth/Kconfig
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config EXAMPLES_FMSYNTH
|
||||
tristate "FM Synthesizer examples"
|
||||
default n
|
||||
---help---
|
||||
Examples for fmsynth library.
|
||||
|
||||
if EXAMPLES_FMSYNTH
|
||||
|
||||
config EXAMPLES_FMSYNTH_KEYBOARD_PROGNAME
|
||||
string "Simple music keyboard Program name"
|
||||
default "keyboard"
|
||||
---help---
|
||||
Command name of this "Simple music keyboard".
|
||||
|
||||
config EXAMPLES_FMSYNTH_KEYBOARD_PRIORITY
|
||||
int "Simple music keyboard task priority"
|
||||
default 100
|
||||
|
||||
config EXAMPLES_FMSYNTH_KEYBOARD_STACKSIZE
|
||||
int "Simple music keyboard stack size"
|
||||
default 2048
|
||||
|
||||
config EXAMPLES_FMSYNTH_MMLPLAYER_PROGNAME
|
||||
string "MML Player Program name"
|
||||
default "mmlplayer"
|
||||
---help---
|
||||
Command name of this "MML Player".
|
||||
|
||||
config EXAMPLES_FMSYNTH_MMLPLAYER_PRIORITY
|
||||
int "MML Player task priority"
|
||||
default 100
|
||||
|
||||
config EXAMPLES_FMSYNTH_MMLPLAYER_STACKSIZE
|
||||
int "MML Player stack size"
|
||||
default 2048
|
||||
|
||||
endif
|
||||
23
examples/fmsynth/Make.defs
Normal file
23
examples/fmsynth/Make.defs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
############################################################################
|
||||
# apps/examples/fmsynth/Make.defs
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_EXAMPLES_FMSYNTH),)
|
||||
CONFIGURED_APPS += $(APPDIR)/examples/fmsynth
|
||||
endif
|
||||
44
examples/fmsynth/Makefile
Normal file
44
examples/fmsynth/Makefile
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
############################################################################
|
||||
# apps/examples/fmsynth/Makefile
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# For fmsynth utilities
|
||||
|
||||
ASRCS =
|
||||
CSRCS = music_scale.c operator_algorithm.c
|
||||
|
||||
# For fmsynth_keyboard
|
||||
|
||||
PROGNAME = $(CONFIG_EXAMPLES_FMSYNTH_KEYBOARD_PROGNAME)
|
||||
PRIORITY = $(CONFIG_EXAMPLES_FMSYNTH_KEYBOARD_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_EXAMPLES_FMSYNTH_KEYBOARD_STACKSIZE)
|
||||
MAINSRC = keyboard_main.c
|
||||
|
||||
# For fmsynth_mmlplayer
|
||||
|
||||
PROGNAME += $(CONFIG_EXAMPLES_FMSYNTH_MMLPLAYER_PROGNAME)
|
||||
PRIORITY += $(CONFIG_EXAMPLES_FMSYNTH_MMLPLAYER_PRIORITY)
|
||||
STACKSIZE += $(CONFIG_EXAMPLES_FMSYNTH_MMLPLAYER_STACKSIZE)
|
||||
MAINSRC += mmlplayer_main.c
|
||||
|
||||
MODULE = $(CONFIG_EXAMPLES_FMSYNTH)
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
449
examples/fmsynth/keyboard_main.c
Normal file
449
examples/fmsynth/keyboard_main.c
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
/****************************************************************************
|
||||
* 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;
|
||||
char 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 = (char)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;
|
||||
}
|
||||
563
examples/fmsynth/mmlplayer_main.c
Normal file
563
examples/fmsynth/mmlplayer_main.c
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
/****************************************************************************
|
||||
* 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 <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 <audioutils/mml_parser.h>
|
||||
|
||||
#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;
|
||||
char 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 = (char)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;
|
||||
}
|
||||
58
examples/fmsynth/mmlplayer_score.h
Normal file
58
examples/fmsynth/mmlplayer_score.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/fmsynth/mmlplayer_score.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
|
||||
#define __APPS_EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
|
||||
|
||||
static const char *floh_walzer_right =
|
||||
"T120 L4 O4"
|
||||
"R8 {D#C#}8"
|
||||
"R8{[<A#>F#][<A#>F#]}{D#C#}8 R8{[<A#>F#][<A#>F#]}{D#C#}8"
|
||||
"R8[<A#>F#]8R8[<A#>F#]8 R8{[<B>F][<B>F]} {D#C#}8"
|
||||
"R8{[<B>F][<B>F]}{D#C#}8 R8{[<B>F][<B>F]}{D#C#}8 "
|
||||
"R8[<B>F]8R8[<B>F]8 R8{[<A#>F#][<A#>F#]} {D#C#}8"
|
||||
"R8{[<A#>F#][<A#>F#]}{D#C#}8 R8{[<A#>F#][<A#>F#]}{D#C#}8"
|
||||
"R8[<A#>F#]8R8[<A#>F#]8 R8{[<B>F][<B>F]} {D#C#}8"
|
||||
"R8{[<B>F][<B>F]}{D#C#}8 R8{[<B>F][<B>F]}{D#C#}8 "
|
||||
"R8[<B>F]8R8[<B>F]8 R8{[<A#>F#][<A#>F#]} {D#C#}8"
|
||||
"R8[<A#>F#]8R8[<A#>F#]8 R8[<A#>F#]8R8[<A#>F#]8 "
|
||||
"R2 R8{[<B>F][<B>F]} {D#C#}8"
|
||||
"R8[<B>F]8R8[<B>F]8 R8[<B>F]8R8[<B>F]8 "
|
||||
"R2 R8{[<A#>F#][<A#>F#]} {D#C#}8"
|
||||
"R8{[<A#>F#][<A#>F#]}{D#C#}8 R8{[<A#>F#][<A#>F#]}{D#C#}8"
|
||||
"R8[<A#>F#]8R8[<A#>F#]8 R8{[<B>F][<B>F]} {D#C#}8"
|
||||
"R8{[<B>F][<B>F]}{D#C#}8 R8{[<B>F][<B>F]}{D#C#}8 "
|
||||
"R8[<B>F]8R8[<B>F]8 R8{[<A#>F#][<A#>F#]} {D#C#}8"
|
||||
"[<A#>F#]8{CC}8{C#C} R8[<B>F]8[<A#>F#]8R8";
|
||||
|
||||
static const char *floh_walzer_left =
|
||||
"T120 L4 O3"
|
||||
"R4"
|
||||
"F#.R8 F#.R8 F#D# C#.R8"
|
||||
"C#.R8 C#.R8 C#D# F#.R8"
|
||||
">A#.R8 A#.R8 A#>C# D#.R8"
|
||||
"D#.R8 D#.R8 D#C# <A#.R8"
|
||||
"<F#C# F#C# {F#F}{F#G} G#R"
|
||||
"G#C# G#C# {G#G}{G#A} A#R"
|
||||
"F#.R8 F#.R8 F#D# C#.R8"
|
||||
"C#.R8 C#.R8 C#D# F#.R8"
|
||||
"C#8R8R R8C#8<F#8R8";
|
||||
|
||||
#endif /* __APPS_EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H */
|
||||
97
examples/fmsynth/music_scale.c
Normal file
97
examples/fmsynth/music_scale.c
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/fmsynth/music_scale.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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Musical Scale frequency
|
||||
* Negative value means not supported.
|
||||
*/
|
||||
|
||||
const float musical_scale[] =
|
||||
{
|
||||
/* Octave 0 */
|
||||
|
||||
-1.f, -1.f, -1.f,
|
||||
-1.f, -1.f, -1.f,
|
||||
-1.f, -1.f, -1.f,
|
||||
27.5f, 29.13523509f, 30.86770631f,
|
||||
|
||||
/* Octave 1 */
|
||||
|
||||
32.70319563f, 34.64782883f, 36.70809593f,
|
||||
38.89087289f, 41.20344452f, 43.65352881f,
|
||||
46.2493027f, 48.99942933f, 51.913087f,
|
||||
55.f, 58.27047017f, 61.73541262f,
|
||||
|
||||
/* Octave 2 */
|
||||
|
||||
65.40639126f, 69.29565765f, 73.41619185f,
|
||||
77.78174577f, 82.40688903f, 87.30705762f,
|
||||
92.4986054f, 97.99885866f, 103.826174f,
|
||||
110.f, 116.5409403f, 123.4708252f,
|
||||
|
||||
/* Octave 3 */
|
||||
|
||||
130.8127825f, 138.5913153f, 146.8323837f,
|
||||
155.5634915f, 164.8137781f, 174.6141152f,
|
||||
184.9972108f, 195.9977173f, 207.652348f,
|
||||
220.f, 233.0818807f, 246.9416505f,
|
||||
|
||||
/* Octave 4 */
|
||||
|
||||
261.625565f, 277.1826306f, 293.6647674f,
|
||||
311.1269831f, 329.6275561f, 349.2282305f,
|
||||
369.9944216f, 391.9954347f, 415.304696f,
|
||||
440.f, 466.1637614f, 493.8833009f,
|
||||
|
||||
/* Octave 5 */
|
||||
|
||||
523.2511301f, 554.3652612f, 587.3295348f,
|
||||
622.2539662f, 659.2551123f, 698.456461f,
|
||||
739.9888432f, 783.9908693f, 830.6093921f,
|
||||
880.f, 932.3275227f, 987.7666018f,
|
||||
|
||||
/* Octave 6 */
|
||||
|
||||
1046.50226f, 1108.730522f, 1174.65907f,
|
||||
1244.507932f, 1318.510225f, 1396.912922f,
|
||||
1479.977686f, 1567.981739f, 1661.218784f,
|
||||
1760.f, 1864.655045f, 1975.533204f,
|
||||
|
||||
/* Octave 7 */
|
||||
|
||||
2093.00452f, 2217.461045f, 2349.318139f,
|
||||
2489.015865f, 2637.020449f, 2793.825844f,
|
||||
2959.955373f, 3135.963477f, 3322.437568f,
|
||||
3520.f, 3729.310091f, 3951.066407f,
|
||||
|
||||
/* Octave 8 */
|
||||
|
||||
4186.009041f, -1.f, -1.f,
|
||||
-1.f, -1.f, -1.f,
|
||||
-1.f, -1.f, -1.f,
|
||||
-1.f, -1.f, -1.f,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
62
examples/fmsynth/music_scale.h
Normal file
62
examples/fmsynth/music_scale.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/fmsynth/music_scale.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H
|
||||
#define __APPS_EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor definisions
|
||||
****************************************************************************/
|
||||
|
||||
#define MUSIC_SCALE_C (0)
|
||||
#define MUSIC_SCALE_CS (1)
|
||||
#define MUSIC_SCALE_D (2)
|
||||
#define MUSIC_SCALE_DS (3)
|
||||
#define MUSIC_SCALE_E (4)
|
||||
#define MUSIC_SCALE_F (5)
|
||||
#define MUSIC_SCALE_FS (6)
|
||||
#define MUSIC_SCALE_G (7)
|
||||
#define MUSIC_SCALE_GS (8)
|
||||
#define MUSIC_SCALE_A (9)
|
||||
#define MUSIC_SCALE_AS (10)
|
||||
#define MUSIC_SCALE_B (11)
|
||||
#define OCTAVE(n, s) ((s) + ((n) * 12))
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
EXTERN const float musical_scale[];
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __APPS_EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H */
|
||||
188
examples/fmsynth/operator_algorithm.c
Normal file
188
examples/fmsynth/operator_algorithm.c
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/fmsynth/operator_algorithm.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 <stddef.h>
|
||||
|
||||
#include <audioutils/fmsynth.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* name: fmsynthutil_algorithm0
|
||||
****************************************************************************/
|
||||
|
||||
FAR fmsynth_op_t *fmsynthutil_algorithm0(void)
|
||||
{
|
||||
/* [Simple sin operator]
|
||||
*
|
||||
* +--------------+
|
||||
* | OP (carrier) | ----> Audio out
|
||||
* +--------------+
|
||||
*/
|
||||
|
||||
FAR fmsynth_op_t *carrier;
|
||||
fmsynth_eglevels_t level;
|
||||
|
||||
/* Attack level and period time : 1.0, 40ms
|
||||
* Decay Break level and period time : 0.3, 200ms
|
||||
* Decay level and period time : 0.1, 100ms
|
||||
* Sustain level and period time : 0.1, 100ms
|
||||
* Release level : 0.0, 0ms
|
||||
*
|
||||
*/
|
||||
|
||||
level.attack.level = 1.0f;
|
||||
level.attack.period_ms = 40;
|
||||
level.decaybrk.level = 0.3f;
|
||||
level.decaybrk.period_ms = 200;
|
||||
level.decay.level = 0.1f;
|
||||
level.decay.period_ms = 100;
|
||||
level.sustain.level = 0.1f;
|
||||
level.sustain.period_ms = 100;
|
||||
level.release.level = 0.f;
|
||||
level.release.period_ms = 0;
|
||||
|
||||
carrier = fmsynthop_create();
|
||||
if (carrier)
|
||||
{
|
||||
fmsynthop_set_envelope(carrier, &level);
|
||||
fmsynthop_select_opfunc(carrier, FMSYNTH_OPFUNC_SIN);
|
||||
}
|
||||
|
||||
return carrier;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* name: fmsynthutil_algorithm1
|
||||
****************************************************************************/
|
||||
|
||||
FAR fmsynth_op_t *fmsynthutil_algorithm1(void)
|
||||
{
|
||||
/* feed back
|
||||
* +--------------------+
|
||||
* | |
|
||||
* | +--------------+ |
|
||||
* +->| OP (carrier) | -+--> Audio out
|
||||
* +--------------+
|
||||
*/
|
||||
|
||||
FAR fmsynth_op_t *carrier;
|
||||
fmsynth_eglevels_t level;
|
||||
|
||||
level.attack.level = 1.0f;
|
||||
level.attack.period_ms = 40;
|
||||
level.decaybrk.level = 0.3f;
|
||||
level.decaybrk.period_ms = 200;
|
||||
level.decay.level = 0.1f;
|
||||
level.decay.period_ms = 100;
|
||||
level.sustain.level = 0.1f;
|
||||
level.sustain.period_ms = 100;
|
||||
level.release.level = 0.f;
|
||||
level.release.period_ms = 0;
|
||||
|
||||
carrier = fmsynthop_create();
|
||||
if (carrier)
|
||||
{
|
||||
fmsynthop_set_envelope(carrier, &level);
|
||||
fmsynthop_select_opfunc(carrier, FMSYNTH_OPFUNC_SIN);
|
||||
fmsynthop_bind_feedback(carrier, carrier, 0.6f);
|
||||
}
|
||||
|
||||
return carrier;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* name: fmsynthutil_algorithm2
|
||||
****************************************************************************/
|
||||
|
||||
FAR fmsynth_op_t *fmsynthutil_algorithm2(void)
|
||||
{
|
||||
/* feed back
|
||||
* +--------------------+
|
||||
* | |
|
||||
* | +--------------+ | +--------------+
|
||||
* +->| OP (subop) | -+-> | OP (carrier) | ----> Audio out
|
||||
* +--------------+ +--------------+
|
||||
*/
|
||||
|
||||
FAR fmsynth_op_t *carrier;
|
||||
FAR fmsynth_op_t *subop;
|
||||
fmsynth_eglevels_t level;
|
||||
|
||||
level.attack.level = 1.0f;
|
||||
level.attack.period_ms = 40;
|
||||
level.decaybrk.level = 0.3f;
|
||||
level.decaybrk.period_ms = 200;
|
||||
level.decay.level = 0.1f;
|
||||
level.decay.period_ms = 100;
|
||||
level.sustain.level = 0.f;
|
||||
level.sustain.period_ms = 0;
|
||||
level.release.level = 0.f;
|
||||
level.release.period_ms = 0;
|
||||
|
||||
carrier = fmsynthop_create();
|
||||
if (carrier)
|
||||
{
|
||||
subop = fmsynthop_create();
|
||||
if (!subop)
|
||||
{
|
||||
fmsynthop_delete(carrier);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fmsynthop_set_envelope(carrier, &level);
|
||||
fmsynthop_select_opfunc(carrier, FMSYNTH_OPFUNC_SIN);
|
||||
|
||||
fmsynthop_set_soundfreqrate(subop, 3.7f);
|
||||
fmsynthop_select_opfunc(subop, FMSYNTH_OPFUNC_SIN);
|
||||
|
||||
fmsynthop_cascade_subop(carrier, subop);
|
||||
}
|
||||
|
||||
return carrier;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* name: fmsynthutil_delete_ops
|
||||
****************************************************************************/
|
||||
|
||||
void FAR fmsynthutil_delete_ops(FAR fmsynth_op_t *op)
|
||||
{
|
||||
FAR fmsynth_op_t *tmp;
|
||||
|
||||
while (op != NULL)
|
||||
{
|
||||
tmp = op->parallelop;
|
||||
|
||||
if (op->cascadeop)
|
||||
{
|
||||
fmsynthutil_delete_ops(op->cascadeop);
|
||||
}
|
||||
|
||||
fmsynthop_delete(op);
|
||||
op = tmp;
|
||||
}
|
||||
}
|
||||
39
examples/fmsynth/operator_algorithm.h
Normal file
39
examples/fmsynth/operator_algorithm.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/fmsynth/operator_algorithm.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H
|
||||
#define __APPS_EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <audioutils/fmsynth.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
FAR fmsynth_op_t *fmsynthutil_algorithm0(void);
|
||||
FAR fmsynth_op_t *fmsynthutil_algorithm1(void);
|
||||
FAR fmsynth_op_t *fmsynthutil_algorithm2(void);
|
||||
void FAR fmsynthutil_delete_ops(FAR fmsynth_op_t *op);
|
||||
|
||||
#endif /* __APPS_EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue