You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2022/08/16 12:30:19 UTC

[GitHub] [incubator-nuttx-apps] takayoshi-k opened a new pull request, #1283: Add audiolib fmsynthesizer

takayoshi-k opened a new pull request, #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283

   ## Summary
   Add FM synthesizer library as one of audio utility libraries and an example using it.
   
   ## Impact
   Just add a new additonal library and an example.
   
   ## Testing
   Test if keyboard and mmlplayer examples works well on sprsense board.
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] pkarashchenko commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
pkarashchenko commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r952780268


##########
examples/fmsynth/music_scale.h:
##########
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * 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[];
+
+#define MAX_SCALE  (sizeof(musical_scale) / sizeof(musical_scale[0]))

Review Comment:
   Since the number of elements of `musical_scale` is not defined in the header file the other files that will use this macro will not be able to determine array size at compilation time.
   I'm not sure what will be the result of using this macro outside the C file that defines `musical_sale`. I think if there will be no error, then the macro will be evaluated to 1 always.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#issuecomment-1227031408

   > Few minor comments, but nothing that blocks from merging and can be fixed in follow-up PR
   
   Thank you.
   I will remain them. And will be fix next time.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] masayuki2009 commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
masayuki2009 commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r946769362


##########
audioutils/fmsynth/Makefile:
##########
@@ -0,0 +1,27 @@
+############################################################################
+# apps/audioutils/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
+
+# NSH Library

Review Comment:
   NSH Library??
   



##########
audioutils/nxaudio/Makefile:
##########
@@ -0,0 +1,27 @@
+############################################################################
+# apps/audioutils/nxaudio/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
+
+# NSH Library

Review Comment:
   NSH Library??
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r946801838


##########
audioutils/fmsynth/Makefile:
##########
@@ -0,0 +1,27 @@
+############################################################################
+# apps/audioutils/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
+
+# NSH Library

Review Comment:
   Removed.



##########
audioutils/nxaudio/Makefile:
##########
@@ -0,0 +1,27 @@
+############################################################################
+# apps/audioutils/nxaudio/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
+
+# NSH Library

Review Comment:
   Removed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] pkarashchenko commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
pkarashchenko commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r947534850


##########
include/audioutils/nxaudio.h:
##########
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * apps/include/audioutils/nxaudio.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_INCLUDE_AUDIOUTILS_NXAUDIO_H
+#define __APPS_INCLUDE_AUDIOUTILS_NXAUDIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <mqueue.h>
+#include <nuttx/audio/audio.h>
+
+/****************************************************************************
+ * Public Data Types
+ ****************************************************************************/
+
+struct nxaudio_s
+{
+  int fd;
+
+  int abufnum;
+  struct ap_buffer_s **abufs;
+  mqd_t mq;
+
+  int chnum;
+};
+
+struct nxaudio_callbacks_s
+{
+  void (*dequeue)(unsigned long arg, FAR struct ap_buffer_s *apb);
+  void (*complete)(unsigned long arg);
+  void (*user)(unsigned long arg, FAR struct audio_msg_s *msg,
+                                              FAR bool *running);
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum);
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio);
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb);
+int nxaudio_setvolume(FAR struct nxaudio_s *nxaudio, uint16_t vol);
+int nxaudio_start(FAR struct nxaudio_s *nxaudio);
+int nxaudio_msgloop(FAR struct nxaudio_s *nxaudio,
+                            FAR struct nxaudio_callbacks_s *cbs,
+                            unsigned long arg);

Review Comment:
   ```suggestion
   int nxaudio_msgloop(FAR struct nxaudio_s *nxaudio,
                       FAR struct nxaudio_callbacks_s *cbs,
                       unsigned long arg);
   ```



##########
include/audioutils/nxaudio.h:
##########
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * apps/include/audioutils/nxaudio.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_INCLUDE_AUDIOUTILS_NXAUDIO_H
+#define __APPS_INCLUDE_AUDIOUTILS_NXAUDIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <mqueue.h>
+#include <nuttx/audio/audio.h>
+
+/****************************************************************************
+ * Public Data Types
+ ****************************************************************************/
+
+struct nxaudio_s
+{
+  int fd;
+
+  int abufnum;
+  struct ap_buffer_s **abufs;
+  mqd_t mq;
+
+  int chnum;
+};
+
+struct nxaudio_callbacks_s
+{
+  void (*dequeue)(unsigned long arg, FAR struct ap_buffer_s *apb);
+  void (*complete)(unsigned long arg);
+  void (*user)(unsigned long arg, FAR struct audio_msg_s *msg,
+                                              FAR bool *running);
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum);
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio);
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb);

Review Comment:
   ```suggestion
   int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
                         FAR struct ap_buffer_s *apb);
   ```



##########
include/audioutils/nxaudio.h:
##########
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * apps/include/audioutils/nxaudio.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_INCLUDE_AUDIOUTILS_NXAUDIO_H
+#define __APPS_INCLUDE_AUDIOUTILS_NXAUDIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <mqueue.h>
+#include <nuttx/audio/audio.h>
+
+/****************************************************************************
+ * Public Data Types
+ ****************************************************************************/
+
+struct nxaudio_s
+{
+  int fd;
+
+  int abufnum;
+  struct ap_buffer_s **abufs;
+  mqd_t mq;
+
+  int chnum;
+};
+
+struct nxaudio_callbacks_s
+{
+  void (*dequeue)(unsigned long arg, FAR struct ap_buffer_s *apb);
+  void (*complete)(unsigned long arg);
+  void (*user)(unsigned long arg, FAR struct audio_msg_s *msg,
+                                              FAR bool *running);

Review Comment:
   ```suggestion
     void CODE (*dequeue)(unsigned long arg, FAR struct ap_buffer_s *apb);
     void CODE (*complete)(unsigned long arg);
     void CODE (*user)(unsigned long arg, FAR struct audio_msg_s *msg,
                       FAR bool *running);
   ```



##########
include/audioutils/nxaudio.h:
##########
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * apps/include/audioutils/nxaudio.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_INCLUDE_AUDIOUTILS_NXAUDIO_H
+#define __APPS_INCLUDE_AUDIOUTILS_NXAUDIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <mqueue.h>
+#include <nuttx/audio/audio.h>
+
+/****************************************************************************
+ * Public Data Types
+ ****************************************************************************/
+
+struct nxaudio_s
+{
+  int fd;
+
+  int abufnum;
+  struct ap_buffer_s **abufs;
+  mqd_t mq;
+
+  int chnum;
+};
+
+struct nxaudio_callbacks_s
+{
+  void (*dequeue)(unsigned long arg, FAR struct ap_buffer_s *apb);
+  void (*complete)(unsigned long arg);
+  void (*user)(unsigned long arg, FAR struct audio_msg_s *msg,
+                                              FAR bool *running);
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum);

Review Comment:
   ```suggestion
   int init_nxaudio(FAR struct nxaudio_s *nxaudio,
                    int fs, int bps, int chnum);
   ```



##########
include/audioutils/nxaudio.h:
##########
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * apps/include/audioutils/nxaudio.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_INCLUDE_AUDIOUTILS_NXAUDIO_H
+#define __APPS_INCLUDE_AUDIOUTILS_NXAUDIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <mqueue.h>
+#include <nuttx/audio/audio.h>
+
+/****************************************************************************
+ * Public Data Types
+ ****************************************************************************/
+
+struct nxaudio_s
+{
+  int fd;
+
+  int abufnum;
+  struct ap_buffer_s **abufs;

Review Comment:
   ```suggestion
     FAR struct ap_buffer_s **abufs;
   ```



##########
include/audioutils/fmsynth.h:
##########
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * apps/include/audioutils/fmsynth.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 __INCLUDE_AUDIOUTILS_FMSYNTH_H
+#define __INCLUDE_AUDIOUTILS_FMSYNTH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <limits.h>
+#include <stdint.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FMSYNTH_MAX_VOLUME (SHRT_MAX)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef struct fmsynth_sound_s
+{
+  int phase_time;
+  int max_phase_time;
+  int volume;
+  fmsynth_op_t *operators;
+
+  struct fmsynth_sound_s *next_sound;

Review Comment:
   ```suggestion
     FAR struct fmsynth_sound_s *next_sound;
   ```



##########
examples/fmsynth/music_scale.h:
##########
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * 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 __EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H
+#define __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
+ ****************************************************************************/
+
+extern const float musical_scale[];
+
+#define MAX_SCALE  (sizeof(musical_scale) / sizeof(musical_scale[0]))
+
+#endif /* __EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H */

Review Comment:
   ```suggestion
   #endif /* __APPS_EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H */
   ```



##########
include/audioutils/fmsynth.h:
##########
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * apps/include/audioutils/fmsynth.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 __INCLUDE_AUDIOUTILS_FMSYNTH_H
+#define __INCLUDE_AUDIOUTILS_FMSYNTH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <limits.h>
+#include <stdint.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FMSYNTH_MAX_VOLUME (SHRT_MAX)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef struct fmsynth_sound_s
+{
+  int phase_time;
+  int max_phase_time;
+  int volume;
+  fmsynth_op_t *operators;

Review Comment:
   ```suggestion
     FAR fmsynth_op_t *operators;
   ```



##########
examples/fmsynth/music_scale.h:
##########
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * 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 __EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H
+#define __EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H

Review Comment:
   ```suggestion
   #ifndef __APPS_EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H
   #define __APPS_EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H
   ```



##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H

Review Comment:
   ```suggestion
   #ifndef __APPS_EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
   #define __APPS_EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
   ```



##########
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 __EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H
+#define __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  /* __EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H */

Review Comment:
   ```suggestion
   #endif  /* __APPS_EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H */
   ```



##########
examples/fmsynth/music_scale.h:
##########
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * 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 __EXAMPLES_FMSYNTH_UTILS_MUSIC_SCALE_H
+#define __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
+ ****************************************************************************/
+
+extern const float musical_scale[];

Review Comment:
   ```suggestion
   EXTERN const float musical_scale[];
   ```
   Please add
   ```
   #undef EXTERN
   #if defined(__cplusplus)
   #define EXTERN extern "C"
   extern "C"
   {
   #else
   #define EXTERN extern
   #endif
   ...
   #undef EXTERN
   #if defined(__cplusplus)
   }
   #endif
   ```
   to headers



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  const char *dispstr;

Review Comment:
   ```suggestion
     FAR const char *dispstr;
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;

Review Comment:
   ```suggestion
     FAR fmsynth_sound_t  *sound;
     FAR fmsynth_op_t *carrier;
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  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 *)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 = (struct kbd_s *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+
+  if (kbd->request_scale != -1)
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (int16_t *)apb->samp,
+                                      apb->nmaxbytes / sizeof(int16_t),
+                                      kbd->nxaudio.chnum,
+                                      tick_callback, (unsigned long)kbd);
+    }
+  else
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct kbd_s *kbd = (struct kbd_s *)arg;

Review Comment:
   ```suggestion
     FAR struct kbd_s *kbd = (FAR struct kbd_s *)arg;
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  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 *)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 = (struct kbd_s *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+
+  if (kbd->request_scale != -1)
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (int16_t *)apb->samp,
+                                      apb->nmaxbytes / sizeof(int16_t),
+                                      kbd->nxaudio.chnum,
+                                      tick_callback, (unsigned long)kbd);
+    }
+  else
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct kbd_s *kbd = (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, 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;

Review Comment:
   ```suggestion
             default:
               return ERROR;
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  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 *)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 = (struct kbd_s *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+
+  if (kbd->request_scale != -1)
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (int16_t *)apb->samp,
+                                      apb->nmaxbytes / sizeof(int16_t),
+                                      kbd->nxaudio.chnum,
+                                      tick_callback, (unsigned long)kbd);
+    }
+  else
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (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 void *audio_loop_thread(pthread_addr_t arg)

Review Comment:
   ```suggestion
   static FAR void *audio_loop_thread(pthread_addr_t arg)
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  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 *)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 = (struct kbd_s *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+
+  if (kbd->request_scale != -1)
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (int16_t *)apb->samp,
+                                      apb->nmaxbytes / sizeof(int16_t),
+                                      kbd->nxaudio.chnum,
+                                      tick_callback, (unsigned long)kbd);
+    }
+  else
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (int16_t *)apb->samp,

Review Comment:
   ```suggestion
                                         (FAR int16_t *)apb->samp,
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  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 *)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 = (struct kbd_s *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+
+  if (kbd->request_scale != -1)
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (int16_t *)apb->samp,
+                                      apb->nmaxbytes / sizeof(int16_t),
+                                      kbd->nxaudio.chnum,
+                                      tick_callback, (unsigned long)kbd);
+    }
+  else
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct kbd_s *kbd = (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, char **argv)

Review Comment:
   ```suggestion
   static int configure_option(FAR struct app_options *option,
                               int argc, FAR char **argv)
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  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 *)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 = (struct kbd_s *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+
+  if (kbd->request_scale != -1)
+    {
+      apb->nbytes = fmsynth_rendering(kbd->sound,
+                                      (int16_t *)apb->samp,

Review Comment:
   ```suggestion
                                         (FAR int16_t *)apb->samp,
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: 2 channels, 48 kFs, 16 bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->abufs = create_audio_buffers(nxaudio->fd,
+                               buf_info.nbuffers, buf_info.buffer_size);
+      nxaudio->abufnum = buf_info.nbuffers;
+
+      return 0;
+    }
+  else
+    {
+      return -1;
+    }
+}
+
+/****************************************************************************
+ * name: nxaudio_enqbuffer
+ ****************************************************************************/
+
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb)
+{
+  struct audio_buf_desc_s desc;
+
+  desc.numbytes  = apb->nbytes;

Review Comment:
   ```suggestion
     desc.numbytes = apb->nbytes;
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: 2 channels, 48 kFs, 16 bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->abufs = create_audio_buffers(nxaudio->fd,
+                               buf_info.nbuffers, buf_info.buffer_size);
+      nxaudio->abufnum = buf_info.nbuffers;
+
+      return 0;
+    }
+  else
+    {
+      return -1;
+    }
+}
+
+/****************************************************************************
+ * name: nxaudio_enqbuffer
+ ****************************************************************************/
+
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb)
+{
+  struct audio_buf_desc_s desc;
+
+  desc.numbytes  = apb->nbytes;
+  desc.u.buffer = apb;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)&desc);
+}
+
+/****************************************************************************
+ * name: nxaudio_setvolume
+ ****************************************************************************/
+
+int nxaudio_setvolume(FAR struct nxaudio_s *nxaudio, uint16_t vol)
+{
+  struct audio_caps_desc_s  cap_desc;
+
+  cap_desc.caps.ac_len            = sizeof(struct audio_caps_s);
+  cap_desc.caps.ac_type           = AUDIO_TYPE_FEATURE;
+  cap_desc.caps.ac_format.hw      = AUDIO_FU_VOLUME;
+  cap_desc.caps.ac_controls.hw[0] = vol;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);

Review Comment:
   ```suggestion
     return ioctl(nxaudio->fd, AUDIOIOC_CONFIGURE, (unsigned long)(uintptr_t)&cap_desc);
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: 2 channels, 48 kFs, 16 bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->abufs = create_audio_buffers(nxaudio->fd,
+                               buf_info.nbuffers, buf_info.buffer_size);
+      nxaudio->abufnum = buf_info.nbuffers;
+
+      return 0;
+    }
+  else
+    {
+      return -1;
+    }
+}
+
+/****************************************************************************
+ * name: nxaudio_enqbuffer
+ ****************************************************************************/
+
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb)
+{
+  struct audio_buf_desc_s desc;
+
+  desc.numbytes  = apb->nbytes;
+  desc.u.buffer = apb;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)&desc);
+}
+
+/****************************************************************************
+ * name: nxaudio_setvolume
+ ****************************************************************************/
+
+int nxaudio_setvolume(FAR struct nxaudio_s *nxaudio, uint16_t vol)
+{
+  struct audio_caps_desc_s  cap_desc;
+
+  cap_desc.caps.ac_len            = sizeof(struct audio_caps_s);
+  cap_desc.caps.ac_type           = AUDIO_TYPE_FEATURE;
+  cap_desc.caps.ac_format.hw      = AUDIO_FU_VOLUME;
+  cap_desc.caps.ac_controls.hw[0] = vol;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+}
+
+/****************************************************************************
+ * name: nxaudio_start
+ ****************************************************************************/
+
+int nxaudio_start(FAR struct nxaudio_s *nxaudio)
+{
+  return ioctl(nxaudio->fd, AUDIOIOC_START, 0);
+}
+
+/****************************************************************************
+ * name: nxaudio_start
+ ****************************************************************************/
+
+int nxaudio_stop(FAR struct nxaudio_s *nxaudio)
+{
+  struct audio_msg_s  term_msg;

Review Comment:
   ```suggestion
     struct audio_msg_s term_msg;
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: 2 channels, 48 kFs, 16 bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info);

Review Comment:
   ```suggestion
         ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)(uintptr_t)&buf_info);
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;

Review Comment:
   ```suggestion
     FAR struct ap_buffer_s **ret;
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));

Review Comment:
   ```suggestion
     ret = (FAR struct ap_buffer_s **)calloc(num, sizeof(FAR void *));
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,517 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;

Review Comment:
   Please add default case



##########
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)

Review Comment:
   ```suggestion
     while (op != NULL)
   ```



##########
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 __EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H
+#define __EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H

Review Comment:
   ```suggestion
   #ifndef __APPS_EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H
   #define __APPS_EXAMPLES_FMSYNTH_OPERATOR_ALGORITHM_H
   ```



##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+
+static const char *floh_walzer_right =

Review Comment:
   Where this is used?



##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __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 =

Review Comment:
   Where this is used?



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);

Review Comment:
   ```suggestion
     return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)(uintptr_t)&cap);
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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)

Review Comment:
   ```suggestion
   #define APP_FS        (48000)
   #define APP_BPS       (16)
   #define APP_CHNUM     (2)
   #define CARRIER_LEVEL (25.f / 100.f)
   ```
   Also maybe `25.f / 100.f` can be replaced by `.25f`?



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: 2 channels, 48 kFs, 16 bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->abufs = create_audio_buffers(nxaudio->fd,
+                               buf_info.nbuffers, buf_info.buffer_size);
+      nxaudio->abufnum = buf_info.nbuffers;
+
+      return 0;
+    }
+  else
+    {
+      return -1;
+    }
+}
+
+/****************************************************************************
+ * name: nxaudio_enqbuffer
+ ****************************************************************************/
+
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb)
+{
+  struct audio_buf_desc_s desc;
+
+  desc.numbytes  = apb->nbytes;
+  desc.u.buffer = apb;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)&desc);

Review Comment:
   ```suggestion
     return ioctl(nxaudio->fd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)(uintptr_t)&desc);
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: 2 channels, 48 kFs, 16 bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->abufs = create_audio_buffers(nxaudio->fd,
+                               buf_info.nbuffers, buf_info.buffer_size);
+      nxaudio->abufnum = buf_info.nbuffers;
+
+      return 0;
+    }
+  else
+    {
+      return -1;
+    }
+}
+
+/****************************************************************************
+ * name: nxaudio_enqbuffer
+ ****************************************************************************/
+
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb)
+{
+  struct audio_buf_desc_s desc;
+
+  desc.numbytes  = apb->nbytes;
+  desc.u.buffer = apb;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)&desc);
+}
+
+/****************************************************************************
+ * name: nxaudio_setvolume
+ ****************************************************************************/
+
+int nxaudio_setvolume(FAR struct nxaudio_s *nxaudio, uint16_t vol)
+{
+  struct audio_caps_desc_s  cap_desc;
+
+  cap_desc.caps.ac_len            = sizeof(struct audio_caps_s);
+  cap_desc.caps.ac_type           = AUDIO_TYPE_FEATURE;
+  cap_desc.caps.ac_format.hw      = AUDIO_FU_VOLUME;
+  cap_desc.caps.ac_controls.hw[0] = vol;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+}
+
+/****************************************************************************
+ * name: nxaudio_start
+ ****************************************************************************/
+
+int nxaudio_start(FAR struct nxaudio_s *nxaudio)
+{
+  return ioctl(nxaudio->fd, AUDIOIOC_START, 0);
+}
+
+/****************************************************************************
+ * name: nxaudio_start
+ ****************************************************************************/
+
+int nxaudio_stop(FAR struct nxaudio_s *nxaudio)
+{
+  struct audio_msg_s  term_msg;
+
+  term_msg.msg_id = AUDIO_MSG_STOP;
+  term_msg.u.data = 0;
+  mq_send(nxaudio->mq, (FAR const char *)&term_msg, sizeof(term_msg), 0);
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: nxaudio_msgloop
+ ****************************************************************************/
+
+int nxaudio_msgloop(FAR struct nxaudio_s *nxaudio,
+                            FAR struct nxaudio_callbacks_s *cbs,
+                            unsigned long arg)

Review Comment:
   ```suggestion
   int nxaudio_msgloop(FAR struct nxaudio_s *nxaudio,
                       FAR struct nxaudio_callbacks_s *cbs,
                       unsigned long arg)
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);

Review Comment:
   ```suggestion
         ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)(uintptr_t)&desc);
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);

Review Comment:
   ```suggestion
             ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
                   (unsigned long)(uintptr_t)&desc);
   ```



##########
examples/fmsynth/keyboard_main.c:
##########
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * 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;
+
+  fmsynth_sound_t  *sound;
+  fmsynth_op_t *carrier;
+
+  volatile int request_scale;
+};
+
+struct key_convert_s
+{
+  int key;
+  char key_str;
+  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 *)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 = (struct kbd_s *)arg;

Review Comment:
   ```suggestion
     FAR struct kbd_s *kbd = (FAR struct kbd_s *)arg;
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: 2 channels, 48 kFs, 16 bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->abufs = create_audio_buffers(nxaudio->fd,
+                               buf_info.nbuffers, buf_info.buffer_size);
+      nxaudio->abufnum = buf_info.nbuffers;
+
+      return 0;
+    }
+  else
+    {
+      return -1;
+    }
+}
+
+/****************************************************************************
+ * name: nxaudio_enqbuffer
+ ****************************************************************************/
+
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                              FAR struct ap_buffer_s *apb)

Review Comment:
   ```suggestion
   int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
                         FAR struct ap_buffer_s *apb)
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+#define AUDIO_DEVICE_PATH "/dev/audio/pcm1"
+#define FMMUSIC_NXAUDIO_MQ "/tmp/fmaudio_mq"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  struct ap_buffer_s **ret;
+
+  ret = (struct ap_buffer_s **)calloc(num, sizeof(void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                         int fs, int bps, int chnum)

Review Comment:
   ```suggestion
   int init_nxaudio(FAR struct nxaudio_s *nxaudio,
                    int fs, int bps, int chnum)
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r953082344


##########
examples/fmsynth/music_scale.h:
##########
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * 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[];
+
+#define MAX_SCALE  (sizeof(musical_scale) / sizeof(musical_scale[0]))

Review Comment:
   Thank you for the explanation.
   I got it.
   And it is not used in any place fortunately. So I removed it.
   (If it was used, then compilation error would occure.)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] pkarashchenko commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
pkarashchenko commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r947532441


##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)
+    {
+      return ERROR;
+    }
+
+  for (s = top; s->next_sound; s = s->next_sound);
+  s->next_sound = sub;

Review Comment:
   ok



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] pkarashchenko commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
pkarashchenko commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r954629087


##########
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);

Review Comment:
   ```suggestion
     pthread_create(&pid, &tattr, audio_loop_thread,
                    (pthread_addr_t)mmlplayer);
   ```



##########
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);

Review Comment:
   ```suggestion
               print_chord(1, mml_result.note_idx[0], mml_result.note_idx[1],
                           mml_result.length);
   ```



##########
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);

Review Comment:
   ```suggestion
     printf("%c: O%d%c : %d\n", LR ? 'R' : 'L',
            index / 12, "CcDdEFfGgAaB"[index % 12], length);
   ```



##########
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);

Review Comment:
   ```suggestion
     nxaudio_msgloop(&kbd->nxaudio, &cbs, (unsigned long)(uintptr_t)kbd);
   ```



##########
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]);

Review Comment:
   ```suggestion
         app_dequeue_cb((unsigned long)(uintptr_t)&g_kbd,
                        g_kbd.nxaudio.abufs[i]);
   ```



##########
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);

Review Comment:
   ```suggestion
     printf("%c: [O%d%c, O%d%c] : %d\n", LR ? 'R' : 'L',
            index1 / 12, "CcDdEFfGgAaB"[index1 % 12],
            index2 / 12, "CcDdEFfGgAaB"[index2 % 12],
            length);
   ```



##########
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);

Review Comment:
   ```suggestion
     pthread_create(&pid, &tattr, audio_loop_thread,
                    (pthread_addr_t)kbd);
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] pkarashchenko commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
pkarashchenko commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r954627282


##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+
+static const char *floh_walzer_right =

Review Comment:
   I'm asking because placing this in header file and usage of `static` and if header is included into multiple C files, then a separate copy of data will be created so size will be multiple of number of inclusions. To prevent this the best case is to remove `static` and make a symbol global that will cause an error at linking stage. Or leave a place for a "human factor" and keep current approach.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] masayuki2009 merged pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
masayuki2009 merged PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r947324463


##########
audioutils/fmsynth/test/fmsynth_alsa_test.c:
##########
@@ -0,0 +1,324 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_alsa_test.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 <stdio.h>
+#include <stdint.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+
+#define CHANNEL_NUM (2)
+#define RESAMPLING_ALSA (1)
+#define LATENCY_ALSA (10000)
+
+#define SAMPLE_NUM (FS / 20)
+#define BUFF_LENGTH (SAMPLE_NUM * CHANNEL_NUM)
+
+#define CODE_C_FREQ (261.625565f)
+#define CODE_D_FREQ (293.6647674f)
+#define CODE_E_FREQ (329.6275561f)
+#define CODE_F_FREQ (349.2282305f)
+#define CODE_G_FREQ (391.9954347f)
+#define CODE_A_FREQ (440.f)
+#define CODE_B_FREQ (493.8833009f)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t samples[BUFF_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: init_alsa
+ ****************************************************************************/
+
+static snd_pcm_t *init_alsa(int fs)

Review Comment:
   This code is just for unit testing on linux.
   So I don't think it needs "FAR".



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r947323308


##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)
+    {
+      return ERROR;
+    }
+
+  for (s = top; s->next_sound; s = s->next_sound);
+  s->next_sound = sub;

Review Comment:
   This is intentional, because I want to just connect sounds and mix each.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] pkarashchenko commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
pkarashchenko commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r952290412


##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,236 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops != NULL)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op != NULL; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)

Review Comment:
   ```suggestion
     if (ret != NULL)
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,236 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops != NULL)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op != NULL; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd != NULL)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op != NULL; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)

Review Comment:
   ```suggestion
     if (top == NULL || sub == NULL)
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)

Review Comment:
   ```suggestion
     if (ret != NULL)
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)

Review Comment:
   ```suggestion
         if (ret->eg == NULL)
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop     = NULL;
+      ret->parallelop    = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op != NULL)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op != NULL)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)

Review Comment:
   ```suggestion
     if (op == NULL || subop == NULL)
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,236 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops != NULL)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op != NULL; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd != NULL)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op != NULL; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)
+    {
+      return ERROR;
+    }
+
+  for (s = top; s->next_sound; s = s->next_sound);
+  s->next_sound = sub;

Review Comment:
   ```suggestion
     for (s = top; s->next_sound; s = s->next_sound);
   
     s->next_sound = sub;
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop     = NULL;
+      ret->parallelop    = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op != NULL)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op != NULL)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->parallelop; tmp = tmp->parallelop);
+
+  tmp->parallelop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_bind_feedback
+ ****************************************************************************/
+
+int fmsynthop_bind_feedback(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop, float ratio)
+{
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  op->feedbackrate = (int)((float)FMSYNTH_MAX_EGLEVEL * ratio);
+  op->feedback_ref = &subop->last_sigval;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_update_feedback
+ ****************************************************************************/
+
+int fmsynthop_update_feedback(FAR fmsynth_op_t *op)
+{
+  FAR fmsynth_op_t *tmp;
+
+  for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
+    {
+      fmsynthop_update_feedback(tmp);
+    }
+
+  if (op->feedback_ref)
+    {
+      op->feedback_val = *op->feedback_ref * op->feedbackrate
+                       / FMSYNTH_MAX_EGLEVEL;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthop_set_soundfreq(FAR fmsynth_op_t *op, float freq)
+{
+  FAR fmsynth_op_t *tmp;
+
+  op->sound_freq = freq;
+  update_parameters(op);
+
+  for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
+    {
+      fmsynthop_set_soundfreq(tmp, freq);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_soundfreqrate
+ ****************************************************************************/
+
+void fmsynthop_set_soundfreqrate(FAR fmsynth_op_t *op, float rate)
+{
+  op->freq_rate = rate;
+  update_parameters(op);
+}
+
+/****************************************************************************
+ * name: fmsynthop_start
+ ****************************************************************************/
+
+void fmsynthop_start(FAR fmsynth_op_t *op)
+{
+  FAR fmsynth_op_t *tmp;
+
+  fmsyntheg_start(op->eg);
+
+  for (tmp = op->cascadeop; tmp; tmp = tmp->parallelop)
+    {
+      fmsynthop_start(tmp);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_stop
+ ****************************************************************************/
+
+void fmsynthop_stop(FAR fmsynth_op_t *op)
+{
+  FAR fmsynth_op_t *tmp;
+
+  fmsyntheg_stop(op->eg);
+
+  for (tmp = op->cascadeop; tmp; tmp = tmp->parallelop)

Review Comment:
   ```suggestion
     for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,319 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)(uintptr_t)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)

Review Comment:
   ```suggestion
   static FAR struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,319 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)(uintptr_t)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)

Review Comment:
   ```suggestion
     if (ret >= (mqd_t)0)
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;

Review Comment:
   ```suggestion
     FAR char *rscore;
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  char *lscore;

Review Comment:
   ```suggestion
     FAR char *lscore;
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)arg;

Review Comment:
   ```suggestion
     FAR struct mmlplayer_s *fmmsc = (FAR struct mmlplayer_s *)(uintptr_t)arg;
   ```



##########
examples/fmsynth/music_scale.h:
##########
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * 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[];
+
+#define MAX_SCALE  (sizeof(musical_scale) / sizeof(musical_scale[0]))

Review Comment:
   I think this should be moved from header file to C file



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,
+                           apb->nmaxbytes / sizeof(int16_t),
+                           mmlplayer->nxaudio.chnum,
+                           tick_callback, (unsigned long)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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct mmlplayer_s *mmlplayer = (struct mmlplayer_s *)arg;
+
+  nxaudio_start(&mmlplayer->nxaudio);
+  nxaudio_msgloop(&mmlplayer->nxaudio, &cbs, (unsigned long)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)
+{
+  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 = (char *)floh_walzer_right;
+  mmlplayer->lscore  = (char *)floh_walzer_left;
+

Review Comment:
   ```suggestion
     mmlplayer->rscore = (FAR char *)floh_walzer_right;
     mmlplayer->lscore  = (FAR char *)floh_walzer_left;
   
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop     = NULL;
+      ret->parallelop    = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op != NULL)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op != NULL)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)

Review Comment:
   ```suggestion
     if (op == NULL || subop == NULL)
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop     = NULL;
+      ret->parallelop    = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op != NULL)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op != NULL)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->parallelop; tmp = tmp->parallelop);
+
+  tmp->parallelop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_bind_feedback
+ ****************************************************************************/
+
+int fmsynthop_bind_feedback(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop, float ratio)
+{
+  if (!op || !subop)

Review Comment:
   ```suggestion
     if (op == NULL || subop == NULL)
   ```



##########
audioutils/fmsynth/fmsynth_eg.c:
##########
@@ -0,0 +1,197 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_eg.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 <stdlib.h>
+#include <limits.h>
+
+#include <audioutils/fmsynth_eg.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CONVERT_INITVAL(lv) (int)((lv) * FMSYNTH_MAX_EGLEVEL)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: set_egparams
+ ****************************************************************************/
+
+static int set_egparams(int fs,
+                        FAR fmsynth_egparam_t *param,
+                        FAR struct fmsynth_eglevel_s *target_level,
+                        FAR struct fmsynth_eglevel_s *last_level)
+{
+  param->initval   = CONVERT_INITVAL(last_level->level);
+  param->period    = fs * target_level->period_ms / 1000;
+  param->diff2next = CONVERT_INITVAL(target_level->level)
+                    - CONVERT_INITVAL(last_level->level);
+
+  if (param->initval < -FMSYNTH_MAX_EGLEVEL ||
+      param->initval > FMSYNTH_MAX_EGLEVEL || param->period < 0)
+    {
+      return -1;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsyntheg_create
+ ****************************************************************************/
+
+FAR fmsynth_eg_t *fmsyntheg_create(void)
+{
+  int i;
+  FAR fmsynth_eg_t *ret = (FAR fmsynth_eg_t *)malloc(sizeof(fmsynth_eg_t));
+
+  if (ret)

Review Comment:
   ```suggestion
     if (ret != NULL)
   ```



##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+
+static const char *floh_walzer_right =

Review Comment:
   Could you please answer this?



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop     = NULL;
+      ret->parallelop    = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op != NULL)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op != NULL)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)

Review Comment:
   ```suggestion
     if (local_fs >= 0 && op != NULL && levels != NULL)
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop     = NULL;
+      ret->parallelop    = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op != NULL)
+    {
+      if (op->eg)

Review Comment:
   ```suggestion
         if (op->eg != NULL)
   ```



##########
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 *)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 *)arg;

Review Comment:
   ```suggestion
     FAR struct kbd_s *kbd = (FAR struct kbd_s *)(uintptr_t)arg;
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,
+                           apb->nmaxbytes / sizeof(int16_t),
+                           mmlplayer->nxaudio.chnum,
+                           tick_callback, (unsigned long)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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct mmlplayer_s *mmlplayer = (struct mmlplayer_s *)arg;
+
+  nxaudio_start(&mmlplayer->nxaudio);
+  nxaudio_msgloop(&mmlplayer->nxaudio, &cbs, (unsigned long)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)
+{
+  fmsynth_op_t *(*opfunc)(void);

Review Comment:
   ```suggestion
     CODE fmsynth_op_t *(*opfunc)(void);
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */

Review Comment:
   ```suggestion
     FAR fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
     FAR fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
   ```



##########
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 *)arg;

Review Comment:
   ```suggestion
     FAR struct kbd_s *kbd = (FAR struct kbd_s *)(uintptr_t)arg;
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,521 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+      default:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop     = NULL;
+      ret->parallelop    = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op != NULL)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op != NULL)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->parallelop; tmp = tmp->parallelop);
+
+  tmp->parallelop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_bind_feedback
+ ****************************************************************************/
+
+int fmsynthop_bind_feedback(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop, float ratio)
+{
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  op->feedbackrate = (int)((float)FMSYNTH_MAX_EGLEVEL * ratio);
+  op->feedback_ref = &subop->last_sigval;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_update_feedback
+ ****************************************************************************/
+
+int fmsynthop_update_feedback(FAR fmsynth_op_t *op)
+{
+  FAR fmsynth_op_t *tmp;
+
+  for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
+    {
+      fmsynthop_update_feedback(tmp);
+    }
+
+  if (op->feedback_ref)
+    {
+      op->feedback_val = *op->feedback_ref * op->feedbackrate
+                       / FMSYNTH_MAX_EGLEVEL;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthop_set_soundfreq(FAR fmsynth_op_t *op, float freq)
+{
+  FAR fmsynth_op_t *tmp;
+
+  op->sound_freq = freq;
+  update_parameters(op);
+
+  for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
+    {
+      fmsynthop_set_soundfreq(tmp, freq);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_soundfreqrate
+ ****************************************************************************/
+
+void fmsynthop_set_soundfreqrate(FAR fmsynth_op_t *op, float rate)
+{
+  op->freq_rate = rate;
+  update_parameters(op);
+}
+
+/****************************************************************************
+ * name: fmsynthop_start
+ ****************************************************************************/
+
+void fmsynthop_start(FAR fmsynth_op_t *op)
+{
+  FAR fmsynth_op_t *tmp;
+
+  fmsyntheg_start(op->eg);
+
+  for (tmp = op->cascadeop; tmp; tmp = tmp->parallelop)

Review Comment:
   ```suggestion
     for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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)

Review Comment:
   Please add `default` case



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;

Review Comment:
   ```suggestion
     FAR fmsynth_sound_t *lsound;
     FAR fmsynth_op_t    *lop;
   ```



##########
audioutils/nxaudio/nxaudio.c:
##########
@@ -0,0 +1,319 @@
+/****************************************************************************
+ * apps/audioutils/nxaudio/nxaudio.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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <sys/ioctl.h>
+#include <nuttx/audio/audio.h>
+
+#include <errno.h>
+
+#include <audioutils/nxaudio.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: configure_audio
+ ****************************************************************************/
+
+static int configure_audio(int fd, int ch, int fs, int bps, int chmap)
+{
+  struct audio_caps_desc_s cap;
+
+  cap.caps.ac_len = sizeof(struct audio_caps_s);
+  cap.caps.ac_type = AUDIO_TYPE_OUTPUT;
+  cap.caps.ac_channels = ch;
+  cap.caps.ac_chmap = chmap;
+  cap.caps.ac_controls.hw[0] = fs;
+  cap.caps.ac_controls.b[2] = bps;
+  cap.caps.ac_controls.b[3] = 0;  /* Just set 0 */
+
+  return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)(uintptr_t)&cap);
+}
+
+/****************************************************************************
+ * name: create_audiomq
+ ****************************************************************************/
+
+static mqd_t create_audiomq(int fd, int buf_num)
+{
+  mqd_t ret;
+  struct mq_attr attr;
+
+  attr.mq_maxmsg = buf_num;
+  attr.mq_msgsize = sizeof(struct audio_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags = 0;
+
+  ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME,
+                O_RDWR | O_CREAT, 0644, &attr);
+  if (ret >= (mqd_t) 0)
+    {
+      int rr;
+      if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0)
+        {
+          printf("mq register failed: %d, %d\n", rr, errno);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: create_audio_buffers
+ ****************************************************************************/
+
+static struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz)
+{
+  int i;
+  struct audio_buf_desc_s desc;
+  FAR struct ap_buffer_s **ret;
+
+  ret = (FAR struct ap_buffer_s **)calloc(num, sizeof(FAR void *));
+
+  for (i = 0; i < num; i++)
+    {
+      desc.numbytes = sz;
+      desc.u.pbuffer = &ret[i];
+
+      ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)(uintptr_t)&desc);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: free_audio_buffers
+ ****************************************************************************/
+
+static void free_audio_buffers(FAR struct nxaudio_s *nxaudio)
+{
+  int x;
+  struct audio_buf_desc_s desc;
+
+  for (x = 0; x < nxaudio->abufnum; x++)
+    {
+      if (nxaudio->abufs[x] != NULL)
+        {
+          desc.u.buffer = nxaudio->abufs[x];
+          ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER,
+                (unsigned long)(uintptr_t)&desc);
+        }
+    }
+
+  free(nxaudio->abufs);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fin_nxaudio
+ ****************************************************************************/
+
+void fin_nxaudio(FAR struct nxaudio_s *nxaudio)
+{
+  free_audio_buffers(nxaudio);
+  ioctl(nxaudio->fd, AUDIOIOC_STOP, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq);
+  ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0);
+  ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0);
+  mq_close(nxaudio->mq);
+  mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME);
+  close(nxaudio->fd);
+}
+
+/****************************************************************************
+ * name: init_nxaudio
+ ****************************************************************************/
+
+int init_nxaudio(FAR struct nxaudio_s *nxaudio,
+                 int fs, int bps, int chnum)
+{
+  struct ap_buffer_info_s buf_info;
+
+  nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC);
+  if (nxaudio->fd >= 0)
+    {
+      if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0)
+        {
+          close(nxaudio->fd);
+          return -1;
+        }
+
+      /* Audio configuration: set channel num, FS and bps */
+
+      configure_audio(nxaudio->fd, chnum, fs, bps, 0);
+
+      nxaudio->chnum = chnum;
+
+      ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO,
+            (unsigned long)(uintptr_t)&buf_info);
+
+      /* Create message queue to communicate with audio driver */
+
+      nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8);
+
+      /* Create audio buffers to inject audio sample */
+
+      nxaudio->abufs = create_audio_buffers(nxaudio->fd,
+                               buf_info.nbuffers, buf_info.buffer_size);
+      nxaudio->abufnum = buf_info.nbuffers;
+
+      return 0;
+    }
+  else
+    {
+      return -1;
+    }
+}
+
+/****************************************************************************
+ * name: nxaudio_enqbuffer
+ ****************************************************************************/
+
+int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio,
+                      FAR struct ap_buffer_s *apb)
+{
+  struct audio_buf_desc_s desc;
+
+  desc.numbytes = apb->nbytes;
+  desc.u.buffer = apb;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_ENQUEUEBUFFER,
+               (unsigned long)(uintptr_t)&desc);
+}
+
+/****************************************************************************
+ * name: nxaudio_setvolume
+ ****************************************************************************/
+
+int nxaudio_setvolume(FAR struct nxaudio_s *nxaudio, uint16_t vol)
+{
+  struct audio_caps_desc_s cap_desc;
+
+  cap_desc.caps.ac_len            = sizeof(struct audio_caps_s);
+  cap_desc.caps.ac_type           = AUDIO_TYPE_FEATURE;
+  cap_desc.caps.ac_format.hw      = AUDIO_FU_VOLUME;
+  cap_desc.caps.ac_controls.hw[0] = vol;
+
+  return ioctl(nxaudio->fd, AUDIOIOC_CONFIGURE,
+               (unsigned long)(uintptr_t)&cap_desc);
+}
+
+/****************************************************************************
+ * name: nxaudio_start
+ ****************************************************************************/
+
+int nxaudio_start(FAR struct nxaudio_s *nxaudio)
+{
+  return ioctl(nxaudio->fd, AUDIOIOC_START, 0);
+}
+
+/****************************************************************************
+ * name: nxaudio_start
+ ****************************************************************************/
+
+int nxaudio_stop(FAR struct nxaudio_s *nxaudio)
+{
+  struct audio_msg_s term_msg;
+
+  term_msg.msg_id = AUDIO_MSG_STOP;
+  term_msg.u.data = 0;
+  mq_send(nxaudio->mq, (FAR const char *)&term_msg, sizeof(term_msg), 0);
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: nxaudio_msgloop
+ ****************************************************************************/
+
+int nxaudio_msgloop(FAR struct nxaudio_s *nxaudio,
+                    FAR struct nxaudio_callbacks_s *cbs,
+                    unsigned long arg)
+{
+  bool running = true;
+  struct audio_msg_s msg;
+  unsigned int prio;
+  ssize_t size;
+
+  if (!cbs)

Review Comment:
   ```suggestion
     if (cbs == NULL)
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,
+                           apb->nmaxbytes / sizeof(int16_t),
+                           mmlplayer->nxaudio.chnum,
+                           tick_callback, (unsigned long)mmlplayer);

Review Comment:
   ```suggestion
                              tick_callback, (unsigned long)(uintptr_t)mmlplayer);
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,
+                           apb->nmaxbytes / sizeof(int16_t),
+                           mmlplayer->nxaudio.chnum,
+                           tick_callback, (unsigned long)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 void *audio_loop_thread(pthread_addr_t arg)

Review Comment:
   ```suggestion
   static FAR void *audio_loop_thread(pthread_addr_t arg)
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,

Review Comment:
   ```suggestion
     apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (FAR int16_t *)apb->samp,
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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)

Review Comment:
   Please add `default`case



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,
+                           apb->nmaxbytes / sizeof(int16_t),
+                           mmlplayer->nxaudio.chnum,
+                           tick_callback, (unsigned long)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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct mmlplayer_s *mmlplayer = (struct mmlplayer_s *)arg;

Review Comment:
   ```suggestion
     struct mmlplayer_s *mmlplayer = (FAR struct mmlplayer_s *)arg;
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,
+                           apb->nmaxbytes / sizeof(int16_t),
+                           mmlplayer->nxaudio.chnum,
+                           tick_callback, (unsigned long)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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct mmlplayer_s *mmlplayer = (struct mmlplayer_s *)arg;
+
+  nxaudio_start(&mmlplayer->nxaudio);
+  nxaudio_msgloop(&mmlplayer->nxaudio, &cbs, (unsigned long)mmlplayer);

Review Comment:
   ```suggestion
     nxaudio_msgloop(&mmlplayer->nxaudio, &cbs, (unsigned long)(uintptr_t)mmlplayer);
   ```



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;

Review Comment:
   ```suggestion
     FAR struct mmlplayer_s *mmlplayer = (FAR struct mmlplayer_s *)(uintptr_t)arg;
   ```



##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __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 =

Review Comment:
   Could you please answer this?



##########
examples/fmsynth/mmlplayer_main.c:
##########
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * 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 */
+
+  fmsynth_sound_t *rsound[2]; /* Need 2 sounds for CHORD */
+  fmsynth_op_t    *rop[2];    /* Need 2 sounds for CHORD */
+
+  int rtick;
+  char *rscore;
+  struct music_macro_lang_s rmml;
+
+  /* Left hand sound */
+
+  fmsynth_sound_t *lsound;
+  fmsynth_op_t    *lop;
+  int ltick;
+  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;
+        }
+    }
+  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;
+        }
+    }
+  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 *)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 *)arg;
+
+  apb->curbyte = 0;
+  apb->flags = 0;
+  apb->nbytes = fmsynth_rendering(mmlplayer->lsound, (int16_t *)apb->samp,
+                           apb->nmaxbytes / sizeof(int16_t),
+                           mmlplayer->nxaudio.chnum,
+                           tick_callback, (unsigned long)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 void *audio_loop_thread(pthread_addr_t arg)
+{
+  struct mmlplayer_s *mmlplayer = (struct mmlplayer_s *)arg;
+
+  nxaudio_start(&mmlplayer->nxaudio);
+  nxaudio_msgloop(&mmlplayer->nxaudio, &cbs, (unsigned long)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)
+{
+  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 = (char *)floh_walzer_right;
+  mmlplayer->lscore  = (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)

Review Comment:
   ```suggestion
   static int configure_option(FAR struct app_options *option,
                               int argc, char **argv)
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r948487539


##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+
+static const char *floh_walzer_right =

Review Comment:
   mmlplayer_main.c uses it.
   mmlplayer_main.c is an example about how to use fmsynth.
   And the score is just example to play, so I wanted them separate.



##########
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 __EXAMPLES_FMSYNTH_MMLPLAYER_SCORE_H
+#define __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 =

Review Comment:
   mmlplayer_main.c uses it.
   mmlplayer_main.c is an example about how to use fmsynth.
   And the score is just example to play, so I wanted them separate.



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;

Review Comment:
   No. It is also intentional. Same reason of subsnd->next_sound case.



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->parallelop; tmp = tmp->parallelop);
+
+  tmp->parallelop = subop;

Review Comment:
   No need to add subop->pararelop = NULL. The same reason as subsnd->next_sound case.



##########
examples/fmsynth/music_scale.h:
##########
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * 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[];
+
+#define MAX_SCALE  (sizeof(musical_scale) / sizeof(musical_scale[0]))

Review Comment:
   Could you let me know the reason why you think so?
   
   This is a table size of the musical_scale array which is provided from music_scale.c.
   The music_scale.h header file is providing information of music_scale.c and table size is one of information of music_scale.c.
   So I don't feel any uncomfortable.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] masayuki2009 commented on pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
masayuki2009 commented on PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#issuecomment-1227135794

   >Few minor comments, but nothing that blocks from merging and can be fixed in follow-up PR
   
   Let me merge this PR.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] pkarashchenko commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
pkarashchenko commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r946974062


##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)

Review Comment:
   Optional
   ```suggestion
     while (ops != NULL)
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);

Review Comment:
   ```suggestion
   #define WRAP_ROUND_TIME_SEC (10)
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)
+    {
+      return ERROR;
+    }
+
+  for (s = top; s->next_sound; s = s->next_sound);
+  s->next_sound = sub;

Review Comment:
   Do we need `sub->next_sound = NULL;`?



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)

Review Comment:
   Optional
   ```suggestion
     for (op = snd->operators; op != NULL; op = op->parallelop)
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)

Review Comment:
   Optional
   ```suggestion
     if (snd != NULL)
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op; op = op->parallelop)

Review Comment:
   ditto



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)
+    {
+      return ERROR;
+    }
+
+  for (s = top; s->next_sound; s = s->next_sound);
+  s->next_sound = sub;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynth_rendering
+ ****************************************************************************/
+
+int fmsynth_rendering(FAR fmsynth_sound_t *snd,
+                      FAR int16_t *sample, int sample_num, int chnum,
+                      FAR fmsynth_tickcb_t cb, unsigned long cbarg)
+{
+  int i;
+  int ch;
+  int out;
+  FAR fmsynth_sound_t *itr;
+
+  for (i = 0; i < sample_num; i += chnum)
+    {
+      out = 0;
+      itr = snd;
+      while (itr)
+        {
+          out = out + sound_modulate(itr);
+          itr = itr->next_sound;
+        }

Review Comment:
   Optional
   ```suggestion
         for (itr = snd; itr != NULL; itr = itr->next_sound)
           {
             out = out + sound_modulate(itr);
           }
   ```



##########
audioutils/fmsynth/fmsynth_eg.c:
##########
@@ -0,0 +1,197 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_eg.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 <stdlib.h>
+#include <limits.h>
+
+#include <audioutils/fmsynth_eg.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CONVERT_INITVAL(lv) (int)((lv) * FMSYNTH_MAX_EGLEVEL)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: set_egparams
+ ****************************************************************************/
+
+static int set_egparams(int fs,
+                        FAR fmsynth_egparam_t *param,
+                        FAR struct fmsynth_eglevel_s *target_level,
+                        FAR struct fmsynth_eglevel_s *last_level)
+{
+  param->initval   = CONVERT_INITVAL(last_level->level);
+  param->period    = fs * target_level->period_ms / 1000;
+  param->diff2next = CONVERT_INITVAL(target_level->level)
+                    - CONVERT_INITVAL(last_level->level);
+
+  if (param->initval < -FMSYNTH_MAX_EGLEVEL ||
+      param->initval > FMSYNTH_MAX_EGLEVEL || param->period < 0)
+    {
+      return -1;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsyntheg_create
+ ****************************************************************************/
+
+FAR fmsynth_eg_t *fmsyntheg_create(void)
+{
+  int i;
+  FAR fmsynth_eg_t *ret = (FAR fmsynth_eg_t *)malloc(sizeof(fmsynth_eg_t));
+
+  if (ret)
+    {
+      ret->state = EGSTATE_RELEASED;
+      ret->state_counter = 0;
+      for (i = 0; i < EGSTATE_MAX; i++)
+        {
+          ret->state_params[i].initval = 0;
+          ret->state_params[i].period = 0;
+        }
+
+      ret->state_params[EGSTATE_RELEASED].initval = FMSYNTH_MAX_EGLEVEL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsyntheg_delete
+ ****************************************************************************/
+
+void fmsyntheg_delete(FAR fmsynth_eg_t *eg)
+{
+  if (eg)

Review Comment:
   Optional
   ```suggestion
     if (eg != NULL)
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;

Review Comment:
   Optional
   ```suggestion
   static int max_phase_time;
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;

Review Comment:
   ```suggestion
         ret->cascadeop     = NULL;
         ret->parallelop    = NULL;
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;

Review Comment:
   Optional
   ```suggestion
   static int local_fs;
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op)

Review Comment:
   Optional
   ```suggestion
     if (op != NULL)
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->parallelop; tmp = tmp->parallelop);
+
+  tmp->parallelop = subop;

Review Comment:
   ditto



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;

Review Comment:
   do we need `subop->cascadeop = NULL;`?



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->parallelop; tmp = tmp->parallelop);
+
+  tmp->parallelop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_bind_feedback
+ ****************************************************************************/
+
+int fmsynthop_bind_feedback(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop, float ratio)
+{
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  op->feedbackrate = (int)((float)FMSYNTH_MAX_EGLEVEL * ratio);
+  op->feedback_ref = &subop->last_sigval;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_update_feedback
+ ****************************************************************************/
+
+int fmsynthop_update_feedback(FAR fmsynth_op_t *op)
+{
+  FAR fmsynth_op_t *tmp = op->cascadeop;
+
+  while (tmp)
+    {
+      fmsynthop_update_feedback(tmp);
+      tmp = tmp->parallelop;
+    }

Review Comment:
   Optional
   ```suggestion
     FAR fmsynth_op_t *tmp;
   
     for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
       {
         fmsynthop_update_feedback(tmp);
       }
   ```



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)

Review Comment:
   Optional
   ```suggestion
     if (op != NULL)
       {
         if (op->eg != NULL)
   ```



##########
audioutils/fmsynth/test/fmsynth_alsa_test.c:
##########
@@ -0,0 +1,324 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_alsa_test.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 <stdio.h>
+#include <stdint.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+
+#define CHANNEL_NUM (2)
+#define RESAMPLING_ALSA (1)
+#define LATENCY_ALSA (10000)
+
+#define SAMPLE_NUM (FS / 20)
+#define BUFF_LENGTH (SAMPLE_NUM * CHANNEL_NUM)
+
+#define CODE_C_FREQ (261.625565f)
+#define CODE_D_FREQ (293.6647674f)
+#define CODE_E_FREQ (329.6275561f)
+#define CODE_F_FREQ (349.2282305f)
+#define CODE_G_FREQ (391.9954347f)
+#define CODE_A_FREQ (440.f)
+#define CODE_B_FREQ (493.8833009f)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t samples[BUFF_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: init_alsa
+ ****************************************************************************/
+
+static snd_pcm_t *init_alsa(int fs)

Review Comment:
   ```suggestion
   static FAR snd_pcm_t *init_alsa(int fs)
   ```



##########
audioutils/fmsynth/test/fmsynth_alsa_test.c:
##########
@@ -0,0 +1,324 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_alsa_test.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 <stdio.h>
+#include <stdint.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+
+#define CHANNEL_NUM (2)
+#define RESAMPLING_ALSA (1)
+#define LATENCY_ALSA (10000)
+
+#define SAMPLE_NUM (FS / 20)
+#define BUFF_LENGTH (SAMPLE_NUM * CHANNEL_NUM)
+
+#define CODE_C_FREQ (261.625565f)
+#define CODE_D_FREQ (293.6647674f)
+#define CODE_E_FREQ (329.6275561f)
+#define CODE_F_FREQ (349.2282305f)
+#define CODE_G_FREQ (391.9954347f)
+#define CODE_A_FREQ (440.f)
+#define CODE_B_FREQ (493.8833009f)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t samples[BUFF_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: init_alsa
+ ****************************************************************************/
+
+static snd_pcm_t *init_alsa(int fs)
+{
+  int ret;
+  snd_pcm_t *hndl = NULL;

Review Comment:
   FAR



##########
audioutils/fmsynth/test/fmsynth_alsa_test.c:
##########
@@ -0,0 +1,324 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_alsa_test.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 <stdio.h>
+#include <stdint.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+
+#define CHANNEL_NUM (2)
+#define RESAMPLING_ALSA (1)
+#define LATENCY_ALSA (10000)
+
+#define SAMPLE_NUM (FS / 20)
+#define BUFF_LENGTH (SAMPLE_NUM * CHANNEL_NUM)
+
+#define CODE_C_FREQ (261.625565f)
+#define CODE_D_FREQ (293.6647674f)
+#define CODE_E_FREQ (329.6275561f)
+#define CODE_F_FREQ (349.2282305f)
+#define CODE_G_FREQ (391.9954347f)
+#define CODE_A_FREQ (440.f)
+#define CODE_B_FREQ (493.8833009f)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t samples[BUFF_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: init_alsa
+ ****************************************************************************/
+
+static snd_pcm_t *init_alsa(int fs)
+{
+  int ret;
+  snd_pcm_t *hndl = NULL;
+
+  ret = snd_pcm_open(&hndl, "default", SND_PCM_STREAM_PLAYBACK, 0);
+  if (ret < 0)
+    {
+      printf("sdn_pcm_open error\n");
+      return NULL;
+    }
+
+  ret = snd_pcm_set_params(hndl,
+                           SND_PCM_FORMAT_S16,
+                           SND_PCM_ACCESS_RW_INTERLEAVED,
+                           CHANNEL_NUM, fs, RESAMPLING_ALSA, LATENCY_ALSA);
+  if (ret != 0)
+    {
+      printf("sdn_pcm_set_params error\n");
+      snd_pcm_close(hndl);
+      return NULL;
+    }
+
+  return hndl;
+}
+
+/****************************************************************************
+ * name: set_nonblocking
+ ****************************************************************************/
+
+static int set_nonblocking(struct termios *saved)

Review Comment:
   ```suggestion
   static int set_nonblocking(FAR struct termios *saved)
   ```
   Here and other similar places



##########
audioutils/fmsynth/fmsynth_op.c:
##########
@@ -0,0 +1,518 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth_op.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 <stdlib.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PHASE_ADJUST(th) \
+        ( ((th) < 0 ? (FMSYNTH_PI) - (th) : (th)) % (FMSYNTH_PI * 2) )
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const short s_sintbl[] =
+{
+  0xff37, /* Extra data for linear completion */
+
+  /* Actual sin table of half PI [256] */
+
+  0x0000, 0x00c9, 0x0192, 0x025b,
+  0x0324, 0x03ed, 0x04b6, 0x057e,
+  0x0647, 0x0710, 0x07d9, 0x08a1,
+  0x096a, 0x0a32, 0x0afb, 0x0bc3,
+  0x0c8b, 0x0d53, 0x0e1b, 0x0ee3,
+  0x0fab, 0x1072, 0x1139, 0x1200,
+  0x12c7, 0x138e, 0x1455, 0x151b,
+  0x15e1, 0x16a7, 0x176d, 0x1833,
+  0x18f8, 0x19bd, 0x1a82, 0x1b46,
+  0x1c0b, 0x1ccf, 0x1d93, 0x1e56,
+  0x1f19, 0x1fdc, 0x209f, 0x2161,
+  0x2223, 0x22e4, 0x23a6, 0x2467,
+  0x2527, 0x25e7, 0x26a7, 0x2767,
+  0x2826, 0x28e5, 0x29a3, 0x2a61,
+  0x2b1e, 0x2bdb, 0x2c98, 0x2d54,
+  0x2e10, 0x2ecc, 0x2f86, 0x3041,
+  0x30fb, 0x31b4, 0x326d, 0x3326,
+  0x33de, 0x3496, 0x354d, 0x3603,
+  0x36b9, 0x376f, 0x3824, 0x38d8,
+  0x398c, 0x3a3f, 0x3af2, 0x3ba4,
+  0x3c56, 0x3d07, 0x3db7, 0x3e67,
+  0x3f16, 0x3fc5, 0x4073, 0x4120,
+  0x41cd, 0x4279, 0x4325, 0x43d0,
+  0x447a, 0x4523, 0x45cc, 0x4674,
+  0x471c, 0x47c3, 0x4869, 0x490e,
+  0x49b3, 0x4a57, 0x4afa, 0x4b9d,
+  0x4c3f, 0x4ce0, 0x4d80, 0x4e20,
+  0x4ebf, 0x4f5d, 0x4ffa, 0x5097,
+  0x5133, 0x51ce, 0x5268, 0x5301,
+  0x539a, 0x5432, 0x54c9, 0x555f,
+  0x55f4, 0x5689, 0x571d, 0x57b0,
+  0x5842, 0x58d3, 0x5963, 0x59f3,
+  0x5a81, 0x5b0f, 0x5b9c, 0x5c28,
+  0x5cb3, 0x5d3d, 0x5dc6, 0x5e4f,
+  0x5ed6, 0x5f5d, 0x5fe2, 0x6067,
+  0x60eb, 0x616e, 0x61f0, 0x6271,
+  0x62f1, 0x6370, 0x63ee, 0x646b,
+  0x64e7, 0x6562, 0x65dd, 0x6656,
+  0x66ce, 0x6745, 0x67bc, 0x6831,
+  0x68a5, 0x6919, 0x698b, 0x69fc,
+  0x6a6c, 0x6adb, 0x6b4a, 0x6bb7,
+  0x6c23, 0x6c8e, 0x6cf8, 0x6d61,
+  0x6dc9, 0x6e30, 0x6e95, 0x6efa,
+  0x6f5e, 0x6fc0, 0x7022, 0x7082,
+  0x70e1, 0x7140, 0x719d, 0x71f9,
+  0x7254, 0x72ae, 0x7306, 0x735e,
+  0x73b5, 0x740a, 0x745e, 0x74b1,
+  0x7503, 0x7554, 0x75a4, 0x75f3,
+  0x7640, 0x768d, 0x76d8, 0x7722,
+  0x776b, 0x77b3, 0x77f9, 0x783f,
+  0x7883, 0x78c6, 0x7908, 0x7949,
+  0x7989, 0x79c7, 0x7a04, 0x7a41,
+  0x7a7c, 0x7ab5, 0x7aee, 0x7b25,
+  0x7b5c, 0x7b91, 0x7bc4, 0x7bf7,
+  0x7c29, 0x7c59, 0x7c88, 0x7cb6,
+  0x7ce2, 0x7d0e, 0x7d38, 0x7d61,
+  0x7d89, 0x7db0, 0x7dd5, 0x7df9,
+  0x7e1c, 0x7e3e, 0x7e5e, 0x7e7e,
+  0x7e9c, 0x7eb9, 0x7ed4, 0x7eef,
+  0x7f08, 0x7f20, 0x7f37, 0x7f4c,
+  0x7f61, 0x7f74, 0x7f86, 0x7f96,
+  0x7fa6, 0x7fb4, 0x7fc1, 0x7fcd,
+  0x7fd7, 0x7fe0, 0x7fe8, 0x7fef,
+  0x7ff5, 0x7ff9, 0x7ffc, 0x7ffe,
+
+  0x7fff, /* Extra data for linear completion */
+};
+
+static int local_fs = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: pseudo_sin256
+ ****************************************************************************/
+
+static int pseudo_sin256(int theta)
+{
+  int short_sin;
+  int rest;
+  int phase;
+  int tblidx;
+
+  theta = PHASE_ADJUST(theta);
+
+  rest   = theta & 0x7f;
+  phase  = theta / (FMSYNTH_PI / 2);
+  tblidx = (theta % (FMSYNTH_PI / 2)) >> 7;
+
+  if (phase & 0x01)
+    {
+      tblidx = 257 - tblidx;
+      short_sin = s_sintbl[tblidx];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx - 1] - short_sin) * rest) >> 7);
+    }
+  else
+    {
+      short_sin = s_sintbl[tblidx + 1];
+      short_sin = short_sin
+                + (((s_sintbl[tblidx + 2] - short_sin) * rest) >> 7);
+    }
+
+  return phase & 0x02 ? -short_sin : short_sin;
+}
+
+/****************************************************************************
+ * name: triangle_wave
+ ****************************************************************************/
+
+static int triangle_wave(int theta)
+{
+  int ret = 0;
+  int phase;
+  int offset;
+  int slope;
+
+  theta = PHASE_ADJUST(theta);
+  phase  = theta / (FMSYNTH_PI / 2);
+  offset = theta % (FMSYNTH_PI / 2);
+
+  switch (phase)
+    {
+      case 0:
+        ret = 0;
+        slope = SHRT_MAX;
+        break;
+      case 1:
+        ret = SHRT_MAX;
+        slope = -SHRT_MAX;
+        break;
+      case 2:
+        ret = 0;
+        slope = -SHRT_MAX;
+        break;
+      case 3:
+        ret = -SHRT_MAX;
+        slope = SHRT_MAX;
+        break;
+    }
+
+  return ret + ((slope * offset) >> 15);
+}
+
+/****************************************************************************
+ * name: sawtooth_wave
+ ****************************************************************************/
+
+static int sawtooth_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return (theta >> 1) - SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: square_wave
+ ****************************************************************************/
+
+static int square_wave(int theta)
+{
+  theta = PHASE_ADJUST(theta);
+  return theta < FMSYNTH_PI ? SHRT_MAX : -SHRT_MAX;
+}
+
+/****************************************************************************
+ * name: update_parameters
+ ****************************************************************************/
+
+static void update_parameters(FAR fmsynth_op_t *op)
+{
+  if (local_fs != 0)
+    {
+      op->delta_phase = 2 * FMSYNTH_PI * op->sound_freq * op->freq_rate
+                        / (float)local_fs;
+    }
+  else
+    {
+      op->delta_phase = 0.f;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynthop_set_samplerate
+ ****************************************************************************/
+
+int fmsynthop_set_samplerate(int fs)
+{
+  if (fs < 0)
+    {
+      return ERROR;
+    }
+
+  local_fs = fs;
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_create
+ ****************************************************************************/
+
+FAR fmsynth_op_t *fmsynthop_create(void)
+{
+  FAR fmsynth_op_t *ret;
+
+  ret = (FAR fmsynth_op_t *)malloc(sizeof(fmsynth_op_t));
+
+  if (ret)
+    {
+      ret->eg = fmsyntheg_create();
+      if (!ret->eg)
+        {
+          free(ret);
+          return NULL;
+        }
+
+      ret->wavegen       = NULL;
+      ret->cascadeop    = NULL;
+      ret->parallelop   = NULL;
+      ret->feedback_ref  = NULL;
+      ret->feedback_val  = 0;
+      ret->feedbackrate  = 0;
+      ret->last_sigval   = 0;
+      ret->freq_rate     = 1.f;
+      ret->sound_freq    = 0.f;
+      ret->delta_phase   = 0.f;
+      ret->current_phase = 0.f;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_delete
+ ****************************************************************************/
+
+void fmsynthop_delete(FAR fmsynth_op_t *op)
+{
+  if (op)
+    {
+      if (op->eg)
+        {
+          free(op->eg);
+        }
+
+      free(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthop_select_opfunc
+ ****************************************************************************/
+
+int fmsynthop_select_opfunc(FAR fmsynth_op_t *op, int type)
+{
+  int ret = ERROR;
+
+  if (op)
+    {
+      switch (type)
+        {
+          case FMSYNTH_OPFUNC_SIN:
+            op->wavegen = pseudo_sin256;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_TRIANGLE:
+            op->wavegen = triangle_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SAWTOOTH:
+            op->wavegen = sawtooth_wave;
+            ret = OK;
+            break;
+
+          case FMSYNTH_OPFUNC_SQUARE:
+            op->wavegen = square_wave;
+            ret = OK;
+            break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_envelope
+ ****************************************************************************/
+
+int fmsynthop_set_envelope(FAR fmsynth_op_t *op,
+                           FAR fmsynth_eglevels_t *levels)
+{
+  if (local_fs >= 0 && op && levels)
+    {
+      return fmsyntheg_set_param(op->eg, local_fs, levels);
+    }
+
+  return ERROR;
+}
+
+/****************************************************************************
+ * name: fmsynthop_cascade_subop
+ ****************************************************************************/
+
+int fmsynthop_cascade_subop(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->cascadeop; tmp = tmp->cascadeop);
+
+  tmp->cascadeop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_parallel_subop
+ ****************************************************************************/
+
+int fmsynthop_parallel_subop(FAR fmsynth_op_t *op,
+                             FAR fmsynth_op_t *subop)
+{
+  FAR fmsynth_op_t *tmp;
+
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  for (tmp = op; tmp->parallelop; tmp = tmp->parallelop);
+
+  tmp->parallelop = subop;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_bind_feedback
+ ****************************************************************************/
+
+int fmsynthop_bind_feedback(FAR fmsynth_op_t *op,
+                            FAR fmsynth_op_t *subop, float ratio)
+{
+  if (!op || !subop)
+    {
+      return ERROR;
+    }
+
+  op->feedbackrate = (int)((float)FMSYNTH_MAX_EGLEVEL * ratio);
+  op->feedback_ref = &subop->last_sigval;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_update_feedback
+ ****************************************************************************/
+
+int fmsynthop_update_feedback(FAR fmsynth_op_t *op)
+{
+  FAR fmsynth_op_t *tmp = op->cascadeop;
+
+  while (tmp)
+    {
+      fmsynthop_update_feedback(tmp);
+      tmp = tmp->parallelop;
+    }
+
+  if (op->feedback_ref)
+    {
+      op->feedback_val = *op->feedback_ref * op->feedbackrate
+                       / FMSYNTH_MAX_EGLEVEL;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthop_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthop_set_soundfreq(FAR fmsynth_op_t *op, float freq)
+{
+  FAR fmsynth_op_t *tmp;
+
+  op->sound_freq = freq;
+  update_parameters(op);
+
+  for (tmp = op->cascadeop; tmp; tmp = tmp->parallelop)

Review Comment:
   Optional
   ```suggestion
     for (tmp = op->cascadeop; tmp != NULL; tmp = tmp->parallelop)
   ```



##########
audioutils/fmsynth/test/fmsynth_test.c:
##########
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_test.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 <stdio.h>
+#include <stdint.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+#define SOUNDFREQ (3000.f)
+#define TEST_LENGTH ((FS / 1000) * (10 + 20 + 16 + 5 + 30))
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t my_sample[TEST_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: set_levels
+ ****************************************************************************/
+
+static fmsynth_eglevels_t *set_levels(fmsynth_eglevels_t *level,
+                                      int atk_lvl, int atk_peri,
+                                      int decbrk_lvl, int decbrk_peri,
+                                      int dec_lvl, int dec_peri,
+                                      int sus_lvl, int sus_peri,
+                                      int rel_lvl, int rel_peri)
+{
+  level->attack.level = atk_lvl;
+  level->attack.period_ms = atk_peri;
+  level->decaybrk.level = decbrk_lvl;
+  level->decaybrk.period_ms = decbrk_peri;
+  level->decay.level = dec_lvl;
+  level->decay.period_ms = dec_peri;
+  level->sustain.level = sus_lvl;
+  level->sustain.period_ms = sus_peri;
+  level->release.level = rel_lvl;
+  level->release.period_ms = rel_peri;
+
+  return level;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: main
+ ****************************************************************************/
+
+int main(void)
+{
+  int phase_time;
+
+  fmsynth_eglevels_t levels;
+  fmsynth_sound_t *snd1;
+  fmsynth_op_t *envop;
+  fmsynth_op_t *fbop;

Review Comment:
   FAR



##########
include/audioutils/fmsynth.h:
##########
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * apps/include/audioutils/fmsynth.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 __INCLUDE_AUDIOUTILS_FMSYNTH_H
+#define __INCLUDE_AUDIOUTILS_FMSYNTH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <limits.h>
+#include <stdint.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FMSYNTH_MAX_VOLUME (SHRT_MAX)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef struct fmsynth_sound_s
+{
+  int phase_time;
+  int max_phase_time;
+  int volume;
+  fmsynth_op_t *operators;
+
+  struct fmsynth_sound_s *next_sound;
+} fmsynth_sound_t;
+
+typedef void (*fmsynth_tickcb_t)(unsigned long cbarg);

Review Comment:
   ```suggestion
   typedef CODE void (*fmsynth_tickcb_t)(unsigned long cbarg);
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)
+    {
+      return ERROR;
+    }
+
+  for (s = top; s->next_sound; s = s->next_sound);
+  s->next_sound = sub;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynth_rendering
+ ****************************************************************************/
+
+int fmsynth_rendering(FAR fmsynth_sound_t *snd,
+                      FAR int16_t *sample, int sample_num, int chnum,
+                      FAR fmsynth_tickcb_t cb, unsigned long cbarg)

Review Comment:
   ```suggestion
                        fmsynth_tickcb_t cb, unsigned long cbarg)
   ```



##########
include/audioutils/fmsynth_op.h:
##########
@@ -0,0 +1,99 @@
+/****************************************************************************
+ * apps/include/audioutils/fmsynth_op.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_INCLUDE_AUDIOUTILS_FMSYNTH_OP_H
+#define __APPS_INCLUDE_AUDIOUTILS_FMSYNTH_OP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <audioutils/fmsynth_eg.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FMSYNTH_PI (0x10000)
+
+#define FMSYNTH_OPFUNC_SIN      (0)
+#define FMSYNTH_OPFUNC_TRIANGLE (1)
+#define FMSYNTH_OPFUNC_SAWTOOTH (2)
+#define FMSYNTH_OPFUNC_SQUARE   (3)
+#define FMSYNTH_OPFUNC_NUM      (4)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef int (*opfunc_t)(int theta);

Review Comment:
   ```suggestion
   typedef CODE int (*opfunc_t)(int theta);
   ```



##########
audioutils/fmsynth/fmsynth.c:
##########
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/fmsynth.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 <stdlib.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define WRAP_ROUND_TIME_SEC (10);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int max_phase_time = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fetch_feedback
+ ****************************************************************************/
+
+static void fetch_feedback(FAR fmsynth_op_t *ops)
+{
+  while (ops)
+    {
+      fmsynthop_update_feedback(ops);
+      ops = ops->parallelop;
+    }
+}
+
+/****************************************************************************
+ * name: update_phase
+ ****************************************************************************/
+
+static void update_phase(FAR fmsynth_sound_t *snd)
+{
+  snd->phase_time++;
+  if (snd->phase_time >= max_phase_time)
+    {
+      snd->phase_time = 0;
+    }
+}
+
+/****************************************************************************
+ * name: sound_modulate
+ ****************************************************************************/
+
+static int sound_modulate(FAR fmsynth_sound_t *snd)
+{
+  int out = 0;
+  FAR fmsynth_op_t *op;
+
+  if (snd->operators == NULL)
+    {
+      return out;
+    }
+
+  fetch_feedback(snd->operators);
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      out += fmsynthop_operate(op, snd->phase_time);
+    }
+
+  update_phase(snd);
+
+  return out * snd->volume / FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: fmsynth_initialize
+ ****************************************************************************/
+
+int fmsynth_initialize(int fs)
+{
+  max_phase_time = fs * WRAP_ROUND_TIME_SEC;
+  return fmsynthop_set_samplerate(fs);
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_create
+ ****************************************************************************/
+
+FAR fmsynth_sound_t *fmsynthsnd_create(void)
+{
+  FAR fmsynth_sound_t *ret;
+  ret = (FAR fmsynth_sound_t *)malloc(sizeof(fmsynth_sound_t));
+  if (ret)
+    {
+      ret->phase_time = 0;
+      ret->volume = FMSYNTH_MAX_VOLUME;
+      ret->operators = NULL;
+      ret->next_sound = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_delete
+ ****************************************************************************/
+
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd)
+{
+  if (snd)
+    {
+      free(snd);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_operator
+ ****************************************************************************/
+
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op)
+{
+  snd->operators = op;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_soundfreq
+ ****************************************************************************/
+
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq)
+{
+  FAR fmsynth_op_t *op;
+
+  for (op = snd->operators; op; op = op->parallelop)
+    {
+      fmsynthop_set_soundfreq(op, freq);
+      fmsynthop_start(op);
+    }
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_set_volume
+ ****************************************************************************/
+
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol)
+{
+  snd->volume = vol * FMSYNTH_MAX_VOLUME;
+}
+
+/****************************************************************************
+ * name: fmsynthsnd_add_subsound
+ ****************************************************************************/
+
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub)
+{
+  FAR fmsynth_sound_t *s = top;
+
+  if (!top || !sub)
+    {
+      return ERROR;
+    }
+
+  for (s = top; s->next_sound; s = s->next_sound);
+  s->next_sound = sub;
+
+  return OK;
+}
+
+/****************************************************************************
+ * name: fmsynth_rendering
+ ****************************************************************************/
+
+int fmsynth_rendering(FAR fmsynth_sound_t *snd,
+                      FAR int16_t *sample, int sample_num, int chnum,
+                      FAR fmsynth_tickcb_t cb, unsigned long cbarg)
+{
+  int i;
+  int ch;
+  int out;
+  FAR fmsynth_sound_t *itr;
+
+  for (i = 0; i < sample_num; i += chnum)
+    {
+      out = 0;
+      itr = snd;
+      while (itr)
+        {
+          out = out + sound_modulate(itr);
+          itr = itr->next_sound;
+        }
+
+      for (ch = 0; ch < chnum; ch++)
+        {
+          *sample++ = (int16_t)out;
+        }
+
+      if (cb)

Review Comment:
   Optional
   ```suggestion
         if (cb != NULL)
   ```



##########
include/audioutils/fmsynth.h:
##########
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * apps/include/audioutils/fmsynth.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 __INCLUDE_AUDIOUTILS_FMSYNTH_H
+#define __INCLUDE_AUDIOUTILS_FMSYNTH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <limits.h>
+#include <stdint.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FMSYNTH_MAX_VOLUME (SHRT_MAX)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef struct fmsynth_sound_s
+{
+  int phase_time;
+  int max_phase_time;
+  int volume;
+  fmsynth_op_t *operators;
+
+  struct fmsynth_sound_s *next_sound;
+} fmsynth_sound_t;
+
+typedef void (*fmsynth_tickcb_t)(unsigned long cbarg);
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int fmsynth_initialize(int fs);
+FAR fmsynth_sound_t *fmsynthsnd_create(void);
+void fmsynthsnd_delete(FAR fmsynth_sound_t *snd);
+int fmsynthsnd_set_operator(FAR fmsynth_sound_t *snd, FAR fmsynth_op_t *op);
+void fmsynthsnd_set_soundfreq(FAR fmsynth_sound_t *snd, float freq);
+void fmsynthsnd_set_volume(FAR fmsynth_sound_t *snd, float vol);
+int fmsynthsnd_add_subsound(FAR fmsynth_sound_t *top,
+                            FAR fmsynth_sound_t *sub);
+int fmsynth_rendering(FAR fmsynth_sound_t *snd,
+                      FAR int16_t *sample, int sample_num, int chnum,
+                      FAR fmsynth_tickcb_t cb, unsigned long cbarg);

Review Comment:
   ```suggestion
                        fmsynth_tickcb_t cb, unsigned long cbarg);
   ```



##########
include/audioutils/fmsynth_op.h:
##########
@@ -0,0 +1,99 @@
+/****************************************************************************
+ * apps/include/audioutils/fmsynth_op.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_INCLUDE_AUDIOUTILS_FMSYNTH_OP_H
+#define __APPS_INCLUDE_AUDIOUTILS_FMSYNTH_OP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <audioutils/fmsynth_eg.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FMSYNTH_PI (0x10000)
+
+#define FMSYNTH_OPFUNC_SIN      (0)
+#define FMSYNTH_OPFUNC_TRIANGLE (1)
+#define FMSYNTH_OPFUNC_SAWTOOTH (2)
+#define FMSYNTH_OPFUNC_SQUARE   (3)
+#define FMSYNTH_OPFUNC_NUM      (4)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef int (*opfunc_t)(int theta);
+
+typedef struct fmsynth_op_s
+{
+  fmsynth_eg_t  *eg;
+  opfunc_t wavegen;
+  struct fmsynth_op_s *cascadeop;
+  struct fmsynth_op_s *parallelop;
+
+  int *feedback_ref;

Review Comment:
   ```suggestion
     FAR int *feedback_ref;
   ```



##########
include/audioutils/fmsynth_op.h:
##########
@@ -0,0 +1,99 @@
+/****************************************************************************
+ * apps/include/audioutils/fmsynth_op.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_INCLUDE_AUDIOUTILS_FMSYNTH_OP_H
+#define __APPS_INCLUDE_AUDIOUTILS_FMSYNTH_OP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <audioutils/fmsynth_eg.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FMSYNTH_PI (0x10000)
+
+#define FMSYNTH_OPFUNC_SIN      (0)
+#define FMSYNTH_OPFUNC_TRIANGLE (1)
+#define FMSYNTH_OPFUNC_SAWTOOTH (2)
+#define FMSYNTH_OPFUNC_SQUARE   (3)
+#define FMSYNTH_OPFUNC_NUM      (4)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef int (*opfunc_t)(int theta);
+
+typedef struct fmsynth_op_s
+{
+  fmsynth_eg_t  *eg;

Review Comment:
   FAR



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#issuecomment-1217261870

   Hi @acassis , I belive it works on other boards supporting audio, because no spresense specific code in it. But I didn't test it on them because I don't have. At least I did unit test on linux (those code is in this PR in audioutils/fmsynth/test) and it works well.
   
   fmsynth is just making audio samples. So even if the board has no audio function, it works.
   nxaudio is an utility library for nuttx audio driver. So every boards supporting audio can works.
   
   But, I dare say, it is depending on cpu performance. fmsynth is calculating every single sample. (It is the reason that I didn't use sinf() function of regular math library.)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#issuecomment-1217287241

   @pkarashchenko 
   Thank you for your review.
   I modified. Please check it again.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r947324582


##########
audioutils/fmsynth/test/fmsynth_alsa_test.c:
##########
@@ -0,0 +1,324 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_alsa_test.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 <stdio.h>
+#include <stdint.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+
+#define CHANNEL_NUM (2)
+#define RESAMPLING_ALSA (1)
+#define LATENCY_ALSA (10000)
+
+#define SAMPLE_NUM (FS / 20)
+#define BUFF_LENGTH (SAMPLE_NUM * CHANNEL_NUM)
+
+#define CODE_C_FREQ (261.625565f)
+#define CODE_D_FREQ (293.6647674f)
+#define CODE_E_FREQ (329.6275561f)
+#define CODE_F_FREQ (349.2282305f)
+#define CODE_G_FREQ (391.9954347f)
+#define CODE_A_FREQ (440.f)
+#define CODE_B_FREQ (493.8833009f)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t samples[BUFF_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: init_alsa
+ ****************************************************************************/
+
+static snd_pcm_t *init_alsa(int fs)
+{
+  int ret;
+  snd_pcm_t *hndl = NULL;

Review Comment:
   This code is just for unit testing on linux.
   So I don't think it needs "FAR".



##########
audioutils/fmsynth/test/fmsynth_alsa_test.c:
##########
@@ -0,0 +1,324 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_alsa_test.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 <stdio.h>
+#include <stdint.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+
+#define CHANNEL_NUM (2)
+#define RESAMPLING_ALSA (1)
+#define LATENCY_ALSA (10000)
+
+#define SAMPLE_NUM (FS / 20)
+#define BUFF_LENGTH (SAMPLE_NUM * CHANNEL_NUM)
+
+#define CODE_C_FREQ (261.625565f)
+#define CODE_D_FREQ (293.6647674f)
+#define CODE_E_FREQ (329.6275561f)
+#define CODE_F_FREQ (349.2282305f)
+#define CODE_G_FREQ (391.9954347f)
+#define CODE_A_FREQ (440.f)
+#define CODE_B_FREQ (493.8833009f)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t samples[BUFF_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: init_alsa
+ ****************************************************************************/
+
+static snd_pcm_t *init_alsa(int fs)
+{
+  int ret;
+  snd_pcm_t *hndl = NULL;
+
+  ret = snd_pcm_open(&hndl, "default", SND_PCM_STREAM_PLAYBACK, 0);
+  if (ret < 0)
+    {
+      printf("sdn_pcm_open error\n");
+      return NULL;
+    }
+
+  ret = snd_pcm_set_params(hndl,
+                           SND_PCM_FORMAT_S16,
+                           SND_PCM_ACCESS_RW_INTERLEAVED,
+                           CHANNEL_NUM, fs, RESAMPLING_ALSA, LATENCY_ALSA);
+  if (ret != 0)
+    {
+      printf("sdn_pcm_set_params error\n");
+      snd_pcm_close(hndl);
+      return NULL;
+    }
+
+  return hndl;
+}
+
+/****************************************************************************
+ * name: set_nonblocking
+ ****************************************************************************/
+
+static int set_nonblocking(struct termios *saved)

Review Comment:
   This code is just for unit testing on linux.
   So I don't think it needs "FAR".



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on a diff in pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on code in PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#discussion_r947324696


##########
audioutils/fmsynth/test/fmsynth_test.c:
##########
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * apps/audioutils/fmsynth/test/fmsynth_test.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 <stdio.h>
+#include <stdint.h>
+
+#include <audioutils/fmsynth_eg.h>
+#include <audioutils/fmsynth_op.h>
+#include <audioutils/fmsynth.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FS (48000)
+#define SOUNDFREQ (3000.f)
+#define TEST_LENGTH ((FS / 1000) * (10 + 20 + 16 + 5 + 30))
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int16_t my_sample[TEST_LENGTH];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: set_levels
+ ****************************************************************************/
+
+static fmsynth_eglevels_t *set_levels(fmsynth_eglevels_t *level,
+                                      int atk_lvl, int atk_peri,
+                                      int decbrk_lvl, int decbrk_peri,
+                                      int dec_lvl, int dec_peri,
+                                      int sus_lvl, int sus_peri,
+                                      int rel_lvl, int rel_peri)
+{
+  level->attack.level = atk_lvl;
+  level->attack.period_ms = atk_peri;
+  level->decaybrk.level = decbrk_lvl;
+  level->decaybrk.period_ms = decbrk_peri;
+  level->decay.level = dec_lvl;
+  level->decay.period_ms = dec_peri;
+  level->sustain.level = sus_lvl;
+  level->sustain.period_ms = sus_peri;
+  level->release.level = rel_lvl;
+  level->release.period_ms = rel_peri;
+
+  return level;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * name: main
+ ****************************************************************************/
+
+int main(void)
+{
+  int phase_time;
+
+  fmsynth_eglevels_t levels;
+  fmsynth_sound_t *snd1;
+  fmsynth_op_t *envop;
+  fmsynth_op_t *fbop;

Review Comment:
   This code is just for unit testing on linux.
   So I don't think it needs "FAR".



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] acassis commented on pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
acassis commented on PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#issuecomment-1217187813

   Hi @takayoshik, does it work on other boards that have audio support like stm32f4discovery and raspberrypi pico? Or is it Spresense board only?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#issuecomment-1223939558

   Hi @pkarashchenko 
   Regarding floh_walzer_right and floh_walzer_left is used in mmlplayer_main.c around on line 407.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx-apps] takayoshi-k commented on pull request #1283: Add audiolib fmsynthesizer

Posted by GitBox <gi...@apache.org>.
takayoshi-k commented on PR #1283:
URL: https://github.com/apache/incubator-nuttx-apps/pull/1283#issuecomment-1223358968

   Hi @pkarashchenko 
   I hadn't mension to you.
   I updated. Please check it again.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org