You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ma...@apache.org on 2022/08/25 11:30:03 UTC

[incubator-nuttx-apps] 03/03: examples/fmsynth: Add examples for FM synthesizer lib

This is an automated email from the ASF dual-hosted git repository.

masayuki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git

commit 4d86c69a22092e803340f4c22c1a5dee4c592843
Author: Takayoshi Koizumi <ta...@gmail.com>
AuthorDate: Tue Aug 16 09:03:39 2022 +0000

    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.
---
 examples/fmsynth/Kconfig              |  42 +++
 examples/fmsynth/Make.defs            |  23 ++
 examples/fmsynth/Makefile             |  44 +++
 examples/fmsynth/keyboard_main.c      | 449 +++++++++++++++++++++++++++
 examples/fmsynth/mmlplayer_main.c     | 563 ++++++++++++++++++++++++++++++++++
 examples/fmsynth/mmlplayer_score.h    |  58 ++++
 examples/fmsynth/music_scale.c        |  97 ++++++
 examples/fmsynth/music_scale.h        |  62 ++++
 examples/fmsynth/operator_algorithm.c | 188 ++++++++++++
 examples/fmsynth/operator_algorithm.h |  39 +++
 10 files changed, 1565 insertions(+)

diff --git a/examples/fmsynth/Kconfig b/examples/fmsynth/Kconfig
new file mode 100644
index 000000000..6038fb033
--- /dev/null
+++ b/examples/fmsynth/Kconfig
@@ -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
diff --git a/examples/fmsynth/Make.defs b/examples/fmsynth/Make.defs
new file mode 100644
index 000000000..25be117b1
--- /dev/null
+++ b/examples/fmsynth/Make.defs
@@ -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
diff --git a/examples/fmsynth/Makefile b/examples/fmsynth/Makefile
new file mode 100644
index 000000000..d89a7df17
--- /dev/null
+++ b/examples/fmsynth/Makefile
@@ -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
diff --git a/examples/fmsynth/keyboard_main.c b/examples/fmsynth/keyboard_main.c
new file mode 100644
index 000000000..d3f0c9bc4
--- /dev/null
+++ b/examples/fmsynth/keyboard_main.c
@@ -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;
+}
diff --git a/examples/fmsynth/mmlplayer_main.c b/examples/fmsynth/mmlplayer_main.c
new file mode 100644
index 000000000..edab3cb9a
--- /dev/null
+++ b/examples/fmsynth/mmlplayer_main.c
@@ -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;
+}
diff --git a/examples/fmsynth/mmlplayer_score.h b/examples/fmsynth/mmlplayer_score.h
new file mode 100644
index 000000000..f9e757846
--- /dev/null
+++ b/examples/fmsynth/mmlplayer_score.h
@@ -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 */
diff --git a/examples/fmsynth/music_scale.c b/examples/fmsynth/music_scale.c
new file mode 100644
index 000000000..7ec2e7709
--- /dev/null
+++ b/examples/fmsynth/music_scale.c
@@ -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
+ ****************************************************************************/
diff --git a/examples/fmsynth/music_scale.h b/examples/fmsynth/music_scale.h
new file mode 100644
index 000000000..577564a3c
--- /dev/null
+++ b/examples/fmsynth/music_scale.h
@@ -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 */
diff --git a/examples/fmsynth/operator_algorithm.c b/examples/fmsynth/operator_algorithm.c
new file mode 100644
index 000000000..2d6b6068e
--- /dev/null
+++ b/examples/fmsynth/operator_algorithm.c
@@ -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;
+    }
+}
diff --git a/examples/fmsynth/operator_algorithm.h b/examples/fmsynth/operator_algorithm.h
new file mode 100644
index 000000000..94594d027
--- /dev/null
+++ b/examples/fmsynth/operator_algorithm.h
@@ -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 */