mirror of
https://github.com/alexkay/spek.git
synced 2025-06-09 11:52:13 +03:00
Average values for decoded audio
This commit is contained in:
parent
eea89183d1
commit
9c1a32213b
@ -55,7 +55,8 @@ SpekAudioContext * spek_audio_open (const char *file_name) {
|
|||||||
cx->error = _("The file contains no audio streams");
|
cx->error = _("The file contains no audio streams");
|
||||||
return cx;
|
return cx;
|
||||||
}
|
}
|
||||||
cx->codec_context = cx->format_context->streams[cx->audio_stream]->codec;
|
cx->stream = cx->format_context->streams[cx->audio_stream];
|
||||||
|
cx->codec_context = cx->stream->codec;
|
||||||
cx->codec = avcodec_find_decoder (cx->codec_context->codec_id);
|
cx->codec = avcodec_find_decoder (cx->codec_context->codec_id);
|
||||||
if (cx->codec == NULL) {
|
if (cx->codec == NULL) {
|
||||||
cx->error = _("Cannot find decoder");
|
cx->error = _("Cannot find decoder");
|
||||||
@ -71,11 +72,36 @@ SpekAudioContext * spek_audio_open (const char *file_name) {
|
|||||||
cx->bits_per_sample = cx->codec_context->bits_per_coded_sample;
|
cx->bits_per_sample = cx->codec_context->bits_per_coded_sample;
|
||||||
}
|
}
|
||||||
cx->channels = cx->codec_context->channels;
|
cx->channels = cx->codec_context->channels;
|
||||||
|
if (cx->channels <= 0) {
|
||||||
|
cx->error = _("No audio channels");
|
||||||
|
return cx;
|
||||||
|
}
|
||||||
cx->buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
|
cx->buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
|
||||||
if (avcodec_open (cx->codec_context, cx->codec) < 0) {
|
if (avcodec_open (cx->codec_context, cx->codec) < 0) {
|
||||||
cx->error = _("Cannot open decoder");
|
cx->error = _("Cannot open decoder");
|
||||||
return cx;
|
return cx;
|
||||||
}
|
}
|
||||||
|
switch (cx->codec_context->sample_fmt) {
|
||||||
|
case SAMPLE_FMT_S16:
|
||||||
|
cx->width = 16;
|
||||||
|
cx->fp = FALSE;
|
||||||
|
break;
|
||||||
|
case SAMPLE_FMT_S32:
|
||||||
|
cx->width = 32;
|
||||||
|
cx->fp = FALSE;
|
||||||
|
break;
|
||||||
|
case SAMPLE_FMT_FLT:
|
||||||
|
cx->width = 32;
|
||||||
|
cx->fp = TRUE;
|
||||||
|
break;
|
||||||
|
case SAMPLE_FMT_DBL:
|
||||||
|
cx->width = 64;
|
||||||
|
cx->fp = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cx->error = _("Unsupported sample format");
|
||||||
|
return cx;
|
||||||
|
}
|
||||||
av_init_packet (&cx->packet);
|
av_init_packet (&cx->packet);
|
||||||
cx->offset = 0;
|
cx->offset = 0;
|
||||||
return cx;
|
return cx;
|
||||||
|
@ -28,6 +28,7 @@ typedef struct {
|
|||||||
AVFormatContext *format_context;
|
AVFormatContext *format_context;
|
||||||
gint audio_stream;
|
gint audio_stream;
|
||||||
AVCodecContext *codec_context;
|
AVCodecContext *codec_context;
|
||||||
|
AVStream *stream;
|
||||||
AVCodec *codec;
|
AVCodec *codec;
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
gint offset;
|
gint offset;
|
||||||
@ -39,6 +40,8 @@ typedef struct {
|
|||||||
gint bit_rate;
|
gint bit_rate;
|
||||||
gint sample_rate;
|
gint sample_rate;
|
||||||
gint bits_per_sample;
|
gint bits_per_sample;
|
||||||
|
gint width; /* number of bits used to store a sample */
|
||||||
|
gboolean fp; /* floating-point sample representation */
|
||||||
gint channels;
|
gint channels;
|
||||||
gint buffer_size; /* minimum buffer size for spek_audio_read() */
|
gint buffer_size; /* minimum buffer size for spek_audio_read() */
|
||||||
} SpekAudioContext;
|
} SpekAudioContext;
|
||||||
|
@ -14,15 +14,34 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Spek. If not, see <http://www.gnu.org/licenses/>.
|
* along with Spek. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Conversion of decoded samples into an FFT-happy format is heavily
|
||||||
|
* influenced by GstSpectrum which is part of gst-plugins-good.
|
||||||
|
* The original code:
|
||||||
|
* (c) 1999 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
|
* (c) 2006 Stefan Kost <ensonic@users.sf.net>
|
||||||
|
* (c) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Spek {
|
namespace Spek {
|
||||||
public class Pipeline {
|
public class Pipeline {
|
||||||
private Audio.Context cx;
|
|
||||||
public string description { get; private set; }
|
public string description { get; private set; }
|
||||||
|
public int sample_rate { get; private set; }
|
||||||
|
public delegate void Callback (int sample, float[] values);
|
||||||
|
|
||||||
public Pipeline (string file_name) {
|
private Audio.Context cx;
|
||||||
cx = new Audio.Context (file_name);
|
private int bands;
|
||||||
|
private int samples;
|
||||||
|
private int threshold;
|
||||||
|
private Callback cb;
|
||||||
|
private uint8[] buffer;
|
||||||
|
|
||||||
|
public Pipeline (string file_name, int bands, int samples, int threshold, Callback cb) {
|
||||||
|
this.cx = new Audio.Context (file_name);
|
||||||
|
this.bands = bands;
|
||||||
|
this.samples = samples;
|
||||||
|
this.threshold = threshold;
|
||||||
|
this.cb = cb;
|
||||||
|
|
||||||
// Build the description string.
|
// Build the description string.
|
||||||
string[] items = {};
|
string[] items = {};
|
||||||
@ -51,24 +70,59 @@ namespace Spek {
|
|||||||
description = _("%s: %s").printf (cx.error, description);
|
description = _("%s: %s").printf (cx.error, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = new uint8[cx.buffer_size];
|
this.sample_rate = cx.sample_rate;
|
||||||
while (cx.read (buffer) > 0);
|
this.buffer = new uint8[cx.buffer_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
public string file_name {
|
public void start () {
|
||||||
get { return cx.file_name; }
|
int nfft = 2 * bands - 2;
|
||||||
|
var input = new float[nfft];
|
||||||
|
int pos = 0;
|
||||||
|
int frames = 0;
|
||||||
|
int size;
|
||||||
|
while ((size = cx.read (this.buffer)) > 0) {
|
||||||
|
uint8 *buffer = (uint8 *) this.buffer;
|
||||||
|
var block_size = cx.width * cx.channels;
|
||||||
|
while (size >= block_size) {
|
||||||
|
input[pos] = average_input (buffer);
|
||||||
|
buffer += block_size;
|
||||||
|
size -= block_size;
|
||||||
|
pos = (pos + 1) % nfft;
|
||||||
|
frames++;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
assert (size == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int bit_rate {
|
private float average_input (uint8 *buffer) {
|
||||||
get { return cx.bit_rate; }
|
float res = 0f;
|
||||||
}
|
float max_value = cx.bits_per_sample > 1 ? (1UL << (cx.bits_per_sample - 1)) - 1 : 0;
|
||||||
|
if (cx.fp && cx.width == 32) {
|
||||||
public int sample_rate {
|
float *p = (float *) buffer;
|
||||||
get { return cx.sample_rate; }
|
for (int i = 0; i < cx.channels; i++) {
|
||||||
}
|
res += p[i];
|
||||||
|
}
|
||||||
public int channels {
|
} else if (cx.fp && cx.width == 64) {
|
||||||
get { return cx.channels; }
|
double *p = (double *) buffer;
|
||||||
|
for (int i = 0; i < cx.channels; i++) {
|
||||||
|
res += (float) p[i];
|
||||||
|
}
|
||||||
|
} else if (!cx.fp && cx.width == 32) {
|
||||||
|
int32 *p = (int32 *) buffer;
|
||||||
|
for (int i = 0; i < cx.channels; i++) {
|
||||||
|
res += p[i] / (max_value == 0 ? int32.MAX : max_value);
|
||||||
|
}
|
||||||
|
} else if (!cx.fp && cx.width == 16) {
|
||||||
|
int64 *p = (int64 *) buffer;
|
||||||
|
for (int i = 0; i < cx.channels; i++) {
|
||||||
|
res += p[i] / (max_value == 0 ? int16.MAX : max_value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert_not_reached ();
|
||||||
|
}
|
||||||
|
return res / cx.channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,10 +63,6 @@ namespace Spek {
|
|||||||
this.file_name = file_name;
|
this.file_name = file_name;
|
||||||
this.info = "";
|
this.info = "";
|
||||||
|
|
||||||
// TODO
|
|
||||||
var pipeline = new Pipeline (file_name);
|
|
||||||
print ("\n%s:\n%s\n", file_name, pipeline.description);
|
|
||||||
|
|
||||||
start ();
|
start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +88,11 @@ namespace Spek {
|
|||||||
image = null;
|
image = null;
|
||||||
source = null;
|
source = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
var pipeline = new Pipeline (file_name, BANDS, samples, THRESHOLD, data_cb);
|
||||||
|
print ("\n%s:\n%s\n", file_name, pipeline.description);
|
||||||
|
|
||||||
queue_draw ();
|
queue_draw ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +241,7 @@ namespace Spek {
|
|||||||
unowned uchar[] data = surface.get_data ();
|
unowned uchar[] data = surface.get_data ();
|
||||||
|
|
||||||
// Translate uchar* to uint32* to avoid dealing with endianness.
|
// Translate uchar* to uint32* to avoid dealing with endianness.
|
||||||
uint32 *p = &data[i];
|
uint32 *p = (uint32 *) (&data[i]);
|
||||||
*p = color;
|
*p = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ namespace Spek.Audio {
|
|||||||
public int bit_rate;
|
public int bit_rate;
|
||||||
public int sample_rate;
|
public int sample_rate;
|
||||||
public int bits_per_sample;
|
public int bits_per_sample;
|
||||||
|
public int width;
|
||||||
|
public bool fp;
|
||||||
public int channels;
|
public int channels;
|
||||||
public int buffer_size;
|
public int buffer_size;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user