#include #include #include #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; }