commit 92dd6a8bbfa73b914e6dabd8033afd836394c7e0
parent 98ba100f0ce41fbf8547a8eb3eecdc0859ba6928
Author: Alexander Kojevnikov <alexander@kojevnikov.com>
Date: Sun, 5 Aug 2012 23:04:29 -0700
Add spek-audio.c
Diffstat:
3 files changed, 120 insertions(+), 108 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
@@ -2,6 +2,8 @@ bin_PROGRAMS = spek
spek_SOURCES = \
spek.cc \
+ spek-audio.c \
+ spek-audio.h \
spek-fft.c \
spek-fft.h \
spek-platform.cc \
diff --git a/src/spek-audio.c b/src/spek-audio.c
@@ -1,6 +1,6 @@
/* spek-audio.c
*
- * Copyright (C) 2010 Alexander Kojevnikov <alexander@kojevnikov.com>
+ * Copyright (C) 2010-2012 Alexander Kojevnikov <alexander@kojevnikov.com>
*
* Spek is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,47 +16,48 @@
* along with Spek. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <glib.h>
-#include <glib/gi18n.h>
+#include <string.h>
+
#include <libavutil/mathematics.h>
+#include "spek-platform.h"
+
#include "spek-audio.h"
-void spek_audio_init () {
- /* TODO: register only audio decoders */
- av_register_all ();
-}
+// TODO: move translations to UI code, return an error code instead.
+#define _
-SpekAudioContext * spek_audio_open (const gchar *file_name) {
- SpekAudioContext *cx;
- int i;
+void spek_audio_init()
+{
+ // TODO: register only audio decoders.
+ av_register_all();
+}
- cx = g_new0 (SpekAudioContext, 1);
- cx->file_name = g_strdup (file_name);
-#ifdef G_OS_WIN32
- /* av_open_input_file() cannot open files with Unicode chars in it
- * when running under Windows. When this happens we will re-try
- * using the corresponding short file name.
- */
- cx->short_name = g_win32_locale_filename_from_utf8 (file_name);
-#endif
+struct spek_audio_context * spek_audio_open(const char *file_name)
+{
+ struct spek_audio_context *cx = malloc(sizeof(struct spek_audio_context));
+ cx->file_name = strdup(file_name);
+ // av_open_input_file() cannot open files with Unicode chars in it
+ // when running under Windows. When this happens we will re-try
+ // using the corresponding short file name.
+ cx->short_name = spek_platform_short_path(file_name);
- if (avformat_open_input (&cx->format_context, file_name, NULL, NULL) != 0) {
+ if (avformat_open_input(&cx->format_context, file_name, NULL, NULL) != 0) {
if (!cx->short_name ||
- avformat_open_input (&cx->format_context, cx->short_name, NULL, NULL) != 0 ) {
+ avformat_open_input(&cx->format_context, cx->short_name, NULL, NULL) != 0 ) {
cx->error = _("Cannot open input file");
return cx;
}
}
- if (avformat_find_stream_info (cx->format_context, NULL) < 0) {
- /* 24-bit APE returns an error but parses the stream info just fine */
+ if (avformat_find_stream_info(cx->format_context, NULL) < 0) {
+ // 24-bit APE returns an error but parses the stream info just fine.
if (cx->format_context->nb_streams <= 0) {
cx->error = _("Cannot find stream info");
return cx;
}
}
cx->audio_stream = -1;
- for (i = 0; i < cx->format_context->nb_streams; i++) {
+ for (int i = 0; i < cx->format_context->nb_streams; i++) {
if (cx->format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
cx->audio_stream = i;
break;
@@ -68,23 +69,23 @@ SpekAudioContext * spek_audio_open (const gchar *file_name) {
}
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) {
cx->error = _("Cannot find decoder");
return cx;
}
- /* We can already fill in the stream info even if the codec won't be able to open it */
- cx->codec_name = g_strdup (cx->codec->long_name);
+ // We can already fill in the stream info even if the codec won't be able to open it.
+ cx->codec_name = strdup(cx->codec->long_name);
cx->bit_rate = cx->codec_context->bit_rate;
cx->sample_rate = cx->codec_context->sample_rate;
cx->bits_per_sample = cx->codec_context->bits_per_raw_sample;
if (!cx->bits_per_sample) {
- /* APE uses bpcs, FLAC uses bprs. */
+ // APE uses bpcs, FLAC uses bprs.
cx->bits_per_sample = cx->codec_context->bits_per_coded_sample;
}
cx->channels = cx->codec_context->channels;
if (cx->stream->duration != AV_NOPTS_VALUE) {
- cx->duration = cx->stream->duration * av_q2d (cx->stream->time_base);
+ cx->duration = cx->stream->duration * av_q2d(cx->stream->time_base);
} else if (cx->format_context->duration != AV_NOPTS_VALUE) {
cx->duration = cx->format_context->duration / (double) AV_TIME_BASE;
} else {
@@ -95,63 +96,61 @@ SpekAudioContext * spek_audio_open (const gchar *file_name) {
cx->error = _("No audio channels");
return cx;
}
- if (avcodec_open2 (cx->codec_context, cx->codec, NULL) < 0) {
+ if (avcodec_open2(cx->codec_context, cx->codec, NULL) < 0) {
cx->error = _("Cannot open decoder");
return cx;
}
switch (cx->codec_context->sample_fmt) {
case SAMPLE_FMT_S16:
cx->width = 16;
- cx->fp = FALSE;
+ cx->fp = false;
break;
case SAMPLE_FMT_S32:
cx->width = 32;
- cx->fp = FALSE;
+ cx->fp = false;
break;
case SAMPLE_FMT_FLT:
cx->width = 32;
- cx->fp = TRUE;
+ cx->fp = true;
break;
case SAMPLE_FMT_DBL:
cx->width = 64;
- cx->fp = TRUE;
+ cx->fp = true;
break;
default:
cx->error = _("Unsupported sample format");
return cx;
}
cx->buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
- cx->buffer = av_malloc (cx->buffer_size);
- cx->packet = av_mallocz (sizeof (AVPacket));
- av_init_packet (cx->packet);
+ cx->buffer = av_malloc(cx->buffer_size);
+ cx->packet = av_mallocz(sizeof(AVPacket));
+ av_init_packet(cx->packet);
cx->offset = 0;
return cx;
}
-void spek_audio_start (SpekAudioContext *cx, gint samples) {
- gint64 rate = cx->sample_rate * (gint64) cx->stream->time_base.num;
- gint64 duration = (gint64) (cx->duration * cx->stream->time_base.den / cx->stream->time_base.num);
- cx->error_base = samples * (gint64) cx->stream->time_base.den;
- cx->frames_per_interval = av_rescale_rnd (duration, rate, cx->error_base, AV_ROUND_DOWN);
+void spek_audio_start(struct spek_audio_context *cx, int samples)
+{
+ int64_t rate = cx->sample_rate * (int64_t) cx->stream->time_base.num;
+ int64_t duration = (int64_t)
+ (cx->duration * cx->stream->time_base.den / cx->stream->time_base.num);
+ cx->error_base = samples * (int64_t)cx->stream->time_base.den;
+ cx->frames_per_interval = av_rescale_rnd(duration, rate, cx->error_base, AV_ROUND_DOWN);
cx->error_per_interval = (duration * rate) % cx->error_base;
}
-gint spek_audio_read (SpekAudioContext *cx) {
- gint buffer_size;
- gint len;
- gint res;
-
+int spek_audio_read(struct spek_audio_context *cx) {
if (cx->error) {
return -1;
}
for (;;) {
while (cx->packet->size > 0) {
- buffer_size = cx->buffer_size;
- len = avcodec_decode_audio3 (
- cx->codec_context, (int16_t *) cx->buffer, &buffer_size, cx->packet);
+ int buffer_size = cx->buffer_size;
+ int len = avcodec_decode_audio3(
+ cx->codec_context, (int16_t *)cx->buffer, &buffer_size, cx->packet);
if (len < 0) {
- /* Error, skip the frame. */
+ // Error, skip the frame.
cx->packet->size = 0;
break;
}
@@ -159,10 +158,10 @@ gint spek_audio_read (SpekAudioContext *cx) {
cx->packet->size -= len;
cx->offset += len;
if (buffer_size <= 0) {
- /* No data yet, get more frames */
+ // No data yet, get more frames.
continue;
}
- /* We have data, return it and come back for more later */
+ // We have data, return it and come back for more later.
return buffer_size;
}
if (cx->packet->data) {
@@ -171,46 +170,49 @@ gint spek_audio_read (SpekAudioContext *cx) {
cx->offset = 0;
av_free_packet (cx->packet);
}
- while ((res = av_read_frame (cx->format_context, cx->packet)) >= 0) {
+
+ int res = 0;
+ while ((res = av_read_frame(cx->format_context, cx->packet)) >= 0) {
if (cx->packet->stream_index == cx->audio_stream) {
break;
}
- av_free_packet (cx->packet);
+ av_free_packet(cx->packet);
}
if (res < 0) {
- /* End of file or error. */
+ // End of file or error.
return 0;
}
}
}
-void spek_audio_close (SpekAudioContext *cx) {
+void spek_audio_close (struct spek_audio_context *cx)
+{
if (cx->file_name != NULL) {
- g_free (cx->file_name);
+ free(cx->file_name);
}
if (cx->short_name != NULL) {
- g_free (cx->short_name);
+ free(cx->short_name);
}
if (cx->codec_name != NULL) {
- g_free (cx->codec_name);
+ free(cx->codec_name);
}
if (cx->buffer) {
- av_free (cx->buffer);
+ av_free(cx->buffer);
}
if (cx->packet) {
if (cx->packet->data) {
cx->packet->data -= cx->offset;
cx->packet->size += cx->offset;
cx->offset = 0;
- av_free_packet (cx->packet);
+ av_free_packet(cx->packet);
}
- av_free (cx->packet);
+ av_free(cx->packet);
}
if (cx->codec_context != NULL) {
- avcodec_close (cx->codec_context);
+ avcodec_close(cx->codec_context);
}
if (cx->format_context != NULL) {
- av_close_input_file (cx->format_context);
+ av_close_input_file(cx->format_context);
}
- g_free (cx);
+ free(cx);
}
diff --git a/src/spek-audio.h b/src/spek-audio.h
@@ -16,62 +16,70 @@
* along with Spek. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __SPEK_AUDIO_H__
-#define __SPEK_AUDIO_H__
+#ifndef SPEK_AUDIO_H_
+#define SPEK_AUDIO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
-#include <glib.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
-typedef struct {
- /* Internal data */
- gchar *short_name;
+struct spek_audio_context
+{
+ // Internal data.
+ char *short_name;
AVFormatContext *format_context;
- gint audio_stream;
+ int audio_stream;
AVCodecContext *codec_context;
AVStream *stream;
AVCodec *codec;
- gint buffer_size;
+ int buffer_size;
AVPacket *packet;
- gint offset;
+ int offset;
- /* Exposed properties */
- gchar *file_name;
- gchar *codec_name;
- gchar *error;
- gint bit_rate;
- gint sample_rate;
- gint bits_per_sample;
- gint width; /* number of bits used to store a sample */
- gboolean fp; /* floating-point sample representation */
- gint channels;
- gdouble duration;
- guint8 *buffer;
- gint64 frames_per_interval;
- gint64 error_per_interval;
- gint64 error_base;
-} SpekAudioContext;
+ // Exposed properties.
+ char *file_name;
+ char *codec_name;
+ char *error;
+ int bit_rate;
+ int sample_rate;
+ int bits_per_sample;
+ int width; // number of bits used to store a sample
+ bool fp; // floating-point sample representation
+ int channels;
+ double duration;
+ uint8_t *buffer;
+ int64_t frames_per_interval;
+ int64_t error_per_interval;
+ int64_t error_base;
+};
-/* Initialise FFmpeg, should be called once on start up */
-void spek_audio_init ();
+// Initialise FFmpeg, should be called once on start up.
+void spek_audio_init();
-/* Open the file, check if it has an audio stream which can be decoded.
- * On error, initialises the `error` field in the returned context.
- */
-SpekAudioContext * spek_audio_open (const gchar *file_name);
+// Open the file, check if it has an audio stream which can be decoded.
+// On error, initialises the `error` field in the returned context.
+struct spek_audio_context * spek_audio_open(const char *file_name);
-/* Prepare the context for reading audio samples. */
-void spek_audio_start (SpekAudioContext *cx, gint samples);
+// Prepare the context for reading audio samples.
+void spek_audio_start(struct spek_audio_context *cx, int samples);
-/* Read and decode the opened audio stream.
- * Returns -1 on error, 0 if there's nothing left to read
- * or the number of bytes decoded into the buffer.
- */
-gint spek_audio_read (SpekAudioContext *cx);
+// Read and decode the opened audio stream.
+// Returns -1 on error, 0 if there's nothing left to read
+// or the number of bytes decoded into the buffer.
+int spek_audio_read(struct spek_audio_context *cx);
-/* Closes the file opened with spek_audio_open,
- * frees all allocated buffers and the context
- */
-void spek_audio_close (SpekAudioContext *cx);
+// Closes the file opened with spek_audio_open,
+// frees all allocated buffers and the context
+void spek_audio_close(struct spek_audio_context *cx);
+
+#ifdef __cplusplus
+}
+#endif
#endif