[RFC 1/1] sound: allow waveform selection
Heinrich Schuchardt
heinrich.schuchardt at canonical.com
Mon Dec 5 01:38:41 CET 2022
* Allow the sound command to select the sine or the square waveform.
* Allow to play multiple tones with one command.
* Adjust documentation.
* Adjust unit test.
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt at canonical.com>
---
This would be the alternative to
[v2,6/7] sound: add CONFIG_SOUND_SINE symbol
For testing with the sandbox remove this line
arch/sandbox/dts/test.dts:969
sandbox,silent; /* Don't emit sounds while testing */
run the sand box with './u-boot -T' and issue the following commands
sound play
sound play -s
sound play -s 600 500 -q
sound play -s 500 1047 500 880 500 0 500 1047 500 880 500 0 500 784 500 698 500 784 1000 698
Listening to the output demonstrates why patch 7/7 is needed.
---
arch/sandbox/include/asm/test.h | 7 ++++
cmd/sound.c | 60 ++++++++++++++++++++++++++-------
doc/usage/cmd/sound.rst | 28 ++++++++++++++-
drivers/sound/sandbox.c | 7 ++++
drivers/sound/sound-uclass.c | 19 +++++++++--
include/sound.h | 21 +++++++++---
test/dm/sound.c | 45 ++++++++++++++++---------
7 files changed, 151 insertions(+), 36 deletions(-)
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 568738c16d..199a38f57e 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -188,6 +188,13 @@ int sandbox_get_setup_called(struct udevice *dev);
*/
int sandbox_get_sound_active(struct udevice *dev);
+/**
+ * sandbox_reset_sound_count() - reset sound data count and sum
+ *
+ * @dev: device to reset
+ */
+void sandbox_reset_sound_count(struct udevice *dev);
+
/**
* sandbox_get_sound_count() - Read back the count of the sound data so far
*
diff --git a/cmd/sound.c b/cmd/sound.c
index 20ac3f758e..d1724e0b7c 100644
--- a/cmd/sound.c
+++ b/cmd/sound.c
@@ -39,26 +39,56 @@ static int do_play(struct cmd_tbl *cmdtp, int flag, int argc,
int ret = 0;
int msec = 1000;
int freq = 400;
-
- if (argc > 1)
- msec = dectoul(argv[1], NULL);
- if (argc > 2)
- freq = dectoul(argv[2], NULL);
+ enum sound_waveform waveform = SOUND_SQUARE;
+ bool first = true;
ret = uclass_first_device_err(UCLASS_SOUND, &dev);
- if (!ret)
- ret = sound_beep(dev, msec, freq);
- if (ret) {
- printf("Sound device failed to play (err=%d)\n", ret);
- return CMD_RET_FAILURE;
+ if (ret)
+ goto err;
+
+ --argc;
+ ++argv;
+ while (argc || first) {
+ first = false;
+ if (argc && *argv[0] == '-') {
+ switch (argv[0][1]) {
+ case 'q':
+ waveform = SOUND_SQUARE;
+ break;
+ case 's':
+ waveform = SOUND_SINE;
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+ --argc;
+ ++argv;
+ }
+ if (argc && *argv[0] != '-') {
+ msec = dectoul(argv[0], NULL);
+ --argc;
+ ++argv;
+ }
+ if (argc && *argv[0] != '-') {
+ freq = dectoul(argv[0], NULL);
+ --argc;
+ ++argv;
+ }
+ ret = sound_beep(dev, msec, freq, waveform);
+ if (ret)
+ goto err;
}
return 0;
+
+err:
+ printf("Sound device failed to play (err=%d)\n", ret);
+ return CMD_RET_FAILURE;
}
static struct cmd_tbl cmd_sound_sub[] = {
U_BOOT_CMD_MKENT(init, 0, 1, do_init, "", ""),
- U_BOOT_CMD_MKENT(play, 2, 1, do_play, "", ""),
+ U_BOOT_CMD_MKENT(play, INT_MAX, 1, do_play, "", ""),
};
/* process sound command */
@@ -83,8 +113,12 @@ static int do_sound(struct cmd_tbl *cmdtp, int flag, int argc,
}
U_BOOT_CMD(
- sound, 4, 1, do_sound,
+ sound, INT_MAX, 1, do_sound,
"sound sub-system",
"init - initialise the sound driver\n"
- "sound play [len [freq]] - play a sound for len ms at freq Hz\n"
+ "sound play [[[-q|-s] len [freq]] ...] - play a sound\n"
+ " -q - square waveform\n"
+ " -s - sine waveform\n"
+ " len - duration in ms\n"
+ " freq - frequency in Hz\n"
);
diff --git a/doc/usage/cmd/sound.rst b/doc/usage/cmd/sound.rst
index d3fac243b1..03e3a2de78 100644
--- a/doc/usage/cmd/sound.rst
+++ b/doc/usage/cmd/sound.rst
@@ -10,7 +10,7 @@ Synopsis
::
sound init
- sound play [len [freq]]
+ sound play [[[-q|-s] len [freq]] ...]
Description
-----------
@@ -24,12 +24,38 @@ sound play
plays a square wave sound. It does not depend on previously calling
*sound init*.
+-q
+ generate a square waveform (this is the default)
+
+-s
+ generate a sine waveform
+
len
duration of the sound in ms, defaults to 1000 ms
freq
frequency of the sound in Hz, defaults to 400 Hz
+Examples
+--------
+
+Square wave beep with 400 Hz for 1000 ms::
+
+ sound play
+
+Sine wave beep with 400 Hz for 1000 ms::
+
+ sound play -s
+
+Sine wave beep at 500 Hz for 600 ms followed by square wave beep at 500 Hz
+for 600 ms::
+
+ sound play -s 600 500 -q
+
+Melody played with sine waveform::
+
+ sound play -s 500 1047 500 880 500 0 500 1047 500 880 500 0 500 784 500 698 500 784 1000 698
+
Configuration
-------------
diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c
index c6cbd81fdb..693611fcc8 100644
--- a/drivers/sound/sandbox.c
+++ b/drivers/sound/sandbox.c
@@ -69,6 +69,13 @@ int sandbox_get_sound_active(struct udevice *dev)
return priv->active;
}
+void sandbox_reset_sound_count(struct udevice *dev) {
+ struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+ priv->count = 0;
+ priv->sum = 0;
+}
+
int sandbox_get_sound_count(struct udevice *dev)
{
struct sandbox_sound_priv *priv = dev_get_priv(dev);
diff --git a/drivers/sound/sound-uclass.c b/drivers/sound/sound-uclass.c
index 2ffc4fc7c1..c459b86ef1 100644
--- a/drivers/sound/sound-uclass.c
+++ b/drivers/sound/sound-uclass.c
@@ -66,7 +66,8 @@ int sound_stop_beep(struct udevice *dev)
return ops->stop_beep(dev);
}
-int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
+int sound_beep(struct udevice *dev, int msecs, int frequency_hz,
+ enum sound_waveform waveform)
{
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
struct i2s_uc_priv *i2s_uc_priv;
@@ -99,8 +100,20 @@ int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
return -ENOMEM;
}
- sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size,
- frequency_hz, i2s_uc_priv->channels);
+ switch (waveform) {
+ case SOUND_SINE:
+ sound_create_sine_wave(i2s_uc_priv->samplingrate, data,
+ data_size, frequency_hz,
+ i2s_uc_priv->channels);
+ break;
+ case SOUND_SQUARE:
+ sound_create_square_wave(i2s_uc_priv->samplingrate, data,
+ data_size, frequency_hz,
+ i2s_uc_priv->channels);
+ break;
+ default:
+ return -EINVAL;
+ }
ret = 0;
while (msecs >= 1000) {
diff --git a/include/sound.h b/include/sound.h
index cf9c3e8fb7..be9bdc58bf 100644
--- a/include/sound.h
+++ b/include/sound.h
@@ -19,6 +19,17 @@ struct sound_codec_info {
int i2c_dev_addr;
};
+/**
+ * enum sound_waveform - sound waveform
+ *
+ * @SOUND_SQUARE: square waveform
+ * @SOUND_SINE: sine waveform
+ */
+enum sound_waveform {
+ SOUND_SQUARE,
+ SOUND_SINE,
+};
+
/**
* struct sound_uc_priv - private uclass information about each sound device
*
@@ -125,12 +136,14 @@ int sound_setup(struct udevice *dev);
/**
* play() - Play a beep
*
- * @dev: Sound device
- * @msecs: Duration of beep in milliseconds
- * @frequency_hz: Frequency of the beep in Hertz
+ * @dev: sound device
+ * @msecs: duration of beep in milliseconds
+ * @frequency_hz: frequency of the beep in Hertz
+ * @waveform: waveform
* Return: 0 if OK, -ve on error
*/
-int sound_beep(struct udevice *dev, int msecs, int frequency_hz);
+int sound_beep(struct udevice *dev, int msecs, int frequency_hz,
+ enum sound_waveform waveform);
/**
* sound_start_beep() - Start beeping
diff --git a/test/dm/sound.c b/test/dm/sound.c
index 15d545ab5a..cfa6306527 100644
--- a/test/dm/sound.c
+++ b/test/dm/sound.c
@@ -12,11 +12,19 @@
#include <test/test.h>
#include <asm/test.h>
+
/* Basic test of the sound codec uclass */
static int dm_test_sound(struct unit_test_state *uts)
{
struct sound_uc_priv *uc_priv;
struct udevice *dev;
+ struct test_data {
+ enum sound_waveform waveform;
+ int expected;
+ } test_data[2] = {
+ {SOUND_SQUARE, 4560},
+ {SOUND_SINE, 3494},
+ };
/* check probe success */
ut_assertok(uclass_first_device_err(UCLASS_SOUND, &dev));
@@ -25,21 +33,28 @@ static int dm_test_sound(struct unit_test_state *uts)
ut_asserteq_str("i2s", uc_priv->i2s->name);
ut_asserteq(0, sandbox_get_setup_called(dev));
- ut_assertok(sound_beep(dev, 1, 100));
- ut_asserteq(48, sandbox_get_sound_count(dev));
- ut_asserteq(4560, sandbox_get_sound_sum(dev));
- ut_assertok(sound_beep(dev, 1, 100));
- ut_asserteq(96, sandbox_get_sound_count(dev));
- ut_asserteq(9120, sandbox_get_sound_sum(dev));
- ut_assertok(sound_beep(dev, 1, -100));
- ut_asserteq(144, sandbox_get_sound_count(dev));
- ut_asserteq(9120, sandbox_get_sound_sum(dev));
- ut_assertok(sound_beep(dev, 1, 0));
- ut_asserteq(192, sandbox_get_sound_count(dev));
- ut_asserteq(9120, sandbox_get_sound_sum(dev));
- ut_assertok(sound_beep(dev, 1, INT_MAX));
- ut_asserteq(240, sandbox_get_sound_count(dev));
- ut_asserteq(9120, sandbox_get_sound_sum(dev));
+ for (int i = 0; i < 2; ++i) {
+ int expected = test_data->expected;
+
+ sandbox_reset_sound_count(dev);
+ ut_assertok(sound_beep(dev, 1, 100, test_data->waveform));
+ ut_asserteq(48, sandbox_get_sound_count(dev));
+ ut_asserteq(expected, sandbox_get_sound_sum(dev));
+ ut_assertok(sound_beep(dev, 1, 100, test_data->waveform));
+ ut_asserteq(96, sandbox_get_sound_count(dev));
+ expected *= 2;
+ ut_asserteq(expected, sandbox_get_sound_sum(dev));
+ ut_assertok(sound_beep(dev, 1, -100, test_data->waveform));
+ ut_asserteq(144, sandbox_get_sound_count(dev));
+ ut_asserteq(expected, sandbox_get_sound_sum(dev));
+ ut_assertok(sound_beep(dev, 1, 0, test_data->waveform));
+ ut_asserteq(192, sandbox_get_sound_count(dev));
+ ut_asserteq(expected, sandbox_get_sound_sum(dev));
+ ut_assertok(sound_beep(dev, 1, INT_MAX, test_data->waveform));
+ ut_asserteq(240, sandbox_get_sound_count(dev));
+ ut_asserteq(expected, sandbox_get_sound_sum(dev));
+ }
+
ut_asserteq(false, sandbox_get_sound_active(dev));
return 0;
--
2.37.2
More information about the U-Boot
mailing list