diff --git a/examples/audio_rttl/CMakeLists.txt b/examples/audio_rttl/CMakeLists.txt index ec7709bd3cb..3553cfec61a 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 2dae260b01b..3a594e8671c 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 1816513a7b9..b2a4630b363 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 3533258c1a9..00000000000 --- 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 -#include -#include -#include -#include - -#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 41c5386d308..00000000000 --- 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 00000000000..5e9e7e96027 --- /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 +#include +#include +#include +#include + +#include + +#ifdef CONFIG_PWM +#include +#endif + +#include + +/**************************************************************************** + * 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 [-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 9d6149edcce..1c2896091a8 100644 --- a/include/.gitignore +++ b/include/.gitignore @@ -1,2 +1,3 @@ /netutils/cJSON.h /netutils/cJSON_Utils.h +/audioutils/rtttl.h