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

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


The following commit(s) were added to refs/heads/master by this push:
     new b39228cd4 !examples/audio_rtttl: Implement example using RTTTL library
b39228cd4 is described below

commit b39228cd41ed882bbaa0e62cdacccd4afea93790
Author: Matteo Golin <[email protected]>
AuthorDate: Sat Jul 11 19:31:00 2026 -0400

    !examples/audio_rtttl: Implement example using RTTTL library
    
    This commit fixes the audio_rtttl example (which was undocumented and
    previously used kernel-level functions) such that now it uses the RTTTL
    parsing library. Contributors can implement 'players' for different
    types of audio sinks. Currently, PWM is supported.
    
    BREAKING: The previous version of this example only supported a single
    board (Spresense) and uses public interfaces from the kernel code. Now
    it only uses user-space interfaces and supports any board implementing
    those interfaces. Users who relied on the old behaviour should submit a
    patch to add a new player to this application which uses the desired
    audio sink for the Spresense through user-space interfaces.
    
    Signed-off-by: Matteo Golin <[email protected]>
---
 examples/audio_rttl/CMakeLists.txt    |   2 +-
 examples/audio_rttl/Kconfig           |  12 +-
 examples/audio_rttl/Makefile          |   2 +-
 examples/audio_rttl/audio_rttl.cxx    | 361 ----------------------------------
 examples/audio_rttl/audio_rttl.h      |  24 ---
 examples/audio_rttl/audio_rttl_main.c | 305 ++++++++++++++++++++++++++++
 include/.gitignore                    |   1 +
 7 files changed, 319 insertions(+), 388 deletions(-)

diff --git a/examples/audio_rttl/CMakeLists.txt 
b/examples/audio_rttl/CMakeLists.txt
index ec7709bd3..3553cfec6 100644
--- a/examples/audio_rttl/CMakeLists.txt
+++ b/examples/audio_rttl/CMakeLists.txt
@@ -29,5 +29,5 @@ if(CONFIG_EXAMPLES_AUDIO_SOUND)
     STACKSIZE
     ${CONFIG_EXAMPLES_AUDIO_SOUND_STACKSIZE}
     SRCS
-    audio_rttl.cxx)
+    audio_rttl_main.c)
 endif()
diff --git a/examples/audio_rttl/Kconfig b/examples/audio_rttl/Kconfig
index 2dae260b0..3a594e867 100644
--- a/examples/audio_rttl/Kconfig
+++ b/examples/audio_rttl/Kconfig
@@ -5,9 +5,11 @@
 
 config EXAMPLES_AUDIO_SOUND
        bool "Audio tone generator example (RTTL player)"
+       depends on AUDIO
+       depends on AUDIOUTILS_RTTTL_C
        default n
        ---help---
-               Enable the audio RTTL player example
+               Enable the audio RTTL player example.
 
 if EXAMPLES_AUDIO_SOUND
 
@@ -23,4 +25,12 @@ config EXAMPLES_AUDIO_SOUND_STACKSIZE
        int "Audio sound stack size"
        default DEFAULT_TASK_STACKSIZE
 
+comment "Program options"
+
+config EXAMPLES_AUDIO_SOUND_MAXLEN
+       int "Maximum RTTL string length"
+       default 256
+       ---help---
+               The maximum length of an RTTL string that can be read from a 
file.
+
 endif
diff --git a/examples/audio_rttl/Makefile b/examples/audio_rttl/Makefile
index 1816513a7..b2a4630b3 100644
--- a/examples/audio_rttl/Makefile
+++ b/examples/audio_rttl/Makefile
@@ -30,6 +30,6 @@ STACKSIZE = $(CONFIG_EXAMPLES_AUDIO_SOUND_STACKSIZE)
 
 # Audio Example
 
-MAINSRC = audio_rttl.cxx
+MAINSRC = audio_rttl_main.c
 
 include $(APPDIR)/Application.mk
diff --git a/examples/audio_rttl/audio_rttl.cxx 
b/examples/audio_rttl/audio_rttl.cxx
deleted file mode 100644
index 3533258c1..000000000
--- a/examples/audio_rttl/audio_rttl.cxx
+++ /dev/null
@@ -1,361 +0,0 @@
-/****************************************************************************
- * apps/examples/audio_rttl/audio_rttl.cxx
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * 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 <math.h>
-#include <string.h>
-#include <arch/board/board.h>
-#include <arch/chip/audio.h>
-
-#include "audio_rttl.h"
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* Note - note freq on octave 1 */
-
-#define C 16.35
-#define CD 17.32
-#define D 18.35
-#define DE 19.45
-#define E 20.60
-#define F 21.83
-#define FG 23.12
-#define G 24.50
-#define A 27.50
-#define AB 29.14
-#define B 30.84
-
-/* Octave - base freq multiplier for the base freq */
-
-#define OCT2 4
-#define OCT3 8
-#define OCT4 16
-#define OCT5 32
-#define OCT6 64
-#define OCT7 128
-#define OCT8 256
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-extern "C" int main(int argc, FAR char *argv[])
-{
-  int freq;
-  float base_freq;
-  char temp_note;
-  int octave;
-  int duration;
-  int note_duration;
-  int base_duration;
-  int bpm;
-  int cnt;
-
-  /* Set I/O parameters for power on. */
-
-  if (!board_audio_power_control(true))
-    {
-      printf("Error: board_audio_power_control() failure.\n");
-      return 1;
-    }
-
-  printf("Start Audio RTTL player\n");
-
-  bpm = 0;
-  octave = 0;
-  base_duration = 0;
-  note_duration = 0;
-
-  while (*g_song != ':')
-    {
-      g_song++;
-    }
-
-  g_song++;
-
-  if (*g_song == 'd')
-    {
-      g_song = g_song + 2;
-      base_duration = *g_song - '0';
-      g_song++;
-      if ((*g_song >= '0') && (*g_song <= '9'))
-        {
-          base_duration = (base_duration * 10) + (*g_song - '0');
-          g_song++;
-        }
-
-      g_song++;
-    }
-
-  if (*g_song == 'o')
-    {
-      g_song = g_song + 2;
-      octave = *g_song - '0';
-      g_song = g_song + 2;
-    }
-
-  if (octave == 2)
-    {
-      octave = OCT2;
-    }
-  else if (octave == 3)
-    {
-      octave = OCT3;
-    }
-  else if (octave == 4)
-    {
-      octave = OCT4;
-    }
-  else if (octave == 5)
-    {
-      octave = OCT5;
-    }
-  else if (octave == 6)
-    {
-      octave = OCT6;
-    }
-  else if (octave == 7)
-    {
-      octave = OCT7;
-    }
-  else if (octave == 8)
-    {
-      octave = OCT8;
-    }
-
-  if (*g_song == 'b')
-    {
-      g_song = g_song + 2;
-      bpm = 0;
-      for (cnt = 1; cnt <= 3; cnt++)
-        {
-          if (*g_song != ':')
-            {
-              bpm = bpm * 10 + (*g_song - '0');
-              g_song++;
-            }
-
-        }
-
-      g_song++;
-    }
-
-  do
-    {
-      if ((*g_song >= '0') && (*g_song <= '9'))
-        {
-          note_duration = *g_song - '0';
-          g_song++;
-        }
-
-      if ((*g_song >= '0') && (*g_song <= '9'))
-        {
-          note_duration = (note_duration * 10) + (*g_song - '0');
-          g_song++;
-        }
-
-      if (note_duration > 0)
-        {
-          duration = ((60 * 1000L / bpm) * 4) / note_duration;
-        }
-      else
-        {
-          duration = ((60 * 1000L / bpm) * 4) / base_duration;
-        }
-
-      base_freq = 0;
-      temp_note = ' ';
-      switch (*g_song)
-        {
-        case 'c':
-          {
-            temp_note = 'c';
-            base_freq = C;
-            break;
-          }
-
-        case 'd':
-          {
-            temp_note = 'd';
-            base_freq = D;
-            break;
-          }
-
-        case 'e':
-          {
-            temp_note = 'e';
-            base_freq = E;
-            break;
-          }
-
-        case 'f':
-          {
-            temp_note = 'f';
-            base_freq = F;
-            break;
-          }
-
-        case 'g':
-          {
-            temp_note = 'g';
-            base_freq = G;
-            break;
-          }
-
-        case 'a':
-          {
-            temp_note = 'a';
-            base_freq = A;
-            break;
-          }
-
-        case 'b':
-          {
-            temp_note = 'b';
-            base_freq = B;
-            break;
-          }
-
-        case 'p':
-          {
-            temp_note = 'p';
-            break;
-          }
-
-        default:
-          break;
-        }
-
-      g_song++;
-
-      if (*g_song == '.')
-        {
-          duration += duration / 2;
-          g_song++;
-        }
-
-      if (*g_song == '#')
-        {
-          if (temp_note == 'c')
-            {
-              base_freq = CD;
-            }
-
-          if (temp_note == 'd')
-            {
-              base_freq = DE;
-            }
-
-          if (temp_note == 'f')
-            {
-              base_freq = FG;
-            }
-
-          if (temp_note == 'a')
-            {
-              base_freq = AB;
-            }
-
-          g_song++;
-        }
-
-      if ((*g_song - '0') == '2')
-        {
-          octave = OCT2;
-        }
-
-      if ((*g_song - '0') == '3')
-        {
-          octave = OCT3;
-        }
-
-      if ((*g_song - '0') == '4')
-        {
-          octave = OCT4;
-        }
-
-      if ((*g_song - '0') == '5')
-        {
-          octave = OCT5;
-        }
-
-      if ((*g_song - '0') == '6')
-        {
-          octave = OCT6;
-        }
-
-      if ((*g_song - '0') == '7')
-        {
-          octave = OCT7;
-        }
-
-      if ((*g_song - '0') == '8')
-        {
-          octave = OCT8;
-        }
-
-      g_song++;
-
-      if (*g_song == ',')
-        {
-          g_song++;
-        }
-
-      /* play the sound */
-
-      freq = ceil(base_freq * octave);
-
-      if (!board_audio_tone_generator(1, -40, freq))
-        {
-          break;
-        }
-
-      usleep(duration * 1000L);
-    }
-  while (*g_song);
-
-  /* Sound off. */
-
-  if (!board_audio_tone_generator(0, 0, 0))
-    {
-      printf("Error: board_audio_tone_generator() failure.\n");
-      return 1;
-    }
-
-  /* Set I/O parameters for power off. */
-
-  if (!board_audio_power_control(false))
-    {
-      printf("Error: board_audio_power_control() failure.\n");
-      return 1;
-    }
-
-  printf("Done.\n");
-
-  return 0;
-}
diff --git a/examples/audio_rttl/audio_rttl.h b/examples/audio_rttl/audio_rttl.h
deleted file mode 100644
index 41c5386d3..000000000
--- a/examples/audio_rttl/audio_rttl.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/****************************************************************************
- * apps/examples/audio_rttl/audio_rttl.h
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * 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.
- *
- ****************************************************************************/
-
-FAR char *g_song = (FAR char *)
-  "Test:d=4,o=6,b=90:c,c#,d,d#,e,f,f#,g,a,a#,b,p,b,a#,a,g,f#,f,e,d#,d,c#,c";
diff --git a/examples/audio_rttl/audio_rttl_main.c 
b/examples/audio_rttl/audio_rttl_main.c
new file mode 100644
index 000000000..5e9e7e960
--- /dev/null
+++ b/examples/audio_rttl/audio_rttl_main.c
@@ -0,0 +1,305 @@
+/****************************************************************************
+ * apps/examples/audio_rttl/audio_rttl_main.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 <fcntl.h>
+#include <getopt.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+
+#ifdef CONFIG_PWM
+#include <nuttx/timers/pwm.h>
+#endif
+
+#include <audioutils/rtttl.h>
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct player_s
+{
+  void (*play)(struct rtttl_tone); /* Play RTTTL sound function */
+  void (*teardown)(void);          /* Clean-up function */
+  void *arg;                       /* Private data for functions */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Default song if none was passed. Otherwise, used as buffer for reading
+ * from a file.
+ */
+
+static char g_default_song[CONFIG_EXAMPLES_AUDIO_SOUND_MAXLEN] =
+    "Test:d=4,o=6,b=90:c,c#,d,d#,e,f,f#,g,a,a#,b,p,b,a#,a,g,"
+    "f#,f,e,d#,d,c#,c";
+
+/* The selected player is a global variable so it can be accessed from within
+ * the player functions properly.
+ */
+
+static struct player_s g_player;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: play_default
+ *
+ * Description:
+ *   The default player choice; prints an error and exits.
+ *
+ * Input Parameters:
+ *   sound - The sound to play
+ *
+ ****************************************************************************/
+
+static void play_default(struct rtttl_tone sound)
+{
+  fprintf(stderr, "No player selected!\n");
+  return;
+}
+
+/****************************************************************************
+ * Name: teardown_default
+ *
+ * Description:
+ *   Default tear-down function. Does nothing.
+ *
+ ****************************************************************************/
+
+static void teardown_default(void)
+{
+  /* No-op */
+
+  return;
+}
+
+#ifdef CONFIG_PWM
+
+/****************************************************************************
+ * Name: play_pwm
+ *
+ * Description:
+ *   RTTTL player for audio sinks using PWM devices
+ *
+ * Input Parameters:
+ *   sound - The sound to play
+ *
+ ****************************************************************************/
+
+static void play_pwm(struct rtttl_tone sound)
+{
+  int err;
+  int i;
+  struct pwm_info_s info;
+  int fd = *((int *)g_player.arg);
+
+  info.channels[0].channel = 1;
+  info.channels[0].duty = b16divi(uitoub16(50) - 1, 100); /* 50% duty cycle */
+  info.channels[0].cpol = PWM_CPOL_NDEF;                  /* Default */
+  info.channels[0].dcpol = PWM_DCPOL_NDEF;                /* Default */
+  info.frequency = sound.frequency_100hz / 100;
+
+  /* Copy settings to all channels */
+
+  for (i = 1; i < CONFIG_PWM_NCHANNELS; i++)
+    {
+      info.channels[i] = info.channels[0];
+      info.channels[i].channel = i + 1;
+    }
+
+  err = ioctl(fd, PWMIOC_SETCHARACTERISTICS, &info);
+  if (err < 0)
+    {
+      fprintf(stderr, "Failed to set PWM characteristics: %d\n", errno);
+      return;
+    }
+
+  err = ioctl(fd, PWMIOC_START, 0);
+  if (err < 0)
+    {
+      fprintf(stderr, "Failed to start PWM: %d\n", errno);
+      return;
+    }
+
+  usleep(sound.duration_us); /* Wait */
+
+  err = ioctl(fd, PWMIOC_STOP, 0);
+  if (err < 0)
+    {
+      fprintf(stderr, "Failed to stop PWM: %d\n", errno);
+    }
+}
+
+/****************************************************************************
+ * Name: teardown_pwm
+ *
+ * Description:
+ *   Teardown function for PWM players
+ *
+ ****************************************************************************/
+
+static void teardown_pwm(void)
+{
+  int fd = *((int *)g_player.arg);
+  close(fd);
+}
+#endif /* CONFIG_PWM */
+
+/****************************************************************************
+ * Name: print_usage
+ *
+ * Description:
+ *   Prints out the usage information for the program.
+ *
+ * Input Parameters:
+ *   sink - The stream to output the usage information
+ *
+ ****************************************************************************/
+
+static void print_usage(FILE *sink)
+{
+  fprintf(sink, "USAGE: audio_rttl <device path> [-s string] [-f file]\n");
+  fprintf(sink, "Ex: audio_rttl /dev/tone0\n");
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  int err;
+  int fd;
+  int c;
+  FILE *fptr;
+  size_t bread;
+  const char *song = g_default_song;
+  const char *device = NULL;
+  const char *file = NULL;
+
+  g_player.play = play_default;
+  g_player.teardown = teardown_default;
+  g_player.arg = NULL;
+
+  while ((c = getopt(argc, argv, ":hs:f:")) != -1)
+    {
+      switch (c)
+        {
+        case 'h':
+          print_usage(stdout);
+          break;
+        case 's':
+          song = optarg;
+          break;
+        case 'f':
+          file = optarg;
+          break;
+        case '?':
+          fprintf(stderr, "Unknown option -%c\n", optopt);
+          print_usage(stderr);
+          return EXIT_FAILURE;
+        }
+    }
+
+  if (argc <= optind)
+    {
+      fprintf(stderr, "Missing argument for device path.\n");
+      return EXIT_FAILURE;
+    }
+
+  device = argv[optind++];
+
+  /* Based on the device path, we choose which player should be used and
+   * perform the setup.
+   */
+
+#ifdef CONFIG_PWM
+  if (strstr(device, "pwm"))
+    {
+      fd = open(device, O_RDWR);
+      if (fd < 0)
+        {
+          fprintf(stderr, "Failed to open %s: %d\n", device, errno);
+          return EXIT_FAILURE;
+        }
+      else
+        {
+          g_player.arg = &fd;
+        }
+
+      g_player.play = play_pwm;
+      g_player.teardown = teardown_pwm;
+    }
+#endif /* CONFIG_PWM */
+
+  /* If the user passed a file and a song string, use the string. Otherwise,
+   * read from the file
+   */
+
+  if (file != NULL && song == g_default_song)
+    {
+      fptr = fopen(file, "r");
+      if (fptr == NULL)
+        {
+          fprintf(stderr, "Couldn't open file '%s': %d", file, errno);
+          g_player.teardown();
+          return EXIT_FAILURE;
+        }
+
+      bread =
+          fread(g_default_song, sizeof(char), sizeof(g_default_song), fptr);
+
+      /* Ensure null termination of the string. */
+
+      if (bread <= sizeof(g_default_song))
+        {
+          g_default_song[bread - 1] = '\0';
+        }
+
+      fclose(fptr);
+    }
+
+  /* Play the song */
+
+  err = rtttl_play(song, g_player.play);
+  if (err != 0)
+    {
+      fprintf(stderr, "Failed to play song: %d\n", err);
+      return err;
+    }
+
+  /* Tear down the player and exit */
+
+  g_player.teardown();
+  return EXIT_SUCCESS;
+}
diff --git a/include/.gitignore b/include/.gitignore
index 9d6149edc..1c2896091 100644
--- a/include/.gitignore
+++ b/include/.gitignore
@@ -1,2 +1,3 @@
 /netutils/cJSON.h
 /netutils/cJSON_Utils.h
+/audioutils/rtttl.h

Reply via email to