Well, the first fruits of my labour.  I have some patches that implement
a tone generator and sound effect sequencer.

This could be useful for implementing the TONE feature, we can also
implement a crude "sweep" function for bandpass testing of rigs.
Frequency accuracy is not super-accurate, but I did try some numbers,
and at worst it seemed to be about 6% off.

The tone generation is fixed-point and the output is unscaled.

With my current builds, I note hitting PTT when in TONE mode immediately
dumps me in the colourful ring of death routine.  We should be able to
use this to perform the same function.

example-usage.diff is an example using the current Subversion head code.
-- 
Stuart Longland (aka Redhatter, VK4MSL)

I haven't lost my mind...
  ...it's backed up on a tape somewhere.
From 37e4cbfa72e54ac61018edd5819f79d126b51d95 Mon Sep 17 00:00:00 2001
From: Stuart Longland <[email protected]>
Date: Fri, 18 Sep 2015 18:29:50 +1000
Subject: [PATCH 1/3] tone: Fixed-point tone generator.

This is a simple fixed-point tone generator.  Most frequencies can be
generated with at most about 6% error, which should be "good enough" for
audio alerts.
---
 stm32/src/tone.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 stm32/src/tone.h |  84 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 198 insertions(+)
 create mode 100644 stm32/src/tone.c
 create mode 100644 stm32/src/tone.h

diff --git a/stm32/src/tone.c b/stm32/src/tone.c
new file mode 100644
index 0000000..7f02fa5
--- /dev/null
+++ b/stm32/src/tone.c
@@ -0,0 +1,114 @@
+/*!
+ * Fixed-point tone generator.
+ *
+ * The code here implements a simple fixed-point tone generator that uses
+ * integer arithmetic to generate a sinusoid at a fixed sample rate of
+ * 16kHz.
+ *
+ * To set the initial state of the state machine, you specify a frequency
+ * and duration using tone_reset.  The corresponding C file embeds a
+ * sinusoid look-up table.  The total number of samples is computed for
+ * the given time and used to initialise 'remain', 'time' is initialised
+ * to 0, and 'step' gives the amount to increment 'time' by each iteration.
+ *
+ * The samples are retrieved by repeatedly calling tone_next.  This
+ * advances 'time' and decrements 'remain'.  The tone is complete when
+ * 'remain' is zero.
+ *
+ * Author Stuart Longland <[email protected]>
+ * Copyright (C) 2015 FreeDV <[email protected]>tors.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1,
+ * as published by the Free Software Foundation.  This program is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "tone.h"
+
+/*! Fixed-point shift factor */
+#define TONE_SHIFT	(12)
+
+/*! Static compiled sinusoid.  Nicked from original FreeDV code. */
+static const int16_t tone_sine[] = {
+     -16,    6384,   12528,   18192,   23200,   27232,   30256,   32128,
+   32752,   32128,   30256,   27232,   23152,   18192,   12528,    6384,
+     -16,   -6416,  -12560,  -18224,  -23184,  -27264,  -30288,  -32160,
+  -32768,  -32160,  -30288,  -27264,  -23184,  -18224,  -12560,   -6416
+};
+
+/*! Length of sinusoid in samples */
+#define TONE_SINE_LEN	(sizeof(tone_sine)/sizeof(tone_sine[0]))
+
+/*!
+ * Re-set the tone generator.
+ *
+ * @param	tone_gen	Tone generator to reset.
+ * @param	freq		Frequency in Hz, 0 = silence.
+ * @param	duration	Duration in milliseconds.  0 to stop.
+ */
+void tone_reset(
+	struct tone_gen_t* const tone_gen,
+	uint16_t freq, uint16_t duration)
+{
+	if (freq)
+		/* Compute the time step */
+		tone_gen->step = (((2*freq*TONE_SINE_LEN) << TONE_SHIFT)
+				/ ((2*TONE_FS) + 1) + 1);
+	else
+		/* DC tone == silence */
+		tone_gen->step = 0;
+
+	/* Compute remaining samples */
+	tone_gen->remain = (uint16_t)(
+			((uint32_t)(TONE_FS * duration)) / 1000);
+
+	/* Initialise the sample counter */
+	tone_gen->sample = 0;
+}
+
+/*!
+ * Retrieve the next sample from the tone generator.
+ * @param	tone_gen	Tone generator to update.
+ */
+int16_t tone_next(
+	struct tone_gen_t* const tone_gen)
+{
+	if (!tone_gen)
+		return 0;
+	if (!tone_gen->remain)
+		return 0;
+	if (!tone_gen->step) {
+		/* Special case, emit silence */
+		tone_gen->remain--;
+		return 0;
+	}
+
+	/* Compute sample index */
+	uint16_t sample_int = ((tone_gen->sample) >> TONE_SHIFT)
+				% TONE_SINE_LEN;
+
+	/* Advance tone generator state */
+	tone_gen->sample += tone_gen->step;
+	tone_gen->remain--;
+
+	return tone_sine[sample_int];
+}
+
+/*!
+ * Retrieve the current time in milliseconds.
+ */
+uint32_t tone_msec(const struct tone_gen_t* const tone_gen)
+{
+	uint64_t ms = tone_gen->sample;
+	ms *= 1000;
+	ms /= TONE_FS;
+	return ms >> TONE_SHIFT;
+}
diff --git a/stm32/src/tone.h b/stm32/src/tone.h
new file mode 100644
index 0000000..a8ed89a
--- /dev/null
+++ b/stm32/src/tone.h
@@ -0,0 +1,84 @@
+#ifndef _TONE_H
+#define _TONE_H
+/*!
+ * Fixed-point tone generator.
+ *
+ * The code here implements a simple fixed-point tone generator that uses
+ * integer arithmetic to generate a sinusoid at a fixed sample rate of
+ * 16kHz.
+ *
+ * To set the initial state of the state machine, you specify a frequency
+ * and duration using tone_reset.  The corresponding C file embeds a
+ * sinusoid look-up table.  The total number of samples is computed for
+ * the given time and used to initialise 'remain', 'time' is initialised
+ * to 0, and 'step' gives the amount to increment 'time' by each iteration.
+ *
+ * The samples are retrieved by repeatedly calling tone_next.  This
+ * advances 'time' and decrements 'remain'.  The tone is complete when
+ * 'remain' is zero.
+ * 
+ * Author Stuart Longland <[email protected]>
+ * Copyright (C) 2015 FreeDV project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1,
+ * as published by the Free Software Foundation.  This program is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+/*! Tone sampling rate in Hz. */
+#define TONE_FS	16000
+
+/*!
+ * Tone generator state.  This holds the current state of the tone
+ * generator in order to decide what sample to release next.
+ */
+struct tone_gen_t {
+	/*! Current sample.  (Q12) */
+	uint32_t	sample;
+	/*!
+	 * Time remaining in samples. (integer)  Playback is finished
+	 * when this reaches zero.
+	 */
+	uint16_t	remain;
+	/*!
+	 * Subsample step (Q12).  This is the number of samples (or part
+	 * thereof) to advance "sample".  Special case: when zero, sample
+	 * is not advanced, silence is generated instead.
+	 */
+	uint16_t	step;
+};
+
+/*!
+ * Re-set the tone generator.
+ *
+ * @param	tone_gen	Tone generator to reset.
+ * @param	freq		Frequency in Hz, 0 = silence.
+ * @param	duration	Duration in milliseconds.  0 to stop.
+ */
+void tone_reset(
+	struct tone_gen_t* const tone_gen,
+	uint16_t freq, uint16_t duration);
+
+/*!
+ * Retrieve the next sample from the tone generator.
+ * @param	tone_gen	Tone generator to update.
+ */
+int16_t tone_next(
+	struct tone_gen_t* const tone_gen);
+
+/*!
+ * Retrieve the current time in milliseconds.
+ */
+uint32_t tone_msec(const struct tone_gen_t* const tone_gen);
+
+#endif
-- 
2.4.6

From 2faebe381685af46277e16a067d3e76de138ea45 Mon Sep 17 00:00:00 2001
From: Stuart Longland <[email protected]>
Date: Fri, 18 Sep 2015 19:23:30 +1000
Subject: [PATCH 2/3] sfx: Sound effect player state machine.

This is a state machine for playing crude sound effects.  The sound
effects are defined as arrays of type struct sfx_note_t, with the last
note having a duration and frequency of 0.  Durations are given in
milliseconds.

Pauses may be encoded by specifying a frequency of 0.
---
 stm32/src/sfx.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 stm32/src/sfx.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+)
 create mode 100644 stm32/src/sfx.c
 create mode 100644 stm32/src/sfx.h

diff --git a/stm32/src/sfx.c b/stm32/src/sfx.c
new file mode 100644
index 0000000..293522e
--- /dev/null
+++ b/stm32/src/sfx.c
@@ -0,0 +1,67 @@
+/*!
+ * Sound effect player library.
+ *
+ * This implements a state machine for playing back various monophonic
+ * sound effects such as morse code symbols, clicks and alert tones.
+ * 
+ * Author Stuart Longland <[email protected]>
+ * Copyright (C) 2015 FreeDV project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1,
+ * as published by the Free Software Foundation.  This program is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include "sfx.h"
+
+static void sfx_next_tone(struct sfx_player_t* const sfx_player)
+{
+	struct tone_gen_t* tone_gen = &(sfx_player->tone_gen);
+	const struct sfx_note_t* note = sfx_player->note;
+
+	if (!note) {
+		tone_reset(tone_gen, 0, 0);
+	} else {
+		tone_reset(tone_gen, note->freq, note->duration);
+
+		if (!note->duration)
+			/* We are done */
+			sfx_player->note = NULL;
+		else
+			/* Move to next note */
+			sfx_player->note++;
+	}
+}
+
+/*!
+ * Start playing a particular effect.
+ * @param	sfx_player	Effect player state machine
+ * @param	effect		Pointer to sound effect (NULL == stop)
+ */
+void sfx_play(struct sfx_player_t* const sfx_player,
+		const struct sfx_note_t* effect)
+{
+	sfx_player->note = effect;
+	sfx_next_tone(sfx_player);
+}
+
+/*!
+ * Retrieve the next sample to be played.
+ */
+int16_t sfx_next(struct sfx_player_t* const sfx_player)
+{
+	if (!sfx_player)
+		return(0);
+	if (!sfx_player->tone_gen.remain)
+		sfx_next_tone(sfx_player);
+	return tone_next(&(sfx_player->tone_gen));
+}
diff --git a/stm32/src/sfx.h b/stm32/src/sfx.h
new file mode 100644
index 0000000..3ac8d5a
--- /dev/null
+++ b/stm32/src/sfx.h
@@ -0,0 +1,63 @@
+#ifndef _SFX_H
+#define _SFX_H
+/*!
+ * Sound effect player library.
+ *
+ * This implements a state machine for playing back various monophonic
+ * sound effects such as morse code symbols, clicks and alert tones.
+ * 
+ * Author Stuart Longland <[email protected]>
+ * Copyright (C) 2015 FreeDV project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1,
+ * as published by the Free Software Foundation.  This program is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "tone.h"
+
+/*!
+ * A sound effect "note"
+ */
+struct sfx_note_t {
+	/*! Note frequency.  0 == pause */
+	uint16_t	freq;
+	/*! Note duration in msec.   0 == end of effect */
+	uint16_t	duration;
+};
+
+/*!
+ * Sound effect player state machine
+ */
+struct sfx_player_t {
+	/*!
+	 * Pointer to the current "note".  When this is NULL,
+	 * playback is complete.
+	 */
+	const struct sfx_note_t*	note;
+	/*! Tone generator state machine */
+	struct tone_gen_t		tone_gen;
+};
+
+/*!
+ * Start playing a particular effect.
+ * @param	sfx_player	Effect player state machine
+ * @param	effect		Pointer to sound effect (NULL == stop)
+ */
+void sfx_play(struct sfx_player_t* const sfx_player,
+		const struct sfx_note_t* effect);
+
+/*!
+ * Retrieve the next sample to be played.
+ */
+int16_t sfx_next(struct sfx_player_t* const sfx_player);
+
+#endif
-- 
2.4.6

From 1f67bdcbe8da0f1a2707a1f041acd890530eb512 Mon Sep 17 00:00:00 2001
From: Stuart Longland <[email protected]>
Date: Fri, 18 Sep 2015 19:25:30 +1000
Subject: [PATCH 3/3] sounds: Add some sound effects.

This gives us two sound effects, one is a sequence of 3 beeps that I've
been using as a start-up sound for testing (it also hides an awkward
squawk).

The other is a very short "bip" noise that can be used when selecting
menu items.
---
 stm32/src/sounds.c | 36 ++++++++++++++++++++++++++++++++++++
 stm32/src/sounds.h | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)
 create mode 100644 stm32/src/sounds.c
 create mode 100644 stm32/src/sounds.h

diff --git a/stm32/src/sounds.c b/stm32/src/sounds.c
new file mode 100644
index 0000000..b79b641
--- /dev/null
+++ b/stm32/src/sounds.c
@@ -0,0 +1,36 @@
+/*!
+ * Sound effect library.
+ *
+ * This provides some sound effects for the SM1000 UI.
+ * 
+ * Author Stuart Longland <[email protected]>
+ * Copyright (C) 2015 FreeDV project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1,
+ * as published by the Free Software Foundation.  This program is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "sounds.h"
+
+/*! Start-up tune */
+struct sfx_note_t sound_startup[] = {
+	{.freq = 600, .duration = 80},
+	{.freq = 800, .duration = 80},
+	{.freq = 1000, .duration = 80},
+	{.freq = 0, .duration = 0}
+};
+
+/*! Click sound */
+struct sfx_note_t sound_click[] = {
+	{.freq = 1200, .duration = 10},
+	{.freq = 0, .duration = 0}
+};
diff --git a/stm32/src/sounds.h b/stm32/src/sounds.h
new file mode 100644
index 0000000..a2e8a01
--- /dev/null
+++ b/stm32/src/sounds.h
@@ -0,0 +1,32 @@
+#ifndef _SOUNDS_H
+#define _SOUNDS_H
+/*!
+ * Sound effect library.
+ *
+ * This provides some sound effects for the SM1000 UI.
+ * 
+ * Author Stuart Longland <[email protected]>
+ * Copyright (C) 2015 FreeDV project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1,
+ * as published by the Free Software Foundation.  This program is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "sfx.h"
+
+/*! Start-up tune */
+extern struct sfx_note_t sound_startup[];
+
+/*! Click sound */
+extern struct sfx_note_t sound_click[];
+
+#endif
-- 
2.4.6

diff --git a/stm32/src/sm1000_main.c b/stm32/src/sm1000_main.c
index 7bfa83a..d16fe33 100644
--- a/stm32/src/sm1000_main.c
+++ b/stm32/src/sm1000_main.c
@@ -37,6 +37,9 @@
 #include <stm32f4xx_gpio.h>
 #include <stdlib.h>
 
+#include "sfx.h"
+#include "sounds.h"
+
 #define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES)
 
 #define FIFTY_MS  50
@@ -57,6 +60,8 @@ typedef struct {
 
 unsigned int downTicker;
 
+struct sfx_player_t sfx_player;
+
 void SysTick_Handler(void);
 void iterate_select_state_machine(SWITCH_STATE *ss);
 
@@ -105,6 +110,9 @@ int main(void) {
     for(i=0; i<FDMDV_OS_TAPS_8K; i++)
         dac8k[i] = 0.0;
 
+    /* play a start-up tune. */
+    sfx_play(&sfx_player, sound_startup);
+
     ss.state = SS_IDLE;
     ss.mode  = ANALOG;
 
@@ -112,7 +120,17 @@ int main(void) {
 
         iterate_select_state_machine(&ss);
 
-        if (switch_ptt() || (ext_ptt() == 0)) {
+        if (sfx_player.note) {
+            int samples = 0;
+            for (i=0; i < n_samples_16k; i++) {
+                dac16k[i] = sfx_next(&sfx_player);
+                samples++;
+                if (!sfx_player.note)
+                    break;
+            }
+            dac2_write(dac16k, samples);
+        }
+        else if (switch_ptt() || (ext_ptt() == 0)) {
 
             /* Transmit -------------------------------------------------------------------------*/
 
@@ -226,6 +244,7 @@ void iterate_select_state_machine(SWITCH_STATE *ss) {
         case SS_DEBOUNCE_DOWN:
             if (downTicker == 0) {
                 ss->mode++;
+                sfx_play(&sfx_player, sound_click);
                 if (ss->mode >= MAX_MODES)
                     ss->mode = 0;
                 next_state = SS_WAIT_BUTTON_UP;

Attachment: signature.asc
Description: OpenPGP digital signature

------------------------------------------------------------------------------
_______________________________________________
Freetel-codec2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freetel-codec2

Reply via email to