spek

Acoustic spectrum analyser
git clone http://git.hanabi.in/repos/spek.git
Log | Files | Refs | README

commit 92dd6a8bbfa73b914e6dabd8033afd836394c7e0
parent 98ba100f0ce41fbf8547a8eb3eecdc0859ba6928
Author: Alexander Kojevnikov <alexander@kojevnikov.com>
Date:   Sun,  5 Aug 2012 23:04:29 -0700

Add spek-audio.c

Diffstat:
Msrc/Makefile.am | 2++
Msrc/spek-audio.c | 134++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/spek-audio.h | 92+++++++++++++++++++++++++++++++++++++++++++------------------------------------
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