mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
!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 <matteo.golin@gmail.com>
This commit is contained in:
parent
3762a64bc6
commit
b39228cd41
7 changed files with 319 additions and 388 deletions
|
|
@ -29,5 +29,5 @@ if(CONFIG_EXAMPLES_AUDIO_SOUND)
|
|||
STACKSIZE
|
||||
${CONFIG_EXAMPLES_AUDIO_SOUND_STACKSIZE}
|
||||
SRCS
|
||||
audio_rttl.cxx)
|
||||
audio_rttl_main.c)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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";
|
||||
305
examples/audio_rttl/audio_rttl_main.c
Normal file
305
examples/audio_rttl/audio_rttl_main.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
1
include/.gitignore
vendored
1
include/.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
/netutils/cJSON.h
|
||||
/netutils/cJSON_Utils.h
|
||||
/audioutils/rtttl.h
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue