Skip to content

Commit

Permalink
lib: tone: Generate tones of differing sample and carrier widths
Browse files Browse the repository at this point in the history
        Update the library to allow tones of 8-, 24- and 32-bit
        samples and 8-, 16 and 32-bit carrier widths to be
        generated.

Signed-off-by: Graham Wacey <[email protected]>
  • Loading branch information
gWacey committed Dec 10, 2024
1 parent a97ba91 commit 33cc0a2
Show file tree
Hide file tree
Showing 3 changed files with 391 additions and 15 deletions.
27 changes: 26 additions & 1 deletion include/tone.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
* @brief Generates one full pulse-code modulation (PCM) period of a tone with the
* given parameters.
*
* @note The returned frequency of the tone is the quotient of the sample_freq_hz
* divided by the tone_freq_hz.
*
* @param tone User provided buffer. Must be large enough to hold
* the generated PCM tone, depending on settings.
* @param tone_size Resulting tone size.
* @param tone_size Resulting tone size in bytes.
* @param tone_freq_hz The desired tone frequency in the range [100..10000] Hz.
* @param smpl_freq_hz Sampling frequency.
* @param amplitude Amplitude in the range [0..1].
Expand All @@ -40,6 +43,28 @@
int tone_gen(int16_t *tone, size_t *tone_size, uint16_t tone_freq_hz, uint32_t smpl_freq_hz,
float amplitude);

/**
* @brief Generates one full pulse-code modulation (PCM) period of a tone with the
* given parameters.
*
* @note The returned frequency of the tone is the quotient of the sample_freq_hz
* divided by the tone_freq_hz.
* @note The routine returns the tone samples left aligned in the carrier.
*
* @param tone User provided buffer. Must be large enough to hold
* the generated PCM tone, depending on settings.
* @param tone_size Resulting tone size in bytes.
* @param tone_freq_hz The desired tone frequency in the range [100..10000] Hz.
* @param sample_freq_hz Sampling frequency.
* @param sample_bits Number of bits to represent a sample (i.e. 8, 16, 24 or 32 bits).
* @param carrier_bits Number of bits to carry a sample (i.e. 8, 16 or 32 bit).
* @param amplitude Amplitude in the range [0..1].
*
* @return 0 if successful, error otherwise.
*/
int tone_gen_size(void *tone, size_t *tone_size, uint16_t tone_freq_hz, uint32_t sample_freq_hz,
uint8_t sample_bits, uint8_t carrier_bits, float amplitude);

/**
* @}
*/
Expand Down
123 changes: 121 additions & 2 deletions lib/tone/tone.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <stdio.h>
#include <arm_math.h>

#define FREQ_LIMIT_LOW 100
#define FREQ_LIMIT_LOW 100
#define FREQ_LIMIT_HIGH 10000

int tone_gen(int16_t *tone, size_t *tone_size, uint16_t tone_freq_hz, uint32_t smpl_freq_hz,
Expand All @@ -31,7 +31,7 @@ int tone_gen(int16_t *tone, size_t *tone_size, uint16_t tone_freq_hz, uint32_t s

uint32_t samples_for_one_period = smpl_freq_hz / tone_freq_hz;

for (uint32_t i = 0; i < samples_for_one_period; i++) {
for (size_t i = 0; i < samples_for_one_period; i++) {
float curr_val = i * 2 * PI / samples_for_one_period;
float32_t res = arm_sin_f32(curr_val);
/* Generate one sine wave */
Expand All @@ -43,3 +43,122 @@ int tone_gen(int16_t *tone, size_t *tone_size, uint16_t tone_freq_hz, uint32_t s

return 0;
}

static int tone_gen_8(int8_t *tone, size_t *tone_size, uint16_t tone_freq_hz, uint32_t smpl_freq_hz,
uint8_t scale, uint32_t max, float amplitude)
{
uint32_t samples_for_one_period = smpl_freq_hz / tone_freq_hz;

tone[0] = 0;

for (size_t i = 1, j = samples_for_one_period - 1; i <= samples_for_one_period / 2;
i++, j--) {
float curr_val = i * 2 * PI / samples_for_one_period;
float32_t res = arm_sin_f32(curr_val);
/* Generate one sine wave */
tone[i] = amplitude * res * max;
tone[i] <<= scale;
tone[j] = -tone[i];
}

*tone_size = (size_t)samples_for_one_period * sizeof(int8_t);

return 0;
}

static int tone_gen_16(int16_t *tone, size_t *tone_size, uint16_t tone_freq_hz,
uint32_t smpl_freq_hz, uint8_t scale, uint32_t max, float amplitude)
{
uint32_t samples_for_one_period = smpl_freq_hz / tone_freq_hz;

tone[0] = 0;

for (size_t i = 1, j = samples_for_one_period - 1; i <= samples_for_one_period / 2;
i++, j--) {
float curr_val = i * 2 * PI / samples_for_one_period;
float32_t res = arm_sin_f32(curr_val);
/* Generate one sine wave */
tone[i] = amplitude * res * max;
tone[i] <<= scale;
tone[j] = -tone[i];
}

*tone_size = (size_t)samples_for_one_period * sizeof(int16_t);

return 0;
}

static int tone_gen_32(int32_t *tone, size_t *tone_size, uint16_t tone_freq_hz,
uint32_t smpl_freq_hz, uint8_t scale, int32_t max, float amplitude)
{
uint32_t samples_for_one_period = smpl_freq_hz / tone_freq_hz;

tone[0] = 0;

for (size_t i = 1, j = samples_for_one_period - 1; i <= samples_for_one_period / 2;
i++, j--) {
float curr_val = i * 2 * PI / samples_for_one_period;
float32_t res = arm_sin_f32(curr_val);
/* Generate one sine wave */
tone[i] = amplitude * res * max;
tone[i] <<= scale;
tone[j] = -tone[i];
}

*tone_size = (size_t)samples_for_one_period * sizeof(int32_t);

return 0;
}

int tone_gen_size(void *tone, size_t *tone_size, uint16_t tone_freq_hz, uint32_t sample_freq_hz,
uint8_t sample_bits, uint8_t carrier_bits, float amplitude)
{
int ret;
uint8_t scale;
int32_t max;

if (tone == NULL || tone_size == NULL) {
return -ENXIO;
}

if (!sample_freq_hz || tone_freq_hz < FREQ_LIMIT_LOW || tone_freq_hz > FREQ_LIMIT_HIGH) {
return -EINVAL;
}

if (amplitude > 1 || amplitude <= 0) {
return -EPERM;
}

if (!sample_bits || !carrier_bits || sample_bits > carrier_bits) {
return -EINVAL;
}

if (sample_bits == 8) {
max = INT8_MAX;
} else if (sample_bits == 16) {
max = INT16_MAX;
} else if (sample_bits == 24) {
max = 0x007FFFFF;
} else if (sample_bits == 32) {
max = INT32_MAX;
} else {
return -EINVAL;
}

scale = carrier_bits - sample_bits;

if (carrier_bits == 8) {
ret = tone_gen_8((int8_t *)tone, tone_size, tone_freq_hz, sample_freq_hz, scale,
max, amplitude);
} else if (carrier_bits == 16) {
ret = tone_gen_16((int16_t *)tone, tone_size, tone_freq_hz, sample_freq_hz, scale,
max, amplitude);
} else if (carrier_bits == 32) {
ret = tone_gen_32((int32_t *)tone, tone_size, tone_freq_hz, sample_freq_hz, scale,
max, amplitude);
} else {
return -EINVAL;
}

return 0;
}
Loading

0 comments on commit 33cc0a2

Please sign in to comment.