Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Greedysky committed Jul 5, 2020
1 parent 3309000 commit 2619eb7
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 140 deletions.
4 changes: 2 additions & 2 deletions qt-spek.pro
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ TEMPLATE = app
QMAKE_CXXFLAGS += -std=c++11

#change to your libav or ffmpeg lib
INCLUDEPATH += -L"."
LIBS += -L"./libav/lib" -lavcodec -lavformat -lavutil
INCLUDEPATH += $$PWD/libav/include
LIBS += -L"$$PWD/libav/lib" -lavcodec -lavformat -lavutil

SOURCES += main.cpp\
spek-ruler.cc \
Expand Down
99 changes: 57 additions & 42 deletions spek-audio.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <assert.h>
#include <QtGlobal>

extern "C" {
#define __STDC_CONSTANT_MACROS
Expand All @@ -10,13 +11,17 @@ extern "C" {

#include "spek-audio.h"

#ifdef Q_CC_GNU
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

class AudioFileImpl : public AudioFile
{
public:
AudioFileImpl(
AudioError error, AVFormatContext *format_context, int audio_stream,
const std::string& codec_name, int bit_rate, int sample_rate, int bits_per_sample,
int streams, int channels, double duration
AudioError error, AVFormatContext *format_context, AVCodecContext *codec_context,
int audio_stream, const std::string& codec_name, int bit_rate, int sample_rate,
int bits_per_sample, int streams, int channels, double duration
);
~AudioFileImpl() override;
void start(int channel, int samples) override;
Expand All @@ -38,6 +43,7 @@ class AudioFileImpl : public AudioFile
private:
AudioError error;
AVFormatContext *format_context;
AVCodecContext *codec_context;
int audio_stream;
std::string codec_name;
int bit_rate;
Expand Down Expand Up @@ -93,7 +99,7 @@ std::unique_ptr<AudioFile> Audio::open(const std::string& file_name, int stream)
int streams = 0;
if (!error) {
for (unsigned int i = 0; i < format_context->nb_streams; i++) {
if (format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (stream == streams) {
audio_stream = i;
}
Expand All @@ -106,12 +112,12 @@ std::unique_ptr<AudioFile> Audio::open(const std::string& file_name, int stream)
}

AVStream *avstream = nullptr;
AVCodecContext *codec_context = nullptr;
AVCodecParameters *codecpar = nullptr;
AVCodec *codec = nullptr;
if (!error) {
avstream = format_context->streams[audio_stream];
codec_context = avstream->codec;
codec = avcodec_find_decoder(codec_context->codec_id);
codecpar = avstream->codecpar;
codec = avcodec_find_decoder(codecpar->codec_id);
if (!codec) {
error = AudioError::NO_DECODER;
}
Expand All @@ -126,24 +132,24 @@ std::unique_ptr<AudioFile> Audio::open(const std::string& file_name, int stream)
if (!error) {
// We can already fill in the stream info even if the codec won't be able to open it.
codec_name = codec->long_name;
bit_rate = codec_context->bit_rate;
sample_rate = codec_context->sample_rate;
bits_per_sample = codec_context->bits_per_raw_sample;
bit_rate = codecpar->bit_rate;
sample_rate = codecpar->sample_rate;
bits_per_sample = codecpar->bits_per_raw_sample;
if (!bits_per_sample) {
// APE uses bpcs, FLAC uses bprs.
bits_per_sample = codec_context->bits_per_coded_sample;
bits_per_sample = codecpar->bits_per_coded_sample;
}
if (codec_context->codec_id == AV_CODEC_ID_AAC ||
codec_context->codec_id == AV_CODEC_ID_MUSEPACK8 ||
codec_context->codec_id == AV_CODEC_ID_WMAV1 ||
codec_context->codec_id == AV_CODEC_ID_WMAV2) {
if (codecpar->codec_id == AV_CODEC_ID_AAC ||
codecpar->codec_id == AV_CODEC_ID_MUSEPACK8 ||
codecpar->codec_id == AV_CODEC_ID_WMAV1 ||
codecpar->codec_id == AV_CODEC_ID_WMAV2) {
// These decoders set both bps and bitrate.
bits_per_sample = 0;
}
if (bits_per_sample) {
bit_rate = 0;
}
channels = codec_context->channels;
channels = codecpar->channels;

if (avstream->duration != AV_NOPTS_VALUE) {
duration = avstream->duration * av_q2d(avstream->time_base);
Expand All @@ -158,12 +164,24 @@ std::unique_ptr<AudioFile> Audio::open(const std::string& file_name, int stream)
}
}

if (!error && avcodec_open2(codec_context, codec, nullptr) < 0) {
AVCodecContext *codec_context = nullptr;
if (!error) {
error = AudioError::CANNOT_OPEN_DECODER;
// Allocate a codec context for the decoder.
codec_context = avcodec_alloc_context3(codec);
if (codec_context) {
// Copy codec parameters from input stream to output codec context.
if (avcodec_parameters_to_context(codec_context, codecpar) == 0) {
// Finally, init the decoder.
if (avcodec_open2(codec_context, codec, nullptr) == 0) {
error = AudioError::OK;
}
}
}
}

if (!error) {
AVSampleFormat fmt = codec_context->sample_fmt;
AVSampleFormat fmt = (AVSampleFormat)codecpar->format;
if (fmt != AV_SAMPLE_FMT_S16 && fmt != AV_SAMPLE_FMT_S16P &&
fmt != AV_SAMPLE_FMT_S32 && fmt != AV_SAMPLE_FMT_S32P &&
fmt != AV_SAMPLE_FMT_FLT && fmt != AV_SAMPLE_FMT_FLTP &&
Expand All @@ -173,27 +191,27 @@ std::unique_ptr<AudioFile> Audio::open(const std::string& file_name, int stream)
}

return std::unique_ptr<AudioFile>(new AudioFileImpl(
error, format_context, audio_stream,
codec_name, bit_rate, sample_rate, bits_per_sample,
streams, channels, duration
error, format_context, codec_context,
audio_stream, codec_name, bit_rate, sample_rate,
bits_per_sample, streams, channels, duration
));
}

AudioFileImpl::AudioFileImpl(
AudioError error, AVFormatContext *format_context, int audio_stream,
const std::string& codec_name, int bit_rate, int sample_rate, int bits_per_sample,
int streams, int channels, double duration
AudioError error, AVFormatContext *format_context, AVCodecContext *codec_context,
int audio_stream, const std::string& codec_name, int bit_rate, int sample_rate,
int bits_per_sample, int streams, int channels, double duration
) :
error(error), format_context(format_context), audio_stream(audio_stream),
codec_name(codec_name), bit_rate(bit_rate),
sample_rate(sample_rate), bits_per_sample(bits_per_sample),
streams(streams), channels(channels), duration(duration)
error(error), format_context(format_context), codec_context(codec_context),
audio_stream(audio_stream), codec_name(codec_name), bit_rate(bit_rate),
sample_rate(sample_rate),
bits_per_sample(bits_per_sample), streams(streams), channels(channels), duration(duration)
{
av_init_packet(&this->packet);
this->packet.data = nullptr;
this->packet.size = 0;
this->offset = 0;
this->frame = avcodec_alloc_frame();
this->frame = av_frame_alloc();
this->buffer_len = 0;
this->buffer = nullptr;
this->frames_per_interval = 0;
Expand All @@ -207,21 +225,18 @@ AudioFileImpl::~AudioFileImpl()
av_freep(&this->buffer);
}
if (this->frame) {
avcodec_free_frame(&this->frame);
av_frame_free(&this->frame);
}
if (this->packet.data) {
this->packet.data -= this->offset;
this->packet.size += this->offset;
this->offset = 0;
av_free_packet(&this->packet);
av_packet_unref(&this->packet);
}
if (this->codec_context) {
avcodec_free_context(&codec_context);
}
if (this->format_context) {
if (this->audio_stream >= 0) {
auto codec_context = this->format_context->streams[this->audio_stream]->codec;
if (codec_context) {
avcodec_close(codec_context);
}
}
avformat_close_input(&this->format_context);
}
}
Expand Down Expand Up @@ -250,10 +265,10 @@ int AudioFileImpl::read()

for (;;) {
while (this->packet.size > 0) {
// avcodec_free_frame(&this->frame);
auto codec_context = this->format_context->streams[this->audio_stream]->codec;
av_frame_unref(this->frame);
int got_frame = 0;
int len = avcodec_decode_audio4(codec_context, this->frame, &got_frame, &this->packet);
int len = avcodec_decode_audio4(this->codec_context, this->frame, &got_frame, &this->packet
);
if (len < 0) {
// Error, skip the frame.
break;
Expand Down Expand Up @@ -318,15 +333,15 @@ int AudioFileImpl::read()
this->packet.data -= this->offset;
this->packet.size += this->offset;
this->offset = 0;
av_free_packet(&this->packet);
av_packet_unref(&this->packet);
}

int res = 0;
while ((res = av_read_frame(this->format_context, &this->packet)) >= 0) {
if (this->packet.stream_index == this->audio_stream) {
break;
}
av_free_packet(&this->packet);
av_packet_unref(&this->packet);
}
if (res < 0) {
// End of file or error.
Expand Down
2 changes: 1 addition & 1 deletion spek-fft.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void FFTPlanImpl::execute()
float n2 = n * n;
this->set_output(0, 10.0f * log10f(this->get_input(0) * this->get_input(0) / n2));
this->set_output(n / 2, 10.0f * log10f(this->get_input(1) * this->get_input(1) / n2));
for (int i = 1; i < n / 2; i++) {
for(int i = 1; i < n / 2; i++) {
float re = this->get_input(i * 2);
float im = this->get_input(i * 2 + 1);
this->set_output(i, 10.0f * log10f((re * re + im * im) / n2));
Expand Down
73 changes: 73 additions & 0 deletions spek-palette.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,65 @@
#include <qmath.h>
#include "spek-palette.h"

#include <QColor>
#include <QVector>

#define GRADIENT_TABLE_SIZE 256

static bool globalTableInit = false;
static uint32_t globalTableGolors[GRADIENT_TABLE_SIZE];
static QVector<QColor> globalGolors = { QColor(0, 0, 0),
QColor(0, 32, 100),
QColor(0, 120, 160),
QColor(128, 255, 120),
QColor(255, 255, 0),
QColor(255, 128, 0),
QColor(255, 0, 0)
};

void createGradientTable()
{
int numbers = 6;
for(int i = 0; i < GRADIENT_TABLE_SIZE; i++)
{
double position = (double)i/GRADIENT_TABLE_SIZE;
/* if position > 1 then we have repetition of colors it maybe useful */
if(position > 1.0)
{
if(position - int(position) == 0.0)
{
position = 1.0;
}
else
{
position = position - int(position);
}
}

const double m = numbers * position;
const int n = (int)m; // integer of m
const double f = m - n; // fraction of m

globalTableGolors[i] = 0xFF0000;
if(n < numbers)
{
globalTableGolors[i] = ((uint32_t)((globalGolors[n].red()) + f * ((globalGolors[n+1].red()) - (globalGolors[n].red()))) & 0xFF) << 16 |
((uint32_t)((globalGolors[n].green()) + f * ((globalGolors[n+1].green()) - (globalGolors[n].green()))) & 0xFF) << 8 |
((uint32_t)((globalGolors[n].blue()) + f * ((globalGolors[n+1].blue()) - (globalGolors[n].blue()))) & 0xFF) << 0;
}
else if(n == numbers)
{
globalTableGolors[i] = ((uint32_t)(globalGolors[n].red()) & 0xFF) << 16 |
((uint32_t)(globalGolors[n].green()) & 0xFF) << 8 |
((uint32_t)(globalGolors[n].blue()) & 0xFF) << 0;
}
else
{
globalTableGolors[i] = 0xFFFFFF;
}
}
}

// Modified version of Dan Bruton's algorithm:
// http://www.physics.sfasu.edu/astro/color/spectra.html
static uint32_t spectrum(double level)
Expand Down Expand Up @@ -44,6 +103,18 @@ static uint32_t spectrum(double level)
return (rr << 16) + (gg << 8) + bb;
}

uint32_t spectrogram(double level)
{
if(!globalTableInit)
{
createGradientTable();
globalTableInit = true;
}

const int index = qBound(0, int(level * GRADIENT_TABLE_SIZE), GRADIENT_TABLE_SIZE - 1);
return globalTableGolors[index];
}

// The default palette used by SoX and written by Rob Sykes.
static uint32_t sox(double level)
{
Expand Down Expand Up @@ -85,6 +156,8 @@ uint32_t spek_palette(Palette palette, double level) {
switch (palette) {
case PALETTE_SPECTRUM:
return spectrum(level);
case PALETTE_SPECTROGRAM:
return spectrogram(level);
case PALETTE_SOX:
return sox(level);
case PALETTE_MONO:
Expand Down
4 changes: 2 additions & 2 deletions spek-palette.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

typedef enum palette {
PALETTE_SPECTRUM,
PALETTE_SPECTROGRAM,
PALETTE_SOX,
PALETTE_MONO,
PALETTE_COUNT,
PALETTE_DEFAULT = PALETTE_SOX,
PALETTE_DEFAULT = PALETTE_SPECTROGRAM,
}Palette;

uint32_t spek_palette(Palette palette, double level);
Expand Down
Loading

0 comments on commit 2619eb7

Please sign in to comment.