Analyse a single channel

References #18.
This commit is contained in:
Alexander Kojevnikov 2016-04-05 11:27:06 -07:00
parent 925570cbb9
commit 7eef5eed6a
3 changed files with 54 additions and 56 deletions

View File

@ -1,3 +1,5 @@
#include <assert.h>
extern "C" { extern "C" {
#define __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
@ -17,7 +19,7 @@ public:
int channels, double duration int channels, double duration
); );
~AudioFileImpl() override; ~AudioFileImpl() override;
void start(int samples) override; void start(int channel, int samples) override;
int read() override; int read() override;
AudioError get_error() const override { return this->error; } AudioError get_error() const override { return this->error; }
@ -43,6 +45,8 @@ private:
int channels; int channels;
double duration; double duration;
int channel;
AVPacket packet; AVPacket packet;
int offset; int offset;
AVFrame *frame; AVFrame *frame;
@ -217,8 +221,14 @@ AudioFileImpl::~AudioFileImpl()
} }
} }
void AudioFileImpl::start(int samples) void AudioFileImpl::start(int channel, int samples)
{ {
this->channel = channel;
if (channel < 0 || channel >= this->channels) {
assert(false);
this->error = AudioError::NO_CHANNELS;
}
AVStream *stream = this->format_context->streams[this->audio_stream]; AVStream *stream = this->format_context->streams[this->audio_stream];
int64_t rate = this->sample_rate * (int64_t)stream->time_base.num; int64_t rate = this->sample_rate * (int64_t)stream->time_base.num;
int64_t duration = (int64_t)(this->duration * stream->time_base.den / stream->time_base.num); int64_t duration = (int64_t)(this->duration * stream->time_base.den / stream->time_base.num);
@ -252,57 +262,52 @@ int AudioFileImpl::read()
} }
// We have data, return it and come back for more later. // We have data, return it and come back for more later.
int samples = this->frame->nb_samples; int samples = this->frame->nb_samples;
int channels = this->channels; if (samples > this->buffer_len) {
int buffer_len = samples * channels;
if (buffer_len > this->buffer_len) {
this->buffer = static_cast<float*>( this->buffer = static_cast<float*>(
av_realloc(this->buffer, buffer_len * sizeof(float)) av_realloc(this->buffer, samples * sizeof(float))
); );
this->buffer_len = buffer_len; this->buffer_len = samples;
} }
AVSampleFormat format = static_cast<AVSampleFormat>(this->frame->format); AVSampleFormat format = static_cast<AVSampleFormat>(this->frame->format);
int is_planar = av_sample_fmt_is_planar(format); int is_planar = av_sample_fmt_is_planar(format);
int i = 0;
for (int sample = 0; sample < samples; ++sample) { for (int sample = 0; sample < samples; ++sample) {
for (int channel = 0; channel < channels; ++channel) { uint8_t *data;
uint8_t *data; int offset;
int offset; if (is_planar) {
if (is_planar) { data = this->frame->data[this->channel];
data = this->frame->data[channel]; offset = sample;
offset = sample; } else {
} else { data = this->frame->data[0];
data = this->frame->data[0]; offset = sample * this->channels;
offset = i;
}
float value;
switch (format) {
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
value = reinterpret_cast<int16_t*>(data)[offset]
/ static_cast<float>(INT16_MAX);
break;
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
value = reinterpret_cast<int32_t*>(data)[offset]
/ static_cast<float>(INT32_MAX);
break;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
value = reinterpret_cast<float*>(data)[offset];
break;
case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
value = reinterpret_cast<double*>(data)[offset];
break;
default:
value = 0.0f;
break;
}
this->buffer[i++] = value;
} }
float value;
switch (format) {
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
value = reinterpret_cast<int16_t*>(data)[offset]
/ static_cast<float>(INT16_MAX);
break;
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
value = reinterpret_cast<int32_t*>(data)[offset]
/ static_cast<float>(INT32_MAX);
break;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
value = reinterpret_cast<float*>(data)[offset];
break;
case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
value = reinterpret_cast<double*>(data)[offset];
break;
default:
value = 0.0f;
break;
}
this->buffer[sample] = value;
} }
return buffer_len; return samples;
} }
if (this->packet.data) { if (this->packet.data) {
this->packet.data -= this->offset; this->packet.data -= this->offset;

View File

@ -21,7 +21,7 @@ class AudioFile
public: public:
virtual ~AudioFile() {} virtual ~AudioFile() {}
virtual void start(int samples) = 0; virtual void start(int channel, int samples) = 0;
virtual int read() = 0; virtual int read() = 0;
virtual AudioError get_error() const = 0; virtual AudioError get_error() const = 0;

View File

@ -95,7 +95,7 @@ struct spek_pipeline * spek_pipeline_open(
p->input_size = p->nfft * (NFFT * 2 + 1); p->input_size = p->nfft * (NFFT * 2 + 1);
p->input = (float*)malloc(p->input_size * sizeof(float)); p->input = (float*)malloc(p->input_size * sizeof(float));
p->output = (float*)malloc(p->fft->get_output_size() * sizeof(float)); p->output = (float*)malloc(p->fft->get_output_size() * sizeof(float));
p->file->start(samples); p->file->start(0, samples);
} }
return p; return p;
@ -293,20 +293,13 @@ static void * reader_func(void *pp)
} }
int pos = 0, prev_pos = 0; int pos = 0, prev_pos = 0;
int channels = p->file->get_channels();
int len; int len;
while ((len = p->file->read()) > 0) { while ((len = p->file->read()) > 0) {
if (p->quit) break; if (p->quit) break;
const float *buffer = p->file->get_buffer(); const float *buffer = p->file->get_buffer();
while (len >= channels) { while (len-- > 0) {
float val = 0.0f; p->input[pos] = *buffer++;
for (int i = 0; i < channels; i++) {
val += buffer[i];
}
p->input[pos] = val / channels;
buffer += channels;
len -= channels;
pos = (pos + 1) % p->input_size; pos = (pos + 1) % p->input_size;
// Wake up the worker if we have enough data. // Wake up the worker if we have enough data.
@ -314,7 +307,7 @@ static void * reader_func(void *pp)
reader_sync(p, prev_pos = pos); reader_sync(p, prev_pos = pos);
} }
} }
assert(len == 0); assert(len == -1);
} }
if (pos != prev_pos) { if (pos != prev_pos) {