103 lines
3.3 KiB
C
103 lines
3.3 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "audio.h"
|
|
#include "audio_internal.h"
|
|
|
|
typedef struct _SourceTesttoneContext {
|
|
AudioBuffer *buffer;
|
|
} SourceTesttoneContext;
|
|
|
|
AudioPipelineStatus source_testtone_start(AudioPipelineElement *self) {
|
|
SourceTesttoneContext *context = (SourceTesttoneContext *)self->ctx;
|
|
|
|
int sample_size = (self->bits_per_sample / 8) * self->channels;
|
|
int bytes_per_sample = (self->bits_per_sample / 8);
|
|
float max_value = pow(2, self->bits_per_sample) / 2 - 1;
|
|
|
|
AudioPipelineStatus result = self->next->start(self->next);
|
|
if (result != PipelineStopped) {
|
|
return result;
|
|
}
|
|
|
|
for (int freq = 440; freq < 1440; freq += 100) {
|
|
for (int i = 0; i < self->sample_rate / 8; i++) {
|
|
float volume = 1.0f - ((float)i / ((float)self->sample_rate / 8.0f));
|
|
int sample = (int)(0.75f * max_value * sinf(2 * M_PI * freq * ((float)i/self->sample_rate))) * volume;
|
|
|
|
for(int c = 0; c < self->channels; c++) {
|
|
int offset = (sample_size * i) + (bytes_per_sample * c);
|
|
context->buffer->data[offset] = sample & 0xff;
|
|
if (bytes_per_sample > 1) {
|
|
context->buffer->data[offset + 1] = (sample >> 8) & 0xff;
|
|
}
|
|
if (bytes_per_sample > 2) {
|
|
context->buffer->data[offset + 2] = (sample >> 16) & 0xff;
|
|
}
|
|
if (bytes_per_sample > 3) {
|
|
context->buffer->data[offset + 3] = (sample >> 24) & 0xff;
|
|
}
|
|
}
|
|
}
|
|
|
|
result = self->next->push(self->next, context->buffer);
|
|
if (result != PipelineRunning) {
|
|
self->pipeline->status = result;
|
|
if (self->pipeline->statusCallback != NULL) {
|
|
self->pipeline->statusCallback(self->pipeline, result);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return PipelineFinished;
|
|
}
|
|
|
|
char *source_testtone_describe(AudioPipelineElement *self) {
|
|
return "testtone source";
|
|
}
|
|
|
|
void source_testtone_destroy(AudioPipelineElement *self) {
|
|
SourceTesttoneContext *context = (SourceTesttoneContext *)self->ctx;
|
|
free_audio_buffer(context->buffer);
|
|
free(self->ctx);
|
|
free(self);
|
|
}
|
|
|
|
AudioPipelineElement *audio_source_testtone(uint16_t sample_rate, uint8_t channels, uint8_t bits_per_sample) {
|
|
AudioPipelineElement *self = calloc(1, sizeof(AudioPipelineElement));
|
|
if (self == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
SourceTesttoneContext *context = calloc(1, sizeof(SourceTesttoneContext));
|
|
if (context == NULL) {
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
|
|
context->buffer = alloc_audio_buffer(sample_rate / 8 * channels * (bits_per_sample / 8));
|
|
if (context->buffer == NULL) {
|
|
free(context);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
|
|
self->bits_per_sample = bits_per_sample;
|
|
self->channels = channels;
|
|
self->sample_rate = sample_rate;
|
|
|
|
self->ctx = context;
|
|
self->describe = source_testtone_describe;
|
|
self->start = source_testtone_start;
|
|
self->reset = source_reset_nop;
|
|
self->stop = source_stop_nop;
|
|
self->push = NULL;
|
|
self->link = NULL;
|
|
self->destroy = source_testtone_destroy;
|
|
self->type = AudioElementSource;
|
|
|
|
return self;
|
|
}
|
|
|