mirror of
https://github.com/alexkay/spek.git
synced 2025-04-16 00:30:34 +03:00
Untabify
This commit is contained in:
parent
72bf4ad3ea
commit
045253bd70
2
dist/osx/bundle.sh
vendored
2
dist/osx/bundle.sh
vendored
@ -66,7 +66,7 @@ hdiutil convert -quiet -format UDBZ -o $DMG_FILE $DMG_FILE.master
|
||||
echo "Done."
|
||||
|
||||
if [ ! "x$1" = "x-m" ]; then
|
||||
rm $DMG_FILE.master
|
||||
rm $DMG_FILE.master
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
|
64
dist/osx/launcher.sh
vendored
64
dist/osx/launcher.sh
vendored
@ -46,27 +46,27 @@ if test "$APPLELANGUAGES"; then
|
||||
# A language ordering exists.
|
||||
# Test, item per item, to see whether there is an corresponding locale.
|
||||
for L in $APPLELANGUAGES; do
|
||||
#test for exact matches:
|
||||
#test for exact matches:
|
||||
if test -f "$I18NDIR/${L}/LC_MESSAGES/$APP.mo"; then
|
||||
export LANG=$L
|
||||
export LANG=$L
|
||||
break
|
||||
fi
|
||||
#This is a special case, because often the original strings are in US
|
||||
#English and there is no translation file.
|
||||
if test "x$L" == "xen_US"; then
|
||||
export LANG=$L
|
||||
break
|
||||
fi
|
||||
#OK, now test for just the first two letters:
|
||||
#This is a special case, because often the original strings are in US
|
||||
#English and there is no translation file.
|
||||
if test "x$L" == "xen_US"; then
|
||||
export LANG=$L
|
||||
break
|
||||
fi
|
||||
#OK, now test for just the first two letters:
|
||||
if test -f "$I18NDIR/${L:0:2}/LC_MESSAGES/$APP.mo"; then
|
||||
export LANG=${L:0:2}
|
||||
break
|
||||
fi
|
||||
#Same thing, but checking for any english variant.
|
||||
if test "x${L:0:2}" == "xen"; then
|
||||
export LANG=$L
|
||||
break
|
||||
fi;
|
||||
export LANG=${L:0:2}
|
||||
break
|
||||
fi
|
||||
#Same thing, but checking for any english variant.
|
||||
if test "x${L:0:2}" == "xen"; then
|
||||
export LANG=$L
|
||||
break
|
||||
fi;
|
||||
done
|
||||
fi
|
||||
unset APPLELANGUAGES L
|
||||
@ -75,7 +75,7 @@ unset APPLELANGUAGES L
|
||||
APPLECOLLATION=`defaults read .GlobalPreferences AppleCollationOrder`
|
||||
if test -z ${LANG} -a -n $APPLECOLLATION; then
|
||||
if test -f "$I18NDIR/${APPLECOLLATION:0:2}/LC_MESSAGES/$APP.mo"; then
|
||||
export LANG=${APPLECOLLATION:0:2}
|
||||
export LANG=${APPLECOLLATION:0:2}
|
||||
fi
|
||||
fi
|
||||
if test ! -z $APPLECOLLATION; then
|
||||
@ -104,21 +104,21 @@ if test -n $LANG; then
|
||||
#locale; otherwise, if it's longer than two characters, then it's
|
||||
#probably a good message locale and we'll go with it.
|
||||
if test $LANG == ${APPLELOCALE:0:5} -o $LANG != ${LANG:0:2}; then
|
||||
export LC_MESSAGES=$LANG
|
||||
export LC_MESSAGES=$LANG
|
||||
#Next try if the Applelocale is longer than 2 chars and the language
|
||||
#bit matches $LANG
|
||||
elif test $LANG == ${APPLELOCALE:0:2} -a $APPLELOCALE > ${APPLELOCALE:0:2}; then
|
||||
export LC_MESSAGES=${APPLELOCALE:0:5}
|
||||
export LC_MESSAGES=${APPLELOCALE:0:5}
|
||||
#Fail. Get a list of the locales in $PREFIX/share/locale that match
|
||||
#our two letter language code and pick the first one, special casing
|
||||
#english to set en_US
|
||||
elif test $LANG == "en"; then
|
||||
export LC_MESSAGES="en_US"
|
||||
export LC_MESSAGES="en_US"
|
||||
else
|
||||
LOC=`find $PREFIX/share/locale -name $LANG???`
|
||||
for L in $LOC; do
|
||||
export LC_MESSAGES=$L
|
||||
done
|
||||
LOC=`find $PREFIX/share/locale -name $LANG???`
|
||||
for L in $LOC; do
|
||||
export LC_MESSAGES=$L
|
||||
done
|
||||
fi
|
||||
else
|
||||
#All efforts have failed, so default to US english
|
||||
@ -129,15 +129,15 @@ CURRENCY=`echo $APPLELOCALE | sed -En 's/.*currency=([[:alpha:]]+).*/\1/p'`
|
||||
if test "x$CURRENCY" != "x"; then
|
||||
#The user has set a special currency. Gtk doesn't install LC_MONETARY files, but Apple does in /usr/share/locale, so we're going to look there for a locale to set LC_CURRENCY to.
|
||||
if test -f /usr/local/share/$LC_MESSAGES/LC_MONETARY; then
|
||||
if test -a `cat /usr/local/share/$LC_MESSAGES/LC_MONETARY` == $CURRENCY; then
|
||||
export LC_MONETARY=$LC_MESSAGES
|
||||
fi
|
||||
if test -a `cat /usr/local/share/$LC_MESSAGES/LC_MONETARY` == $CURRENCY; then
|
||||
export LC_MONETARY=$LC_MESSAGES
|
||||
fi
|
||||
fi
|
||||
if test -z "$LC_MONETARY"; then
|
||||
FILES=`find /usr/share/locale -name LC_MONETARY -exec grep -H $CURRENCY {} \;`
|
||||
if test -n "$FILES"; then
|
||||
export LC_MONETARY=`echo $FILES | sed -En 's%/usr/share/locale/([[:alpha:]_]+)/LC_MONETARY.*%\1%p'`
|
||||
fi
|
||||
FILES=`find /usr/share/locale -name LC_MONETARY -exec grep -H $CURRENCY {} \;`
|
||||
if test -n "$FILES"; then
|
||||
export LC_MONETARY=`echo $FILES | sed -En 's%/usr/share/locale/([[:alpha:]_]+)/LC_MONETARY.*%\1%p'`
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
#No currency value means that the AppleLocale governs:
|
||||
|
70
dist/osx/spek.modules.in
vendored
70
dist/osx/spek.modules.in
vendored
@ -2,44 +2,44 @@
|
||||
<!DOCTYPE moduleset SYSTEM "moduleset.dtd">
|
||||
<?xml-stylesheet type="text/xsl" href="moduleset.xsl"?>
|
||||
<moduleset>
|
||||
<include href="http://github.com/jralls/gtk-osx-build/raw/master/modulesets-stable/gtk-osx.modules"/>
|
||||
<include href="http://github.com/jralls/gtk-osx-build/raw/master/modulesets-stable/gtk-osx.modules"/>
|
||||
|
||||
<repository type="tarball" name="spek" default="yes" href="http://spek.googlecode.com/files/"/>
|
||||
<repository type="tarball" name="libav" href="http://libav.org/releases/"/>
|
||||
<repository type="tarball" name="cairographics-dev" href="http://cairographics.org/snapshots/"/>
|
||||
<repository type="git" name="github.com" href="git://github.com/"/>
|
||||
<repository type="tarball" name="spek" default="yes" href="http://spek.googlecode.com/files/"/>
|
||||
<repository type="tarball" name="libav" href="http://libav.org/releases/"/>
|
||||
<repository type="tarball" name="cairographics-dev" href="http://cairographics.org/snapshots/"/>
|
||||
<repository type="git" name="github.com" href="git://github.com/"/>
|
||||
|
||||
<autotools id="cairo" autogen-sh="configure" autogenargs="--enable-pdf --enable-quartz --enable-xlib=no --without-x">
|
||||
<branch module="cairo-1.11.2.tar.gz" version="1.11.2" repo="cairographics-dev"/>
|
||||
<dependencies>
|
||||
<dep package="pixman"/>
|
||||
</dependencies>
|
||||
<after>
|
||||
<dep package="meta-gtk-osx-bootstrap"/>
|
||||
<dep package="fontconfig"/>
|
||||
<dep package="freetype"/>
|
||||
</after>
|
||||
</autotools>
|
||||
<autotools id="cairo" autogen-sh="configure" autogenargs="--enable-pdf --enable-quartz --enable-xlib=no --without-x">
|
||||
<branch module="cairo-1.11.2.tar.gz" version="1.11.2" repo="cairographics-dev"/>
|
||||
<dependencies>
|
||||
<dep package="pixman"/>
|
||||
</dependencies>
|
||||
<after>
|
||||
<dep package="meta-gtk-osx-bootstrap"/>
|
||||
<dep package="fontconfig"/>
|
||||
<dep package="freetype"/>
|
||||
</after>
|
||||
</autotools>
|
||||
|
||||
<autotools id="gtk-quartz-engine">
|
||||
<branch module="jralls/gtk-quartz-engine" repo="github.com"/>
|
||||
<after>
|
||||
<dep package="meta-gtk-osx-core"/>
|
||||
</after>
|
||||
</autotools>
|
||||
<autotools id="gtk-quartz-engine">
|
||||
<branch module="jralls/gtk-quartz-engine" repo="github.com"/>
|
||||
<after>
|
||||
<dep package="meta-gtk-osx-core"/>
|
||||
</after>
|
||||
</autotools>
|
||||
|
||||
<autotools id="libav" autogenargs="--disable-static --enable-shared --enable-gpl --enable-version3 --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver --disable-avdevice --disable-swscale --enable-pthreads --disable-encoders --disable-muxers --disable-devices --disable-filters" autogen-sh="configure" autogen-template="%(srcdir)s/%(autogen-sh)s --prefix=%(prefix)s --libdir=%(libdir)s %(autogenargs)s">
|
||||
<branch module="libav-0.6.2.tar.bz2" version="0.6.2" repo="libav" hash="sha1:b79dc56a08f4ef07b41d1a78b2251f21fde8b81d"/>
|
||||
</autotools>
|
||||
<autotools id="libav" autogenargs="--disable-static --enable-shared --enable-gpl --enable-version3 --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver --disable-avdevice --disable-swscale --enable-pthreads --disable-encoders --disable-muxers --disable-devices --disable-filters" autogen-sh="configure" autogen-template="%(srcdir)s/%(autogen-sh)s --prefix=%(prefix)s --libdir=%(libdir)s %(autogenargs)s">
|
||||
<branch module="libav-0.6.2.tar.bz2" version="0.6.2" repo="libav" hash="sha1:b79dc56a08f4ef07b41d1a78b2251f21fde8b81d"/>
|
||||
</autotools>
|
||||
|
||||
<autotools id="spek" autogen-sh="configure">
|
||||
<branch module="spek-@VERSION@.tar.bz2" version="@VERSION@" repo="spek"/>
|
||||
<dependencies>
|
||||
<dep package="meta-gtk-osx-bootstrap"/>
|
||||
<dep package="meta-gtk-osx-core"/>
|
||||
<dep package="cairo"/>
|
||||
<dep package="gtk-quartz-engine"/>
|
||||
<dep package="libav"/>
|
||||
</dependencies>
|
||||
</autotools>
|
||||
<autotools id="spek" autogen-sh="configure">
|
||||
<branch module="spek-@VERSION@.tar.bz2" version="@VERSION@" repo="spek"/>
|
||||
<dependencies>
|
||||
<dep package="meta-gtk-osx-bootstrap"/>
|
||||
<dep package="meta-gtk-osx-core"/>
|
||||
<dep package="cairo"/>
|
||||
<dep package="gtk-quartz-engine"/>
|
||||
<dep package="libav"/>
|
||||
</dependencies>
|
||||
</autotools>
|
||||
</moduleset>
|
||||
|
332
src/spek-audio.c
332
src/spek-audio.c
@ -22,188 +22,188 @@
|
||||
#include "spek-audio.h"
|
||||
|
||||
void spek_audio_init () {
|
||||
avcodec_init ();
|
||||
/* TODO: register only audio decoders */
|
||||
av_register_all ();
|
||||
avcodec_init ();
|
||||
/* TODO: register only audio decoders */
|
||||
av_register_all ();
|
||||
}
|
||||
|
||||
SpekAudioContext * spek_audio_open (const gchar *file_name) {
|
||||
SpekAudioContext *cx;
|
||||
int i;
|
||||
SpekAudioContext *cx;
|
||||
int i;
|
||||
|
||||
cx = g_new0 (SpekAudioContext, 1);
|
||||
cx->file_name = g_strdup (file_name);
|
||||
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);
|
||||
/* 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
|
||||
|
||||
if (av_open_input_file (&cx->format_context, file_name, NULL, 0, NULL) != 0) {
|
||||
if (!cx->short_name ||
|
||||
av_open_input_file (&cx->format_context, cx->short_name, NULL, 0, NULL) != 0 ) {
|
||||
cx->error = _("Cannot open input file");
|
||||
return cx;
|
||||
}
|
||||
}
|
||||
if (av_find_stream_info (cx->format_context) < 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++) {
|
||||
if (cx->format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
cx->audio_stream = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cx->audio_stream == -1) {
|
||||
cx->error = _("The file contains no audio streams");
|
||||
return cx;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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. */
|
||||
cx->bits_per_sample = cx->codec_context->bits_per_coded_sample;
|
||||
}
|
||||
cx->channels = cx->codec_context->channels;
|
||||
cx->duration = cx->stream->duration * av_q2d (cx->stream->time_base);
|
||||
if (cx->channels <= 0) {
|
||||
cx->error = _("No audio channels");
|
||||
return cx;
|
||||
}
|
||||
if (avcodec_open (cx->codec_context, cx->codec) < 0) {
|
||||
cx->error = _("Cannot open decoder");
|
||||
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;
|
||||
}
|
||||
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->offset = 0;
|
||||
return cx;
|
||||
if (av_open_input_file (&cx->format_context, file_name, NULL, 0, NULL) != 0) {
|
||||
if (!cx->short_name ||
|
||||
av_open_input_file (&cx->format_context, cx->short_name, NULL, 0, NULL) != 0 ) {
|
||||
cx->error = _("Cannot open input file");
|
||||
return cx;
|
||||
}
|
||||
}
|
||||
if (av_find_stream_info (cx->format_context) < 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++) {
|
||||
if (cx->format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
cx->audio_stream = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cx->audio_stream == -1) {
|
||||
cx->error = _("The file contains no audio streams");
|
||||
return cx;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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. */
|
||||
cx->bits_per_sample = cx->codec_context->bits_per_coded_sample;
|
||||
}
|
||||
cx->channels = cx->codec_context->channels;
|
||||
cx->duration = cx->stream->duration * av_q2d (cx->stream->time_base);
|
||||
if (cx->channels <= 0) {
|
||||
cx->error = _("No audio channels");
|
||||
return cx;
|
||||
}
|
||||
if (avcodec_open (cx->codec_context, cx->codec) < 0) {
|
||||
cx->error = _("Cannot open decoder");
|
||||
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;
|
||||
}
|
||||
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->offset = 0;
|
||||
return cx;
|
||||
}
|
||||
|
||||
void spek_audio_start (SpekAudioContext *cx, gint samples) {
|
||||
gint64 rate = cx->sample_rate * (gint64) cx->stream->time_base.num;
|
||||
cx->error_base = samples * (gint64) cx->stream->time_base.den;
|
||||
cx->frames_per_interval = av_rescale_rnd (
|
||||
cx->stream->duration, rate, cx->error_base, AV_ROUND_DOWN);
|
||||
cx->error_per_interval = (cx->stream->duration * rate) % cx->error_base;
|
||||
gint64 rate = cx->sample_rate * (gint64) cx->stream->time_base.num;
|
||||
cx->error_base = samples * (gint64) cx->stream->time_base.den;
|
||||
cx->frames_per_interval = av_rescale_rnd (
|
||||
cx->stream->duration, rate, cx->error_base, AV_ROUND_DOWN);
|
||||
cx->error_per_interval = (cx->stream->duration * rate) % cx->error_base;
|
||||
}
|
||||
|
||||
gint spek_audio_read (SpekAudioContext *cx) {
|
||||
gint buffer_size;
|
||||
gint len;
|
||||
gint res;
|
||||
gint buffer_size;
|
||||
gint len;
|
||||
gint res;
|
||||
|
||||
if (cx->error) {
|
||||
return -1;
|
||||
}
|
||||
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);
|
||||
if (len < 0) {
|
||||
/* Error, skip the frame. */
|
||||
cx->packet->size = 0;
|
||||
break;
|
||||
}
|
||||
cx->packet->data += len;
|
||||
cx->packet->size -= len;
|
||||
cx->offset += len;
|
||||
if (buffer_size <= 0) {
|
||||
/* No data yet, get more frames */
|
||||
continue;
|
||||
}
|
||||
/* We have data, return it and come back for more later */
|
||||
return buffer_size;
|
||||
}
|
||||
if (cx->packet->data) {
|
||||
cx->packet->data -= cx->offset;
|
||||
cx->packet->size += cx->offset;
|
||||
cx->offset = 0;
|
||||
av_free_packet (cx->packet);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (res < 0) {
|
||||
/* End of file or error. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (len < 0) {
|
||||
/* Error, skip the frame. */
|
||||
cx->packet->size = 0;
|
||||
break;
|
||||
}
|
||||
cx->packet->data += len;
|
||||
cx->packet->size -= len;
|
||||
cx->offset += len;
|
||||
if (buffer_size <= 0) {
|
||||
/* No data yet, get more frames */
|
||||
continue;
|
||||
}
|
||||
/* We have data, return it and come back for more later */
|
||||
return buffer_size;
|
||||
}
|
||||
if (cx->packet->data) {
|
||||
cx->packet->data -= cx->offset;
|
||||
cx->packet->size += cx->offset;
|
||||
cx->offset = 0;
|
||||
av_free_packet (cx->packet);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (res < 0) {
|
||||
/* End of file or error. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spek_audio_close (SpekAudioContext *cx) {
|
||||
if (cx->file_name != NULL) {
|
||||
g_free (cx->file_name);
|
||||
}
|
||||
if (cx->short_name != NULL) {
|
||||
g_free (cx->short_name);
|
||||
}
|
||||
if (cx->codec_name != NULL) {
|
||||
g_free (cx->codec_name);
|
||||
}
|
||||
if (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 (cx->packet);
|
||||
}
|
||||
if (cx->codec_context != NULL) {
|
||||
avcodec_close (cx->codec_context);
|
||||
}
|
||||
if (cx->format_context != NULL) {
|
||||
av_close_input_file (cx->format_context);
|
||||
}
|
||||
g_free (cx);
|
||||
if (cx->file_name != NULL) {
|
||||
g_free (cx->file_name);
|
||||
}
|
||||
if (cx->short_name != NULL) {
|
||||
g_free (cx->short_name);
|
||||
}
|
||||
if (cx->codec_name != NULL) {
|
||||
g_free (cx->codec_name);
|
||||
}
|
||||
if (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 (cx->packet);
|
||||
}
|
||||
if (cx->codec_context != NULL) {
|
||||
avcodec_close (cx->codec_context);
|
||||
}
|
||||
if (cx->format_context != NULL) {
|
||||
av_close_input_file (cx->format_context);
|
||||
}
|
||||
g_free (cx);
|
||||
}
|
||||
|
@ -24,32 +24,32 @@
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
typedef struct {
|
||||
/* Internal data */
|
||||
gchar *short_name;
|
||||
AVFormatContext *format_context;
|
||||
gint audio_stream;
|
||||
AVCodecContext *codec_context;
|
||||
AVStream *stream;
|
||||
AVCodec *codec;
|
||||
gint buffer_size;
|
||||
AVPacket *packet;
|
||||
gint offset;
|
||||
/* Internal data */
|
||||
gchar *short_name;
|
||||
AVFormatContext *format_context;
|
||||
gint audio_stream;
|
||||
AVCodecContext *codec_context;
|
||||
AVStream *stream;
|
||||
AVCodec *codec;
|
||||
gint buffer_size;
|
||||
AVPacket *packet;
|
||||
gint 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;
|
||||
/* 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;
|
||||
|
||||
/* Initialise FFmpeg, should be called once on start up */
|
||||
|
@ -22,38 +22,38 @@
|
||||
#include "spek-fft.h"
|
||||
|
||||
SpekFftPlan * spek_fft_plan_new (gint n, gint threshold) {
|
||||
gint bits;
|
||||
SpekFftPlan *p = g_new0 (SpekFftPlan, 1);
|
||||
p->input = av_mallocz (sizeof (gfloat) * n);
|
||||
p->output = av_mallocz (sizeof (gfloat) * (n / 2 + 1));
|
||||
p->threshold = threshold;
|
||||
for (bits = 0; n; n >>= 1, bits++);
|
||||
p->n = 1 << --bits;
|
||||
p->cx = av_rdft_init (bits, DFT_R2C);
|
||||
return p;
|
||||
gint bits;
|
||||
SpekFftPlan *p = g_new0 (SpekFftPlan, 1);
|
||||
p->input = av_mallocz (sizeof (gfloat) * n);
|
||||
p->output = av_mallocz (sizeof (gfloat) * (n / 2 + 1));
|
||||
p->threshold = threshold;
|
||||
for (bits = 0; n; n >>= 1, bits++);
|
||||
p->n = 1 << --bits;
|
||||
p->cx = av_rdft_init (bits, DFT_R2C);
|
||||
return p;
|
||||
}
|
||||
|
||||
void spek_fft_execute (SpekFftPlan *p) {
|
||||
int i;
|
||||
int n = p->n;
|
||||
int i;
|
||||
int n = p->n;
|
||||
|
||||
av_rdft_calc (p->cx, p->input);
|
||||
av_rdft_calc (p->cx, p->input);
|
||||
|
||||
/* Calculate magnitudes */
|
||||
p->output[0] = p->input[0] * p->input[0] / (n * n);
|
||||
p->output[n / 2] = p->input[1] * p->input[1] / (n * n);
|
||||
for (i = 1; i < n / 2; i++) {
|
||||
gfloat val;
|
||||
val = p->input[i * 2] * p->input[i * 2] + p->input[i * 2 + 1] * p->input[i * 2 + 1];
|
||||
val /= n * n;
|
||||
val = 10.0 * log10f (val);
|
||||
p->output[i] = val < p->threshold ? p->threshold : val;
|
||||
}
|
||||
/* Calculate magnitudes */
|
||||
p->output[0] = p->input[0] * p->input[0] / (n * n);
|
||||
p->output[n / 2] = p->input[1] * p->input[1] / (n * n);
|
||||
for (i = 1; i < n / 2; i++) {
|
||||
gfloat val;
|
||||
val = p->input[i * 2] * p->input[i * 2] + p->input[i * 2 + 1] * p->input[i * 2 + 1];
|
||||
val /= n * n;
|
||||
val = 10.0 * log10f (val);
|
||||
p->output[i] = val < p->threshold ? p->threshold : val;
|
||||
}
|
||||
}
|
||||
|
||||
void spek_fft_destroy (SpekFftPlan *p) {
|
||||
av_rdft_end (p->cx);
|
||||
av_free (p->input);
|
||||
av_free (p->output);
|
||||
g_free (p);
|
||||
av_rdft_end (p->cx);
|
||||
av_free (p->input);
|
||||
av_free (p->output);
|
||||
g_free (p);
|
||||
}
|
||||
|
@ -23,14 +23,14 @@
|
||||
#include <libavcodec/avfft.h>
|
||||
|
||||
typedef struct {
|
||||
/* Internal data */
|
||||
RDFTContext *cx;
|
||||
gint n;
|
||||
gint threshold;
|
||||
/* Internal data */
|
||||
RDFTContext *cx;
|
||||
gint n;
|
||||
gint threshold;
|
||||
|
||||
/* Exposed properties */
|
||||
gfloat *input;
|
||||
gfloat *output;
|
||||
/* Exposed properties */
|
||||
gfloat *input;
|
||||
gfloat *output;
|
||||
} SpekFftPlan;
|
||||
|
||||
/* Allocate buffers and create a new FFT plan */
|
||||
|
@ -22,61 +22,61 @@
|
||||
using Gtk;
|
||||
|
||||
namespace Spek {
|
||||
public class MessageBar : HBox {
|
||||
private Label label;
|
||||
private Gtk.Window win;
|
||||
public class MessageBar : HBox {
|
||||
private Label label;
|
||||
private Gtk.Window win;
|
||||
|
||||
public MessageBar (string message) {
|
||||
homogeneous = false;
|
||||
spacing = 0;
|
||||
border_width = 6;
|
||||
public MessageBar (string message) {
|
||||
homogeneous = false;
|
||||
spacing = 0;
|
||||
border_width = 6;
|
||||
|
||||
win = new Gtk.Window (WindowType.POPUP);
|
||||
win.name = "gtk-tooltips";
|
||||
win.ensure_style ();
|
||||
win.style_set.connect (() => style = win.style);
|
||||
win = new Gtk.Window (WindowType.POPUP);
|
||||
win.name = "gtk-tooltips";
|
||||
win.ensure_style ();
|
||||
win.style_set.connect (() => style = win.style);
|
||||
|
||||
label = new Label (null);
|
||||
label.use_markup = true;
|
||||
label.set_markup (message);
|
||||
label.ellipsize = Pango.EllipsizeMode.END;
|
||||
label.xalign = 0f;
|
||||
label.activate_link.connect (uri => { Platform.show_uri (uri); return true; });
|
||||
var button_box = new HBox (false, 0);
|
||||
button_box.spacing = 3;
|
||||
var close_button = new Button ();
|
||||
close_button.image = new Gtk.Image.from_stock (Stock.CLOSE, IconSize.MENU);
|
||||
close_button.relief = ReliefStyle.NONE;
|
||||
close_button.clicked.connect (() => hide ());
|
||||
label = new Label (null);
|
||||
label.use_markup = true;
|
||||
label.set_markup (message);
|
||||
label.ellipsize = Pango.EllipsizeMode.END;
|
||||
label.xalign = 0f;
|
||||
label.activate_link.connect (uri => { Platform.show_uri (uri); return true; });
|
||||
var button_box = new HBox (false, 0);
|
||||
button_box.spacing = 3;
|
||||
var close_button = new Button ();
|
||||
close_button.image = new Gtk.Image.from_stock (Stock.CLOSE, IconSize.MENU);
|
||||
close_button.relief = ReliefStyle.NONE;
|
||||
close_button.clicked.connect (() => hide ());
|
||||
|
||||
pack_start (label, true, true, 0);
|
||||
pack_start (button_box, false, false, 0);
|
||||
pack_start (close_button, false, false, 0);
|
||||
}
|
||||
pack_start (label, true, true, 0);
|
||||
pack_start (button_box, false, false, 0);
|
||||
pack_start (close_button, false, false, 0);
|
||||
}
|
||||
|
||||
private bool changing_style = false;
|
||||
protected override void style_set (Style? previous_style) {
|
||||
if (changing_style) {
|
||||
return;
|
||||
}
|
||||
private bool changing_style = false;
|
||||
protected override void style_set (Style? previous_style) {
|
||||
if (changing_style) {
|
||||
return;
|
||||
}
|
||||
|
||||
changing_style = true;
|
||||
style = win.style;
|
||||
label.style = style;
|
||||
changing_style = false;
|
||||
}
|
||||
changing_style = true;
|
||||
style = win.style;
|
||||
label.style = style;
|
||||
changing_style = false;
|
||||
}
|
||||
|
||||
protected override bool expose_event (Gdk.EventExpose event) {
|
||||
if (!is_drawable ()) {
|
||||
return false;
|
||||
}
|
||||
protected override bool expose_event (Gdk.EventExpose event) {
|
||||
if (!is_drawable ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var cr = Gdk.cairo_create (event.window);
|
||||
var color = style.bg[StateType.NORMAL];
|
||||
cr.set_source_rgb (color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0);
|
||||
cr.rectangle (allocation.x, allocation.y, allocation.width, allocation.height);
|
||||
cr.fill ();
|
||||
return base.expose_event (event);
|
||||
}
|
||||
}
|
||||
var cr = Gdk.cairo_create (event.window);
|
||||
var color = style.bg[StateType.NORMAL];
|
||||
cr.set_source_rgb (color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0);
|
||||
cr.rectangle (allocation.x, allocation.y, allocation.width, allocation.height);
|
||||
cr.fill ();
|
||||
return base.expose_event (event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,279 +24,279 @@
|
||||
*/
|
||||
|
||||
namespace Spek {
|
||||
public class Pipeline {
|
||||
public string description { get; private set; }
|
||||
public int sample_rate { get; private set; }
|
||||
public double duration { get { return cx.duration; } }
|
||||
public delegate void Callback (int sample, float[] values);
|
||||
public class Pipeline {
|
||||
public string description { get; private set; }
|
||||
public int sample_rate { get; private set; }
|
||||
public double duration { get { return cx.duration; } }
|
||||
public delegate void Callback (int sample, float[] values);
|
||||
|
||||
private Audio.Context cx;
|
||||
private int bands;
|
||||
private int samples;
|
||||
private int threshold;
|
||||
private Callback cb;
|
||||
private Audio.Context cx;
|
||||
private int bands;
|
||||
private int samples;
|
||||
private int threshold;
|
||||
private Callback cb;
|
||||
|
||||
private Fft.Plan fft;
|
||||
private int nfft; // Size of the FFT transform.
|
||||
private float[] coss; // Pre-computed cos table.
|
||||
private const int NFFT = 64; // Number of FFTs to pre-fetch.
|
||||
private int input_size;
|
||||
private int input_pos;
|
||||
private float[] input;
|
||||
private float[] output;
|
||||
private Fft.Plan fft;
|
||||
private int nfft; // Size of the FFT transform.
|
||||
private float[] coss; // Pre-computed cos table.
|
||||
private const int NFFT = 64; // Number of FFTs to pre-fetch.
|
||||
private int input_size;
|
||||
private int input_pos;
|
||||
private float[] input;
|
||||
private float[] output;
|
||||
|
||||
private unowned Thread<void*> reader_thread = null;
|
||||
private unowned Thread<void*> worker_thread;
|
||||
private Mutex reader_mutex;
|
||||
private Cond reader_cond;
|
||||
private Mutex worker_mutex;
|
||||
private Cond worker_cond;
|
||||
private bool worker_done = false;
|
||||
private bool quit = false;
|
||||
private unowned Thread<void*> reader_thread = null;
|
||||
private unowned Thread<void*> worker_thread;
|
||||
private Mutex reader_mutex;
|
||||
private Cond reader_cond;
|
||||
private Mutex worker_mutex;
|
||||
private Cond worker_cond;
|
||||
private bool worker_done = false;
|
||||
private bool quit = false;
|
||||
|
||||
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;
|
||||
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.
|
||||
string[] items = {};
|
||||
if (cx.codec_name != null) {
|
||||
items += cx.codec_name;
|
||||
}
|
||||
if (cx.bit_rate != 0) {
|
||||
items += _("%d kbps").printf ((cx.bit_rate + 500) / 1000);
|
||||
}
|
||||
if (cx.sample_rate != 0) {
|
||||
items += _("%d Hz").printf (cx.sample_rate);
|
||||
}
|
||||
// Show bits per sample only if there is no bitrate.
|
||||
if (cx.bits_per_sample != 0 && cx.bit_rate == 0) {
|
||||
items += ngettext (
|
||||
"%d bit", "%d bits", cx.bits_per_sample).printf (cx.bits_per_sample);
|
||||
}
|
||||
if (cx.channels != 0) {
|
||||
items += ngettext ("%d channel", "%d channels", cx.channels).
|
||||
printf (cx.channels);
|
||||
}
|
||||
description = items.length > 0 ? string.joinv (", ", items) : "";
|
||||
// Build the description string.
|
||||
string[] items = {};
|
||||
if (cx.codec_name != null) {
|
||||
items += cx.codec_name;
|
||||
}
|
||||
if (cx.bit_rate != 0) {
|
||||
items += _("%d kbps").printf ((cx.bit_rate + 500) / 1000);
|
||||
}
|
||||
if (cx.sample_rate != 0) {
|
||||
items += _("%d Hz").printf (cx.sample_rate);
|
||||
}
|
||||
// Show bits per sample only if there is no bitrate.
|
||||
if (cx.bits_per_sample != 0 && cx.bit_rate == 0) {
|
||||
items += ngettext (
|
||||
"%d bit", "%d bits", cx.bits_per_sample).printf (cx.bits_per_sample);
|
||||
}
|
||||
if (cx.channels != 0) {
|
||||
items += ngettext ("%d channel", "%d channels", cx.channels).
|
||||
printf (cx.channels);
|
||||
}
|
||||
description = items.length > 0 ? string.joinv (", ", items) : "";
|
||||
|
||||
if (cx.error != null) {
|
||||
// TRANSLATORS: first %s is the error message, second %s is stream description.
|
||||
description = _("%s: %s").printf (cx.error, description);
|
||||
} else {
|
||||
this.sample_rate = cx.sample_rate;
|
||||
this.nfft = 2 * bands - 2;
|
||||
this.coss = new float[nfft];
|
||||
float cf = 2f * (float) Math.PI / this.nfft;
|
||||
for (int i = 0; i < this.nfft; i++) {
|
||||
this.coss[i] = Math.cosf (cf * i);
|
||||
}
|
||||
this.fft = new Fft.Plan (nfft, threshold);
|
||||
this.input_size = nfft * (NFFT * 2 + 1);
|
||||
this.input = new float[input_size];
|
||||
this.output = new float[bands];
|
||||
this.cx.start (samples);
|
||||
}
|
||||
}
|
||||
if (cx.error != null) {
|
||||
// TRANSLATORS: first %s is the error message, second %s is stream description.
|
||||
description = _("%s: %s").printf (cx.error, description);
|
||||
} else {
|
||||
this.sample_rate = cx.sample_rate;
|
||||
this.nfft = 2 * bands - 2;
|
||||
this.coss = new float[nfft];
|
||||
float cf = 2f * (float) Math.PI / this.nfft;
|
||||
for (int i = 0; i < this.nfft; i++) {
|
||||
this.coss[i] = Math.cosf (cf * i);
|
||||
}
|
||||
this.fft = new Fft.Plan (nfft, threshold);
|
||||
this.input_size = nfft * (NFFT * 2 + 1);
|
||||
this.input = new float[input_size];
|
||||
this.output = new float[bands];
|
||||
this.cx.start (samples);
|
||||
}
|
||||
}
|
||||
|
||||
~Pipeline () {
|
||||
stop ();
|
||||
}
|
||||
~Pipeline () {
|
||||
stop ();
|
||||
}
|
||||
|
||||
public void start () {
|
||||
stop ();
|
||||
public void start () {
|
||||
stop ();
|
||||
|
||||
if (cx.error != null) return;
|
||||
if (cx.error != null) return;
|
||||
|
||||
input_pos = 0;
|
||||
reader_mutex = new Mutex ();
|
||||
reader_cond = new Cond ();
|
||||
worker_mutex = new Mutex ();
|
||||
worker_cond = new Cond ();
|
||||
input_pos = 0;
|
||||
reader_mutex = new Mutex ();
|
||||
reader_cond = new Cond ();
|
||||
worker_mutex = new Mutex ();
|
||||
worker_cond = new Cond ();
|
||||
|
||||
try {
|
||||
reader_thread = Thread.create<void*> (reader_func, true);
|
||||
} catch (ThreadError e) {
|
||||
stop ();
|
||||
}
|
||||
}
|
||||
try {
|
||||
reader_thread = Thread.create<void*> (reader_func, true);
|
||||
} catch (ThreadError e) {
|
||||
stop ();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop () {
|
||||
if (reader_thread != null) {
|
||||
lock (quit) {
|
||||
quit = true;
|
||||
}
|
||||
reader_thread.join ();
|
||||
quit = false;
|
||||
reader_thread = null;
|
||||
}
|
||||
}
|
||||
public void stop () {
|
||||
if (reader_thread != null) {
|
||||
lock (quit) {
|
||||
quit = true;
|
||||
}
|
||||
reader_thread.join ();
|
||||
quit = false;
|
||||
reader_thread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void * reader_func () {
|
||||
var timeval = TimeVal ();
|
||||
timeval.get_current_time ();
|
||||
private void * reader_func () {
|
||||
var timeval = TimeVal ();
|
||||
timeval.get_current_time ();
|
||||
|
||||
int pos = 0, prev_pos = 0;
|
||||
int block_size = cx.width * cx.channels / 8;
|
||||
int size;
|
||||
int pos = 0, prev_pos = 0;
|
||||
int block_size = cx.width * cx.channels / 8;
|
||||
int size;
|
||||
|
||||
try {
|
||||
worker_thread = Thread.create<void*> (worker_func, true);
|
||||
} catch (ThreadError e) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
worker_thread = Thread.create<void*> (worker_func, true);
|
||||
} catch (ThreadError e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while ((size = cx.read ()) > 0) {
|
||||
lock (quit) if (quit) break;
|
||||
while ((size = cx.read ()) > 0) {
|
||||
lock (quit) if (quit) break;
|
||||
|
||||
uint8 *buffer = (uint8 *) cx.buffer;
|
||||
while (size >= block_size) {
|
||||
input[pos] = average_input (buffer);
|
||||
buffer += block_size;
|
||||
size -= block_size;
|
||||
pos = (pos + 1) % input_size;
|
||||
uint8 *buffer = (uint8 *) cx.buffer;
|
||||
while (size >= block_size) {
|
||||
input[pos] = average_input (buffer);
|
||||
buffer += block_size;
|
||||
size -= block_size;
|
||||
pos = (pos + 1) % input_size;
|
||||
|
||||
// Wake up the worker if we have enough data.
|
||||
if ((pos > prev_pos ? pos : pos + input_size) - prev_pos == nfft * NFFT) {
|
||||
reader_sync (prev_pos = pos);
|
||||
}
|
||||
}
|
||||
assert (size == 0);
|
||||
}
|
||||
// Wake up the worker if we have enough data.
|
||||
if ((pos > prev_pos ? pos : pos + input_size) - prev_pos == nfft * NFFT) {
|
||||
reader_sync (prev_pos = pos);
|
||||
}
|
||||
}
|
||||
assert (size == 0);
|
||||
}
|
||||
|
||||
if (pos != prev_pos) {
|
||||
// Process the remaining data.
|
||||
reader_sync (pos);
|
||||
}
|
||||
// Force the worker to quit.
|
||||
reader_sync (-1);
|
||||
worker_thread.join ();
|
||||
return null;
|
||||
}
|
||||
if (pos != prev_pos) {
|
||||
// Process the remaining data.
|
||||
reader_sync (pos);
|
||||
}
|
||||
// Force the worker to quit.
|
||||
reader_sync (-1);
|
||||
worker_thread.join ();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void reader_sync (int pos) {
|
||||
reader_mutex.lock ();
|
||||
while (!worker_done) reader_cond.wait (reader_mutex);
|
||||
worker_done = false;
|
||||
reader_mutex.unlock ();
|
||||
private void reader_sync (int pos) {
|
||||
reader_mutex.lock ();
|
||||
while (!worker_done) reader_cond.wait (reader_mutex);
|
||||
worker_done = false;
|
||||
reader_mutex.unlock ();
|
||||
|
||||
worker_mutex.lock ();
|
||||
input_pos = pos;
|
||||
worker_cond.signal ();
|
||||
worker_mutex.unlock ();
|
||||
}
|
||||
worker_mutex.lock ();
|
||||
input_pos = pos;
|
||||
worker_cond.signal ();
|
||||
worker_mutex.unlock ();
|
||||
}
|
||||
|
||||
private void * worker_func () {
|
||||
int sample = 0;
|
||||
int64 frames = 0;
|
||||
int64 num_fft = 0;
|
||||
int64 acc_error = 0;
|
||||
int head = 0, tail = 0;
|
||||
int prev_head = 0;
|
||||
private void * worker_func () {
|
||||
int sample = 0;
|
||||
int64 frames = 0;
|
||||
int64 num_fft = 0;
|
||||
int64 acc_error = 0;
|
||||
int head = 0, tail = 0;
|
||||
int prev_head = 0;
|
||||
|
||||
Memory.set (output, 0, sizeof (float) * bands);
|
||||
Memory.set (output, 0, sizeof (float) * bands);
|
||||
|
||||
while (true) {
|
||||
reader_mutex.lock ();
|
||||
worker_done = true;
|
||||
reader_cond.signal ();
|
||||
reader_mutex.unlock ();
|
||||
while (true) {
|
||||
reader_mutex.lock ();
|
||||
worker_done = true;
|
||||
reader_cond.signal ();
|
||||
reader_mutex.unlock ();
|
||||
|
||||
worker_mutex.lock ();
|
||||
while (tail == input_pos) worker_cond.wait (worker_mutex);
|
||||
tail = input_pos;
|
||||
worker_mutex.unlock ();
|
||||
worker_mutex.lock ();
|
||||
while (tail == input_pos) worker_cond.wait (worker_mutex);
|
||||
tail = input_pos;
|
||||
worker_mutex.unlock ();
|
||||
|
||||
if (tail == -1) {
|
||||
return null;
|
||||
}
|
||||
if (tail == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
head = (head + 1) % input_size;
|
||||
if (head == tail) {
|
||||
head = prev_head;
|
||||
break;
|
||||
}
|
||||
frames++;
|
||||
while (true) {
|
||||
head = (head + 1) % input_size;
|
||||
if (head == tail) {
|
||||
head = prev_head;
|
||||
break;
|
||||
}
|
||||
frames++;
|
||||
|
||||
// If we have enough frames for an FFT or we have
|
||||
// all frames required for the interval run and FFT.
|
||||
bool int_full = acc_error < cx.error_base && frames == cx.frames_per_interval;
|
||||
bool int_over = acc_error >= cx.error_base && frames == 1 + cx.frames_per_interval;
|
||||
if (frames % nfft == 0 || ((int_full || int_over) && num_fft == 0)) {
|
||||
prev_head = head;
|
||||
for (int i = 0; i < nfft; i++) {
|
||||
float val = input[(input_size + head - nfft + i) % input_size];
|
||||
// TODO: allow the user to chose the window function
|
||||
// Hamming window.
|
||||
// val *= 0.53836f - 0.46164f * coss[i];
|
||||
// Hann window.
|
||||
val *= 0.5f * (1f - coss[i]);
|
||||
fft.input[i] = val;
|
||||
}
|
||||
fft.execute ();
|
||||
num_fft++;
|
||||
for (int i = 0; i < bands; i++) {
|
||||
output[i] += fft.output[i];
|
||||
}
|
||||
}
|
||||
// Do we have the FFTs for one interval?
|
||||
if (int_full || int_over) {
|
||||
if (int_over) {
|
||||
acc_error -= cx.error_base;
|
||||
} else {
|
||||
acc_error += cx.error_per_interval;
|
||||
}
|
||||
// If we have enough frames for an FFT or we have
|
||||
// all frames required for the interval run and FFT.
|
||||
bool int_full = acc_error < cx.error_base && frames == cx.frames_per_interval;
|
||||
bool int_over = acc_error >= cx.error_base && frames == 1 + cx.frames_per_interval;
|
||||
if (frames % nfft == 0 || ((int_full || int_over) && num_fft == 0)) {
|
||||
prev_head = head;
|
||||
for (int i = 0; i < nfft; i++) {
|
||||
float val = input[(input_size + head - nfft + i) % input_size];
|
||||
// TODO: allow the user to chose the window function
|
||||
// Hamming window.
|
||||
// val *= 0.53836f - 0.46164f * coss[i];
|
||||
// Hann window.
|
||||
val *= 0.5f * (1f - coss[i]);
|
||||
fft.input[i] = val;
|
||||
}
|
||||
fft.execute ();
|
||||
num_fft++;
|
||||
for (int i = 0; i < bands; i++) {
|
||||
output[i] += fft.output[i];
|
||||
}
|
||||
}
|
||||
// Do we have the FFTs for one interval?
|
||||
if (int_full || int_over) {
|
||||
if (int_over) {
|
||||
acc_error -= cx.error_base;
|
||||
} else {
|
||||
acc_error += cx.error_per_interval;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bands; i++) {
|
||||
output[i] /= num_fft;
|
||||
}
|
||||
for (int i = 0; i < bands; i++) {
|
||||
output[i] /= num_fft;
|
||||
}
|
||||
|
||||
if (sample == samples) break;
|
||||
cb (sample++, output);
|
||||
if (sample == samples) break;
|
||||
cb (sample++, output);
|
||||
|
||||
Memory.set (output, 0, sizeof (float) * bands);
|
||||
frames = 0;
|
||||
num_fft = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Memory.set (output, 0, sizeof (float) * bands);
|
||||
frames = 0;
|
||||
num_fft = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float average_input (uint8 *buffer) {
|
||||
int channels = cx.channels;
|
||||
float res = 0f;
|
||||
if (cx.fp) {
|
||||
if (cx.width == 32) {
|
||||
float *p = (float *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += p[i];
|
||||
}
|
||||
} else {
|
||||
assert (cx.width == 64);
|
||||
double *p = (double *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += (float) p[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cx.width == 16) {
|
||||
int16 *p = (int16 *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += p[i] / (float) int16.MAX;
|
||||
}
|
||||
} else {
|
||||
assert (cx.width == 32);
|
||||
int32 *p = (int32 *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += p[i] / (float) int32.MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res / channels;
|
||||
}
|
||||
}
|
||||
private float average_input (uint8 *buffer) {
|
||||
int channels = cx.channels;
|
||||
float res = 0f;
|
||||
if (cx.fp) {
|
||||
if (cx.width == 32) {
|
||||
float *p = (float *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += p[i];
|
||||
}
|
||||
} else {
|
||||
assert (cx.width == 64);
|
||||
double *p = (double *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += (float) p[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cx.width == 16) {
|
||||
int16 *p = (int16 *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += p[i] / (float) int16.MAX;
|
||||
}
|
||||
} else {
|
||||
assert (cx.width == 32);
|
||||
int32 *p = (int32 *) buffer;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
res += p[i] / (float) int32.MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res / channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,34 +34,34 @@
|
||||
|
||||
void spek_platform_init () {
|
||||
#ifdef G_OS_DARWIN
|
||||
g_object_new (GTK_TYPE_OSX_APPLICATION, NULL);
|
||||
g_object_new (GTK_TYPE_OSX_APPLICATION, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void spek_platform_fix_args (gchar **argv, gint argc) {
|
||||
#ifdef G_OS_WIN32
|
||||
/* Because MinGW does not support Unicode arguments we are going to
|
||||
* get them using Windows API. In addition, GLib's option parser
|
||||
* doesn't work well with utf-8 strings on Windows, converting
|
||||
* them to URIs works around this problem.
|
||||
*/
|
||||
int i;
|
||||
gchar *s, *t;
|
||||
wchar_t **wargv;
|
||||
int wargc;
|
||||
wargv = CommandLineToArgvW (GetCommandLineW (), &wargc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
s = g_utf16_to_utf8 (wargv[i], -1, NULL, NULL, NULL);
|
||||
if (s) {
|
||||
t = g_filename_to_uri (s, NULL, NULL);
|
||||
g_free (s);
|
||||
if (t) {
|
||||
g_free (argv[i]);
|
||||
argv[i] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalFree (wargv);
|
||||
/* Because MinGW does not support Unicode arguments we are going to
|
||||
* get them using Windows API. In addition, GLib's option parser
|
||||
* doesn't work well with utf-8 strings on Windows, converting
|
||||
* them to URIs works around this problem.
|
||||
*/
|
||||
int i;
|
||||
gchar *s, *t;
|
||||
wchar_t **wargv;
|
||||
int wargc;
|
||||
wargv = CommandLineToArgvW (GetCommandLineW (), &wargc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
s = g_utf16_to_utf8 (wargv[i], -1, NULL, NULL, NULL);
|
||||
if (s) {
|
||||
t = g_filename_to_uri (s, NULL, NULL);
|
||||
g_free (s);
|
||||
if (t) {
|
||||
g_free (argv[i]);
|
||||
argv[i] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalFree (wargv);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -69,141 +69,141 @@ void spek_platform_fix_args (gchar **argv, gint argc) {
|
||||
static void accel_map_foreach (gpointer data, const gchar *accel_path, guint accel_key, GdkModifierType
|
||||
accel_mods, gboolean changed)
|
||||
{
|
||||
if (accel_mods & GDK_CONTROL_MASK) {
|
||||
accel_mods &= ~GDK_CONTROL_MASK;
|
||||
accel_mods |= GDK_META_MASK;
|
||||
gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, FALSE);
|
||||
}
|
||||
if (accel_mods & GDK_CONTROL_MASK) {
|
||||
accel_mods &= ~GDK_CONTROL_MASK;
|
||||
accel_mods |= GDK_META_MASK;
|
||||
gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, FALSE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void spek_platform_fix_ui (GtkUIManager *ui)
|
||||
{
|
||||
#ifdef G_OS_DARWIN
|
||||
GtkOSXApplication *app = NULL;
|
||||
GtkOSXApplicationMenuGroup *group = NULL;
|
||||
GtkWidget *menubar = NULL;
|
||||
GtkWidget *file_quit = NULL;
|
||||
GtkWidget *edit_preferences = NULL;
|
||||
GtkWidget *help_about = NULL;
|
||||
GtkOSXApplication *app = NULL;
|
||||
GtkOSXApplicationMenuGroup *group = NULL;
|
||||
GtkWidget *menubar = NULL;
|
||||
GtkWidget *file_quit = NULL;
|
||||
GtkWidget *edit_preferences = NULL;
|
||||
GtkWidget *help_about = NULL;
|
||||
|
||||
app = g_object_new (GTK_TYPE_OSX_APPLICATION, NULL);
|
||||
menubar = gtk_ui_manager_get_widget (ui, "/MenuBar");
|
||||
file_quit = gtk_ui_manager_get_widget (ui, "/MenuBar/File/FileQuit");
|
||||
edit_preferences = gtk_ui_manager_get_widget (ui, "/MenuBar/Edit/EditPreferences");
|
||||
help_about = gtk_ui_manager_get_widget (ui, "/MenuBar/Help/HelpAbout");
|
||||
app = g_object_new (GTK_TYPE_OSX_APPLICATION, NULL);
|
||||
menubar = gtk_ui_manager_get_widget (ui, "/MenuBar");
|
||||
file_quit = gtk_ui_manager_get_widget (ui, "/MenuBar/File/FileQuit");
|
||||
edit_preferences = gtk_ui_manager_get_widget (ui, "/MenuBar/Edit/EditPreferences");
|
||||
help_about = gtk_ui_manager_get_widget (ui, "/MenuBar/Help/HelpAbout");
|
||||
|
||||
gtk_widget_hide (menubar);
|
||||
gtk_widget_hide (file_quit);
|
||||
gtk_osxapplication_set_menu_bar (app, GTK_MENU_SHELL (menubar));
|
||||
gtk_widget_hide (menubar);
|
||||
gtk_widget_hide (file_quit);
|
||||
gtk_osxapplication_set_menu_bar (app, GTK_MENU_SHELL (menubar));
|
||||
|
||||
group = gtk_osxapplication_add_app_menu_group (app);
|
||||
gtk_osxapplication_add_app_menu_item (app, group, GTK_MENU_ITEM (help_about));
|
||||
group = gtk_osxapplication_add_app_menu_group (app);
|
||||
gtk_osxapplication_add_app_menu_item (app, group, GTK_MENU_ITEM (edit_preferences));
|
||||
group = gtk_osxapplication_add_app_menu_group (app);
|
||||
gtk_osxapplication_add_app_menu_item (app, group, GTK_MENU_ITEM (help_about));
|
||||
group = gtk_osxapplication_add_app_menu_group (app);
|
||||
gtk_osxapplication_add_app_menu_item (app, group, GTK_MENU_ITEM (edit_preferences));
|
||||
|
||||
gtk_accel_map_foreach (NULL, accel_map_foreach);
|
||||
gtk_accel_map_foreach (NULL, accel_map_foreach);
|
||||
|
||||
gtk_osxapplication_ready (app);
|
||||
gtk_osxapplication_ready (app);
|
||||
#endif
|
||||
}
|
||||
|
||||
gchar *spek_platform_locale_dir () {
|
||||
static gchar *locale_dir = NULL;
|
||||
static gchar *locale_dir = NULL;
|
||||
|
||||
if (!locale_dir) {
|
||||
if (!locale_dir) {
|
||||
#ifdef G_OS_WIN32
|
||||
gchar *win32_dir;
|
||||
gchar *win32_dir;
|
||||
|
||||
win32_dir = g_win32_get_package_installation_directory_of_module (NULL);
|
||||
locale_dir = g_build_filename (win32_dir, "share", "locale", NULL);
|
||||
win32_dir = g_win32_get_package_installation_directory_of_module (NULL);
|
||||
locale_dir = g_build_filename (win32_dir, "share", "locale", NULL);
|
||||
|
||||
g_free (win32_dir);
|
||||
g_free (win32_dir);
|
||||
#else
|
||||
#ifdef G_OS_DARWIN
|
||||
GtkOSXApplication *app = NULL;
|
||||
const gchar *res_dir;
|
||||
GtkOSXApplication *app = NULL;
|
||||
const gchar *res_dir;
|
||||
|
||||
app = g_object_new (GTK_TYPE_OSX_APPLICATION, NULL);
|
||||
res_dir = gtk_osxapplication_get_resource_path (app);
|
||||
locale_dir = g_build_filename (res_dir, "share", "locale", NULL);
|
||||
app = g_object_new (GTK_TYPE_OSX_APPLICATION, NULL);
|
||||
res_dir = gtk_osxapplication_get_resource_path (app);
|
||||
locale_dir = g_build_filename (res_dir, "share", "locale", NULL);
|
||||
#else
|
||||
locale_dir = LOCALEDIR;
|
||||
locale_dir = LOCALEDIR;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return locale_dir;
|
||||
return locale_dir;
|
||||
}
|
||||
|
||||
void spek_platform_show_uri (const gchar *uri) {
|
||||
#ifdef G_OS_WIN32
|
||||
/* gtk_show_uri doesn't work on Windows... */
|
||||
ShellExecuteA (NULL, "open", uri, "", NULL, SW_SHOWNORMAL);
|
||||
/* gtk_show_uri doesn't work on Windows... */
|
||||
ShellExecuteA (NULL, "open", uri, "", NULL, SW_SHOWNORMAL);
|
||||
#else
|
||||
#ifdef G_OS_DARWIN
|
||||
/* ...or on OS X */
|
||||
CFStringRef str = NULL;
|
||||
CFURLRef url = NULL;
|
||||
/* ...or on OS X */
|
||||
CFStringRef str = NULL;
|
||||
CFURLRef url = NULL;
|
||||
|
||||
str = CFStringCreateWithCString (NULL, uri, kCFStringEncodingASCII);
|
||||
url = CFURLCreateWithString (NULL, str, NULL);
|
||||
LSOpenCFURLRef (url, NULL);
|
||||
CFRelease (url);
|
||||
CFRelease (str);
|
||||
str = CFStringCreateWithCString (NULL, uri, kCFStringEncodingASCII);
|
||||
url = CFURLCreateWithString (NULL, str, NULL);
|
||||
LSOpenCFURLRef (url, NULL);
|
||||
CFRelease (url);
|
||||
CFRelease (str);
|
||||
#else
|
||||
gtk_show_uri (NULL, uri, gtk_get_current_event_time (), NULL);
|
||||
gtk_show_uri (NULL, uri, gtk_get_current_event_time (), NULL);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
gchar *spek_platform_read_line (const gchar *uri) {
|
||||
#ifdef G_OS_DARWIN
|
||||
/* GIO doesn't work on OS X */
|
||||
CFStringRef str = NULL;
|
||||
CFURLRef url = NULL;
|
||||
CFDataRef data = NULL;
|
||||
CFIndex length = 0;
|
||||
gchar *buf = NULL;
|
||||
/* GIO doesn't work on OS X */
|
||||
CFStringRef str = NULL;
|
||||
CFURLRef url = NULL;
|
||||
CFDataRef data = NULL;
|
||||
CFIndex length = 0;
|
||||
gchar *buf = NULL;
|
||||
|
||||
str = CFStringCreateWithCString (NULL, uri, kCFStringEncodingASCII);
|
||||
url = CFURLCreateWithString (NULL, str, NULL);
|
||||
if (CFURLCreateDataAndPropertiesFromResource (NULL, url, &data, NULL, NULL, NULL)) {
|
||||
length = CFDataGetLength (data);
|
||||
buf = (gchar *) g_malloc (length + 1);
|
||||
CFDataGetBytes (data, CFRangeMake (0, length), (UInt8 *) buf);
|
||||
buf[length] = '\0';
|
||||
g_strchomp (buf);
|
||||
CFRelease (data);
|
||||
}
|
||||
CFRelease (url);
|
||||
CFRelease (str);
|
||||
return buf;
|
||||
str = CFStringCreateWithCString (NULL, uri, kCFStringEncodingASCII);
|
||||
url = CFURLCreateWithString (NULL, str, NULL);
|
||||
if (CFURLCreateDataAndPropertiesFromResource (NULL, url, &data, NULL, NULL, NULL)) {
|
||||
length = CFDataGetLength (data);
|
||||
buf = (gchar *) g_malloc (length + 1);
|
||||
CFDataGetBytes (data, CFRangeMake (0, length), (UInt8 *) buf);
|
||||
buf[length] = '\0';
|
||||
g_strchomp (buf);
|
||||
CFRelease (data);
|
||||
}
|
||||
CFRelease (url);
|
||||
CFRelease (str);
|
||||
return buf;
|
||||
#else
|
||||
gchar *line = NULL;
|
||||
GFile *file = NULL;
|
||||
GFileInputStream *file_stream = NULL;
|
||||
gchar *line = NULL;
|
||||
GFile *file = NULL;
|
||||
GFileInputStream *file_stream = NULL;
|
||||
|
||||
file = g_file_new_for_uri (uri);
|
||||
file_stream = g_file_read (file, NULL, NULL);
|
||||
if (file_stream) {
|
||||
GDataInputStream *data_stream = NULL;
|
||||
file = g_file_new_for_uri (uri);
|
||||
file_stream = g_file_read (file, NULL, NULL);
|
||||
if (file_stream) {
|
||||
GDataInputStream *data_stream = NULL;
|
||||
|
||||
data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
|
||||
line = g_data_input_stream_read_line (data_stream, NULL, NULL, NULL);
|
||||
data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
|
||||
line = g_data_input_stream_read_line (data_stream, NULL, NULL, NULL);
|
||||
|
||||
g_object_unref (data_stream);
|
||||
g_object_unref (file_stream);
|
||||
}
|
||||
g_object_unref (file);
|
||||
return line;
|
||||
g_object_unref (data_stream);
|
||||
g_object_unref (file_stream);
|
||||
}
|
||||
g_object_unref (file);
|
||||
return line;
|
||||
#endif
|
||||
}
|
||||
|
||||
gdouble spek_platform_get_font_scale () {
|
||||
#ifdef G_OS_DARWIN
|
||||
/* Pango/Quartz fonts are smaller than on X. */
|
||||
return 1.4;
|
||||
/* Pango/Quartz fonts are smaller than on X. */
|
||||
return 1.4;
|
||||
#endif
|
||||
return 1.0;
|
||||
return 1.0;
|
||||
}
|
||||
|
@ -19,86 +19,86 @@
|
||||
using Gtk;
|
||||
|
||||
namespace Spek {
|
||||
public class PreferencesDialog : Gtk.Dialog {
|
||||
// List all languages with a decent (e.g. 80%) number of translated
|
||||
// strings. Don't translate language names. Keep the first line intact.
|
||||
private static string[,] languages = {
|
||||
{"", null},
|
||||
public class PreferencesDialog : Gtk.Dialog {
|
||||
// List all languages with a decent (e.g. 80%) number of translated
|
||||
// strings. Don't translate language names. Keep the first line intact.
|
||||
private static string[,] languages = {
|
||||
{"", null},
|
||||
{"cs", "Čeština"},
|
||||
{"de", "Deutsch"},
|
||||
{"en", "English"},
|
||||
{"es", "Español"},
|
||||
{"fr", "Français"},
|
||||
{"it", "Italiano"},
|
||||
{"nl", "Nederlands"},
|
||||
{"pl", "Polski"},
|
||||
{"ru", "Русский"},
|
||||
{"sv", "Svenska"},
|
||||
{"uk", "Українська"}
|
||||
};
|
||||
{"de", "Deutsch"},
|
||||
{"en", "English"},
|
||||
{"es", "Español"},
|
||||
{"fr", "Français"},
|
||||
{"it", "Italiano"},
|
||||
{"nl", "Nederlands"},
|
||||
{"pl", "Polski"},
|
||||
{"ru", "Русский"},
|
||||
{"sv", "Svenska"},
|
||||
{"uk", "Українська"}
|
||||
};
|
||||
|
||||
public PreferencesDialog () {
|
||||
title = _("Preferences");
|
||||
modal = true;
|
||||
resizable = false;
|
||||
window_position = WindowPosition.CENTER_ON_PARENT;
|
||||
languages[0,1] = _("(system default)");
|
||||
public PreferencesDialog () {
|
||||
title = _("Preferences");
|
||||
modal = true;
|
||||
resizable = false;
|
||||
window_position = WindowPosition.CENTER_ON_PARENT;
|
||||
languages[0,1] = _("(system default)");
|
||||
|
||||
var alignment = new Alignment (0.5f, 0.5f, 1f, 1f);
|
||||
alignment.set_padding (12, 12, 12, 12);
|
||||
var box = new VBox (false, 0);
|
||||
var alignment = new Alignment (0.5f, 0.5f, 1f, 1f);
|
||||
alignment.set_padding (12, 12, 12, 12);
|
||||
var box = new VBox (false, 0);
|
||||
|
||||
var general_box = new VBox (false, 6);
|
||||
// TRANSLATORS: The name of a section in the Preferences dialog.
|
||||
var general_label = new Label (_("General"));
|
||||
var attributes = new Pango.AttrList ();
|
||||
attributes.insert (Pango.attr_weight_new (Pango.Weight.BOLD));
|
||||
general_label.attributes = attributes;
|
||||
general_label.xalign = 0;
|
||||
general_box.pack_start (general_label, false, false, 0);
|
||||
var general_alignment = new Alignment (0.5f, 0.5f, 1f, 1f);
|
||||
general_alignment.left_padding = 12;
|
||||
var general_subbox = new VBox (false, 6);
|
||||
var language_box = new HBox (false, 12);
|
||||
var language_label = new Label.with_mnemonic (_("_Language:"));
|
||||
language_box.pack_start (language_label, false, false, 0);
|
||||
var language_combo = new ComboBox.text ();
|
||||
int active_language = 0;
|
||||
var prefs = Preferences.instance;
|
||||
for (int i = 0; i < languages.length[0]; i++) {
|
||||
language_combo.append_text (languages[i,1]);
|
||||
if (languages[i,0] == prefs.language) {
|
||||
active_language = i;
|
||||
}
|
||||
}
|
||||
language_combo.active = active_language;
|
||||
language_combo.changed.connect (
|
||||
() => prefs.language = languages[language_combo.active,0]);
|
||||
language_label.mnemonic_widget = language_combo;
|
||||
language_box.pack_start (language_combo, false, false, 0);
|
||||
general_subbox.pack_start(language_box, false, false, 0);
|
||||
var check_update = new CheckButton.with_mnemonic (_("Check for _updates"));
|
||||
check_update.active = prefs.check_update;
|
||||
check_update.toggled.connect (
|
||||
() => prefs.check_update = check_update.active);
|
||||
general_subbox.pack_start (check_update, false, false, 0);
|
||||
general_alignment.add (general_subbox);
|
||||
general_box.pack_start (general_alignment, false, false, 0);
|
||||
var general_box = new VBox (false, 6);
|
||||
// TRANSLATORS: The name of a section in the Preferences dialog.
|
||||
var general_label = new Label (_("General"));
|
||||
var attributes = new Pango.AttrList ();
|
||||
attributes.insert (Pango.attr_weight_new (Pango.Weight.BOLD));
|
||||
general_label.attributes = attributes;
|
||||
general_label.xalign = 0;
|
||||
general_box.pack_start (general_label, false, false, 0);
|
||||
var general_alignment = new Alignment (0.5f, 0.5f, 1f, 1f);
|
||||
general_alignment.left_padding = 12;
|
||||
var general_subbox = new VBox (false, 6);
|
||||
var language_box = new HBox (false, 12);
|
||||
var language_label = new Label.with_mnemonic (_("_Language:"));
|
||||
language_box.pack_start (language_label, false, false, 0);
|
||||
var language_combo = new ComboBox.text ();
|
||||
int active_language = 0;
|
||||
var prefs = Preferences.instance;
|
||||
for (int i = 0; i < languages.length[0]; i++) {
|
||||
language_combo.append_text (languages[i,1]);
|
||||
if (languages[i,0] == prefs.language) {
|
||||
active_language = i;
|
||||
}
|
||||
}
|
||||
language_combo.active = active_language;
|
||||
language_combo.changed.connect (
|
||||
() => prefs.language = languages[language_combo.active,0]);
|
||||
language_label.mnemonic_widget = language_combo;
|
||||
language_box.pack_start (language_combo, false, false, 0);
|
||||
general_subbox.pack_start(language_box, false, false, 0);
|
||||
var check_update = new CheckButton.with_mnemonic (_("Check for _updates"));
|
||||
check_update.active = prefs.check_update;
|
||||
check_update.toggled.connect (
|
||||
() => prefs.check_update = check_update.active);
|
||||
general_subbox.pack_start (check_update, false, false, 0);
|
||||
general_alignment.add (general_subbox);
|
||||
general_box.pack_start (general_alignment, false, false, 0);
|
||||
|
||||
box.pack_start (general_box, false, false, 0);
|
||||
alignment.add (box);
|
||||
var vbox = (VBox) get_content_area ();
|
||||
vbox.pack_start (alignment, false, false, 0);
|
||||
vbox.show_all ();
|
||||
box.pack_start (general_box, false, false, 0);
|
||||
alignment.add (box);
|
||||
var vbox = (VBox) get_content_area ();
|
||||
vbox.pack_start (alignment, false, false, 0);
|
||||
vbox.show_all ();
|
||||
|
||||
add_button (Stock.CLOSE, ResponseType.CLOSE);
|
||||
set_default_response (ResponseType.CLOSE);
|
||||
response.connect (on_response);
|
||||
}
|
||||
add_button (Stock.CLOSE, ResponseType.CLOSE);
|
||||
set_default_response (ResponseType.CLOSE);
|
||||
response.connect (on_response);
|
||||
}
|
||||
|
||||
private void on_response (Dialog dialog, int response_id) {
|
||||
Preferences.instance.save ();
|
||||
destroy ();
|
||||
}
|
||||
}
|
||||
private void on_response (Dialog dialog, int response_id) {
|
||||
Preferences.instance.save ();
|
||||
destroy ();
|
||||
}
|
||||
}
|
||||
}
|
@ -17,80 +17,80 @@
|
||||
*/
|
||||
|
||||
namespace Spek {
|
||||
public class Preferences {
|
||||
private KeyFile key_file;
|
||||
private string file_name;
|
||||
public class Preferences {
|
||||
private KeyFile key_file;
|
||||
private string file_name;
|
||||
|
||||
private Preferences () {
|
||||
file_name = Path.build_filename (Environment.get_user_config_dir (), "spek");
|
||||
DirUtils.create_with_parents (file_name, 0755);
|
||||
file_name = Path.build_filename (file_name, "preferences");
|
||||
this.key_file = new KeyFile ();
|
||||
try {
|
||||
key_file.load_from_file (file_name, KeyFileFlags.NONE);
|
||||
} catch (KeyFileError e) {
|
||||
} catch (FileError e) {
|
||||
}
|
||||
}
|
||||
private Preferences () {
|
||||
file_name = Path.build_filename (Environment.get_user_config_dir (), "spek");
|
||||
DirUtils.create_with_parents (file_name, 0755);
|
||||
file_name = Path.build_filename (file_name, "preferences");
|
||||
this.key_file = new KeyFile ();
|
||||
try {
|
||||
key_file.load_from_file (file_name, KeyFileFlags.NONE);
|
||||
} catch (KeyFileError e) {
|
||||
} catch (FileError e) {
|
||||
}
|
||||
}
|
||||
|
||||
~Preferences () {
|
||||
save ();
|
||||
}
|
||||
~Preferences () {
|
||||
save ();
|
||||
}
|
||||
|
||||
private static Preferences _instance;
|
||||
public static Preferences instance {
|
||||
get {
|
||||
if (_instance == null) {
|
||||
_instance = new Preferences ();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
private static Preferences _instance;
|
||||
public static Preferences instance {
|
||||
get {
|
||||
if (_instance == null) {
|
||||
_instance = new Preferences ();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public void save () {
|
||||
var output = FileStream.open (file_name, "w+");
|
||||
if (output != null) {
|
||||
output.puts (key_file.to_data ());
|
||||
}
|
||||
}
|
||||
public void save () {
|
||||
var output = FileStream.open (file_name, "w+");
|
||||
if (output != null) {
|
||||
output.puts (key_file.to_data ());
|
||||
}
|
||||
}
|
||||
|
||||
public bool check_update {
|
||||
get {
|
||||
try {
|
||||
return key_file.get_boolean ("update", "check");
|
||||
} catch (KeyFileError e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
set {
|
||||
key_file.set_boolean ("update", "check", value);
|
||||
}
|
||||
}
|
||||
public bool check_update {
|
||||
get {
|
||||
try {
|
||||
return key_file.get_boolean ("update", "check");
|
||||
} catch (KeyFileError e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
set {
|
||||
key_file.set_boolean ("update", "check", value);
|
||||
}
|
||||
}
|
||||
|
||||
public int last_update {
|
||||
get {
|
||||
try {
|
||||
return key_file.get_integer ("update", "last");
|
||||
} catch (KeyFileError e) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
set {
|
||||
key_file.set_integer ("update", "last", value);
|
||||
}
|
||||
}
|
||||
public int last_update {
|
||||
get {
|
||||
try {
|
||||
return key_file.get_integer ("update", "last");
|
||||
} catch (KeyFileError e) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
set {
|
||||
key_file.set_integer ("update", "last", value);
|
||||
}
|
||||
}
|
||||
|
||||
public string language {
|
||||
owned get {
|
||||
try {
|
||||
return key_file.get_string ("general", "language");
|
||||
} catch (KeyFileError e) {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
set {
|
||||
key_file.set_string ("general", "language", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public string language {
|
||||
owned get {
|
||||
try {
|
||||
return key_file.get_string ("general", "language");
|
||||
} catch (KeyFileError e) {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
set {
|
||||
key_file.set_string ("general", "language", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,104 +20,104 @@ using Cairo;
|
||||
using Pango;
|
||||
|
||||
namespace Spek {
|
||||
class Ruler : GLib.Object {
|
||||
public enum Position {
|
||||
TOP,
|
||||
RIGHT,
|
||||
BOTTOM,
|
||||
LEFT
|
||||
}
|
||||
class Ruler : GLib.Object {
|
||||
public enum Position {
|
||||
TOP,
|
||||
RIGHT,
|
||||
BOTTOM,
|
||||
LEFT
|
||||
}
|
||||
|
||||
private Position pos;
|
||||
private string sample_label;
|
||||
private int[] factors;
|
||||
private int units;
|
||||
private double spacing;
|
||||
private Measure measure;
|
||||
private Place place;
|
||||
private FormatTick format_tick;
|
||||
private Position pos;
|
||||
private string sample_label;
|
||||
private int[] factors;
|
||||
private int units;
|
||||
private double spacing;
|
||||
private Measure measure;
|
||||
private Place place;
|
||||
private FormatTick format_tick;
|
||||
|
||||
public delegate double Measure (int unit);
|
||||
public delegate double Place (double p);
|
||||
public delegate string FormatTick (int unit);
|
||||
public delegate double Measure (int unit);
|
||||
public delegate double Place (double p);
|
||||
public delegate string FormatTick (int unit);
|
||||
|
||||
public Ruler (
|
||||
Position pos, string sample_label,
|
||||
int[] factors, int units, double spacing,
|
||||
Measure measure, Place place, FormatTick format_tick) {
|
||||
this.pos = pos;
|
||||
this.sample_label = sample_label;
|
||||
this.factors = factors;
|
||||
this.units = units;
|
||||
this.spacing = spacing;
|
||||
this.measure = measure;
|
||||
this.place = place;
|
||||
this.format_tick = format_tick;
|
||||
}
|
||||
public Ruler (
|
||||
Position pos, string sample_label,
|
||||
int[] factors, int units, double spacing,
|
||||
Measure measure, Place place, FormatTick format_tick) {
|
||||
this.pos = pos;
|
||||
this.sample_label = sample_label;
|
||||
this.factors = factors;
|
||||
this.units = units;
|
||||
this.spacing = spacing;
|
||||
this.measure = measure;
|
||||
this.place = place;
|
||||
this.format_tick = format_tick;
|
||||
}
|
||||
|
||||
public void draw (Cairo.Context cr, Pango.Layout layout) {
|
||||
// Mesure the sample label.
|
||||
int w, h;
|
||||
layout.set_text (sample_label, -1);
|
||||
layout.get_pixel_size (out w, out h);
|
||||
var size = pos == Position.TOP || pos == Position.BOTTOM ? w : h;
|
||||
public void draw (Cairo.Context cr, Pango.Layout layout) {
|
||||
// Mesure the sample label.
|
||||
int w, h;
|
||||
layout.set_text (sample_label, -1);
|
||||
layout.get_pixel_size (out w, out h);
|
||||
var size = pos == Position.TOP || pos == Position.BOTTOM ? w : h;
|
||||
|
||||
// Select the factor to use, we want some space between the labels.
|
||||
int factor = 0;
|
||||
foreach (var f in factors) {
|
||||
if (measure (f) >= spacing * size) {
|
||||
factor = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Select the factor to use, we want some space between the labels.
|
||||
int factor = 0;
|
||||
foreach (var f in factors) {
|
||||
if (measure (f) >= spacing * size) {
|
||||
factor = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the ticks.
|
||||
int[] ticks = { 0, units };
|
||||
if (factor > 0) {
|
||||
for (var tick = factor; tick < units; tick += factor) {
|
||||
if (measure (units - tick) < size * 1.2) {
|
||||
break;
|
||||
}
|
||||
ticks += tick;
|
||||
}
|
||||
// TODO: `ticks = ticks[0:-1]` crashes, file a bug.
|
||||
}
|
||||
// Add the ticks.
|
||||
int[] ticks = { 0, units };
|
||||
if (factor > 0) {
|
||||
for (var tick = factor; tick < units; tick += factor) {
|
||||
if (measure (units - tick) < size * 1.2) {
|
||||
break;
|
||||
}
|
||||
ticks += tick;
|
||||
}
|
||||
// TODO: `ticks = ticks[0:-1]` crashes, file a bug.
|
||||
}
|
||||
|
||||
// Draw the ticks.
|
||||
double GAP = 10;
|
||||
double TICK_LEN = 4;
|
||||
foreach (var tick in ticks) {
|
||||
var label = format_tick (tick);
|
||||
var p = place (measure (
|
||||
pos == Position.TOP || pos == Position.BOTTOM
|
||||
? tick : units - tick));
|
||||
layout.set_text (label, -1);
|
||||
layout.get_pixel_size (out w, out h);
|
||||
if (pos == Position.TOP) {
|
||||
cr.move_to (p - w / 2, -GAP - h);
|
||||
} else if (pos == Position.RIGHT){
|
||||
cr.move_to (GAP, p + h / 4);
|
||||
} else if (pos == Position.BOTTOM) {
|
||||
cr.move_to (p - w / 2, GAP + h);
|
||||
} else if (pos == Position.LEFT){
|
||||
cr.move_to (-w - GAP, p + h / 4);
|
||||
}
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
if (pos == Position.TOP) {
|
||||
cr.move_to (p, 0);
|
||||
cr.rel_line_to (0, -TICK_LEN);
|
||||
} else if (pos == Position.RIGHT) {
|
||||
cr.move_to (0, p);
|
||||
cr.rel_line_to (TICK_LEN, 0);
|
||||
} else if (pos == Position.BOTTOM) {
|
||||
cr.move_to (p, 0);
|
||||
cr.rel_line_to (0, TICK_LEN);
|
||||
} else if (pos == Position.LEFT) {
|
||||
cr.move_to (0, p);
|
||||
cr.rel_line_to (-TICK_LEN, 0);
|
||||
}
|
||||
cr.stroke ();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw the ticks.
|
||||
double GAP = 10;
|
||||
double TICK_LEN = 4;
|
||||
foreach (var tick in ticks) {
|
||||
var label = format_tick (tick);
|
||||
var p = place (measure (
|
||||
pos == Position.TOP || pos == Position.BOTTOM
|
||||
? tick : units - tick));
|
||||
layout.set_text (label, -1);
|
||||
layout.get_pixel_size (out w, out h);
|
||||
if (pos == Position.TOP) {
|
||||
cr.move_to (p - w / 2, -GAP - h);
|
||||
} else if (pos == Position.RIGHT){
|
||||
cr.move_to (GAP, p + h / 4);
|
||||
} else if (pos == Position.BOTTOM) {
|
||||
cr.move_to (p - w / 2, GAP + h);
|
||||
} else if (pos == Position.LEFT){
|
||||
cr.move_to (-w - GAP, p + h / 4);
|
||||
}
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
if (pos == Position.TOP) {
|
||||
cr.move_to (p, 0);
|
||||
cr.rel_line_to (0, -TICK_LEN);
|
||||
} else if (pos == Position.RIGHT) {
|
||||
cr.move_to (0, p);
|
||||
cr.rel_line_to (TICK_LEN, 0);
|
||||
} else if (pos == Position.BOTTOM) {
|
||||
cr.move_to (p, 0);
|
||||
cr.rel_line_to (0, TICK_LEN);
|
||||
} else if (pos == Position.LEFT) {
|
||||
cr.move_to (0, p);
|
||||
cr.rel_line_to (-TICK_LEN, 0);
|
||||
}
|
||||
cr.stroke ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -22,298 +22,298 @@ using Gtk;
|
||||
using Pango;
|
||||
|
||||
namespace Spek {
|
||||
class Spectrogram : DrawingArea {
|
||||
class Spectrogram : DrawingArea {
|
||||
|
||||
public string file_name { get; private set; }
|
||||
private Pipeline pipeline;
|
||||
private string info;
|
||||
private const int THRESHOLD = -92;
|
||||
private const int NFFT = 2048;
|
||||
private const int BANDS = NFFT / 2 + 1;
|
||||
public string file_name { get; private set; }
|
||||
private Pipeline pipeline;
|
||||
private string info;
|
||||
private const int THRESHOLD = -92;
|
||||
private const int NFFT = 2048;
|
||||
private const int BANDS = NFFT / 2 + 1;
|
||||
|
||||
private ImageSurface image;
|
||||
private ImageSurface palette;
|
||||
private ImageSurface image;
|
||||
private ImageSurface palette;
|
||||
|
||||
private const int LPAD = 60;
|
||||
private const int TPAD = 60;
|
||||
private const int RPAD = 80;
|
||||
private const int BPAD = 40;
|
||||
private const int GAP = 10;
|
||||
private const int RULER = 10;
|
||||
private double FONT_SCALE = Platform.get_font_scale ();
|
||||
private const int LPAD = 60;
|
||||
private const int TPAD = 60;
|
||||
private const int RPAD = 80;
|
||||
private const int BPAD = 40;
|
||||
private const int GAP = 10;
|
||||
private const int RULER = 10;
|
||||
private double FONT_SCALE = Platform.get_font_scale ();
|
||||
|
||||
public Spectrogram () {
|
||||
// Pre-draw the palette.
|
||||
palette = new ImageSurface (Format.RGB24, RULER, BANDS);
|
||||
for (int y = 0; y < BANDS; y++) {
|
||||
var color = get_color (y / (double) BANDS);
|
||||
for (int x = 0; x < RULER; x++) {
|
||||
put_pixel (palette, x, y, color);
|
||||
}
|
||||
}
|
||||
show_all ();
|
||||
}
|
||||
public Spectrogram () {
|
||||
// Pre-draw the palette.
|
||||
palette = new ImageSurface (Format.RGB24, RULER, BANDS);
|
||||
for (int y = 0; y < BANDS; y++) {
|
||||
var color = get_color (y / (double) BANDS);
|
||||
for (int x = 0; x < RULER; x++) {
|
||||
put_pixel (palette, x, y, color);
|
||||
}
|
||||
}
|
||||
show_all ();
|
||||
}
|
||||
|
||||
public void open (string file_name) {
|
||||
this.file_name = file_name;
|
||||
this.info = "";
|
||||
public void open (string file_name) {
|
||||
this.file_name = file_name;
|
||||
this.info = "";
|
||||
|
||||
start ();
|
||||
}
|
||||
start ();
|
||||
}
|
||||
|
||||
public void save (string file_name) {
|
||||
Allocation allocation;
|
||||
get_allocation (out allocation);
|
||||
var surface = new ImageSurface (Format.RGB24, allocation.width, allocation.height);
|
||||
draw (new Cairo.Context (surface));
|
||||
surface.write_to_png (file_name);
|
||||
}
|
||||
public void save (string file_name) {
|
||||
Allocation allocation;
|
||||
get_allocation (out allocation);
|
||||
var surface = new ImageSurface (Format.RGB24, allocation.width, allocation.height);
|
||||
draw (new Cairo.Context (surface));
|
||||
surface.write_to_png (file_name);
|
||||
}
|
||||
|
||||
private void start () {
|
||||
if (pipeline != null) {
|
||||
pipeline.stop ();
|
||||
}
|
||||
private void start () {
|
||||
if (pipeline != null) {
|
||||
pipeline.stop ();
|
||||
}
|
||||
|
||||
// The number of samples is the number of pixels available for the image.
|
||||
// The number of bands is fixed, FFT results are very different for
|
||||
// different values but we need some consistency.
|
||||
Allocation allocation;
|
||||
get_allocation (out allocation);
|
||||
int samples = allocation.width - LPAD - RPAD;
|
||||
if (samples > 0) {
|
||||
image = new ImageSurface (Format.RGB24, samples, BANDS);
|
||||
pipeline = new Pipeline (file_name, BANDS, samples, THRESHOLD, data_cb);
|
||||
pipeline.start ();
|
||||
info = pipeline.description;
|
||||
} else {
|
||||
image = null;
|
||||
pipeline = null;
|
||||
}
|
||||
// The number of samples is the number of pixels available for the image.
|
||||
// The number of bands is fixed, FFT results are very different for
|
||||
// different values but we need some consistency.
|
||||
Allocation allocation;
|
||||
get_allocation (out allocation);
|
||||
int samples = allocation.width - LPAD - RPAD;
|
||||
if (samples > 0) {
|
||||
image = new ImageSurface (Format.RGB24, samples, BANDS);
|
||||
pipeline = new Pipeline (file_name, BANDS, samples, THRESHOLD, data_cb);
|
||||
pipeline.start ();
|
||||
info = pipeline.description;
|
||||
} else {
|
||||
image = null;
|
||||
pipeline = null;
|
||||
}
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
private int prev_width = -1;
|
||||
protected override void size_allocate (Gdk.Rectangle allocation) {
|
||||
base.size_allocate (allocation);
|
||||
private int prev_width = -1;
|
||||
protected override void size_allocate (Gdk.Rectangle allocation) {
|
||||
base.size_allocate (allocation);
|
||||
|
||||
bool width_changed = prev_width != allocation.width;
|
||||
prev_width = allocation.width;
|
||||
bool width_changed = prev_width != allocation.width;
|
||||
prev_width = allocation.width;
|
||||
|
||||
if (file_name != null && width_changed) {
|
||||
start ();
|
||||
}
|
||||
}
|
||||
if (file_name != null && width_changed) {
|
||||
start ();
|
||||
}
|
||||
}
|
||||
|
||||
private double log10_threshold = Math.log10 (-THRESHOLD);
|
||||
private void data_cb (int sample, float[] values) {
|
||||
for (int y = 0; y < BANDS; y++) {
|
||||
var level = double.min (
|
||||
1.0, Math.log10 (1.0 - THRESHOLD + values[y]) / log10_threshold);
|
||||
put_pixel (image, sample, y, get_color (level));
|
||||
}
|
||||
Idle.add (() => { queue_draw (); return false; });
|
||||
}
|
||||
private double log10_threshold = Math.log10 (-THRESHOLD);
|
||||
private void data_cb (int sample, float[] values) {
|
||||
for (int y = 0; y < BANDS; y++) {
|
||||
var level = double.min (
|
||||
1.0, Math.log10 (1.0 - THRESHOLD + values[y]) / log10_threshold);
|
||||
put_pixel (image, sample, y, get_color (level));
|
||||
}
|
||||
Idle.add (() => { queue_draw (); return false; });
|
||||
}
|
||||
|
||||
protected override bool expose_event (EventExpose event) {
|
||||
var window = get_window ();
|
||||
var cr = cairo_create (window);
|
||||
protected override bool expose_event (EventExpose event) {
|
||||
var window = get_window ();
|
||||
var cr = cairo_create (window);
|
||||
|
||||
// Clip to the exposed area.
|
||||
cr.rectangle (event.area.x, event.area.y, event.area.width, event.area.height);
|
||||
cr.clip ();
|
||||
// Clip to the exposed area.
|
||||
cr.rectangle (event.area.x, event.area.y, event.area.width, event.area.height);
|
||||
cr.clip ();
|
||||
|
||||
draw (cr);
|
||||
return true;
|
||||
}
|
||||
draw (cr);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void draw (Cairo.Context cr) {
|
||||
Allocation allocation;
|
||||
get_allocation (out allocation);
|
||||
double w = allocation.width;
|
||||
double h = allocation.height;
|
||||
int text_width, text_height;
|
||||
private void draw (Cairo.Context cr) {
|
||||
Allocation allocation;
|
||||
get_allocation (out allocation);
|
||||
double w = allocation.width;
|
||||
double h = allocation.height;
|
||||
int text_width, text_height;
|
||||
|
||||
// Clean the background.
|
||||
cr.set_source_rgb (0, 0, 0);
|
||||
cr.paint ();
|
||||
// Clean the background.
|
||||
cr.set_source_rgb (0, 0, 0);
|
||||
cr.paint ();
|
||||
|
||||
// Spek version
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
var layout = cairo_create_layout (cr);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (9 * FONT_SCALE).to_string ()));
|
||||
layout.set_width (RPAD * Pango.SCALE);
|
||||
layout.set_text ("dummy", -1);
|
||||
layout.get_pixel_size (out text_width, out text_height);
|
||||
int line_height = text_height;
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans Bold " + (10 * FONT_SCALE).to_string ()));
|
||||
layout.set_text (Config.PACKAGE_NAME + " ", -1);
|
||||
layout.get_pixel_size (out text_width, out text_height);
|
||||
cr.move_to (w - RPAD + GAP, TPAD - 2 * GAP - line_height);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (9 * FONT_SCALE).to_string ()));
|
||||
layout.set_text (Config.PACKAGE_VERSION, -1);
|
||||
cr.rel_move_to (text_width, 0);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
// Spek version
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
var layout = cairo_create_layout (cr);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (9 * FONT_SCALE).to_string ()));
|
||||
layout.set_width (RPAD * Pango.SCALE);
|
||||
layout.set_text ("dummy", -1);
|
||||
layout.get_pixel_size (out text_width, out text_height);
|
||||
int line_height = text_height;
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans Bold " + (10 * FONT_SCALE).to_string ()));
|
||||
layout.set_text (Config.PACKAGE_NAME + " ", -1);
|
||||
layout.get_pixel_size (out text_width, out text_height);
|
||||
cr.move_to (w - RPAD + GAP, TPAD - 2 * GAP - line_height);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (9 * FONT_SCALE).to_string ()));
|
||||
layout.set_text (Config.PACKAGE_VERSION, -1);
|
||||
cr.rel_move_to (text_width, 0);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
|
||||
if (image != null) {
|
||||
// Draw the spectrogram.
|
||||
cr.translate (LPAD, h - BPAD);
|
||||
cr.scale (1, -(h - TPAD - BPAD) / image.get_height ());
|
||||
cr.set_source_surface (image, 0, 0);
|
||||
cr.paint ();
|
||||
cr.identity_matrix ();
|
||||
if (image != null) {
|
||||
// Draw the spectrogram.
|
||||
cr.translate (LPAD, h - BPAD);
|
||||
cr.scale (1, -(h - TPAD - BPAD) / image.get_height ());
|
||||
cr.set_source_surface (image, 0, 0);
|
||||
cr.paint ();
|
||||
cr.identity_matrix ();
|
||||
|
||||
// Prepare to draw the rulers.
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
cr.set_line_width (1);
|
||||
cr.set_antialias (Antialias.NONE);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (8 * FONT_SCALE).to_string ()));
|
||||
layout.set_width (-1);
|
||||
// Prepare to draw the rulers.
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
cr.set_line_width (1);
|
||||
cr.set_antialias (Antialias.NONE);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (8 * FONT_SCALE).to_string ()));
|
||||
layout.set_width (-1);
|
||||
|
||||
// Time ruler.
|
||||
var duration_seconds = (int) pipeline.duration;
|
||||
var time_ruler = new Ruler (
|
||||
Ruler.Position.BOTTOM,
|
||||
// TODO: i18n
|
||||
"00:00",
|
||||
{1, 2, 5, 10, 20, 30, 1*60, 2*60, 5*60, 10*60, 20*60, 30*60},
|
||||
duration_seconds,
|
||||
1.5,
|
||||
unit => (w - LPAD - RPAD) * unit / duration_seconds,
|
||||
p => p,
|
||||
// TODO: i18n
|
||||
unit => "%d:%02d".printf (unit / 60, unit % 60));
|
||||
cr.translate (LPAD, h - BPAD);
|
||||
time_ruler.draw (cr, layout);
|
||||
cr.identity_matrix ();
|
||||
// Time ruler.
|
||||
var duration_seconds = (int) pipeline.duration;
|
||||
var time_ruler = new Ruler (
|
||||
Ruler.Position.BOTTOM,
|
||||
// TODO: i18n
|
||||
"00:00",
|
||||
{1, 2, 5, 10, 20, 30, 1*60, 2*60, 5*60, 10*60, 20*60, 30*60},
|
||||
duration_seconds,
|
||||
1.5,
|
||||
unit => (w - LPAD - RPAD) * unit / duration_seconds,
|
||||
p => p,
|
||||
// TODO: i18n
|
||||
unit => "%d:%02d".printf (unit / 60, unit % 60));
|
||||
cr.translate (LPAD, h - BPAD);
|
||||
time_ruler.draw (cr, layout);
|
||||
cr.identity_matrix ();
|
||||
|
||||
// Frequency ruler.
|
||||
var freq = pipeline.sample_rate / 2;
|
||||
var rate_ruler = new Ruler (
|
||||
Ruler.Position.LEFT,
|
||||
// TRANSLATORS: keep "00" unchanged, it's used to calc the text width
|
||||
_("00 kHz"),
|
||||
{1000, 2000, 5000, 10000, 20000},
|
||||
freq,
|
||||
3.0,
|
||||
unit => (h - TPAD - BPAD) * unit / freq,
|
||||
p => p,
|
||||
unit => _("%d kHz").printf (unit / 1000));
|
||||
cr.translate (LPAD, TPAD);
|
||||
rate_ruler.draw (cr, layout);
|
||||
cr.identity_matrix ();
|
||||
// Frequency ruler.
|
||||
var freq = pipeline.sample_rate / 2;
|
||||
var rate_ruler = new Ruler (
|
||||
Ruler.Position.LEFT,
|
||||
// TRANSLATORS: keep "00" unchanged, it's used to calc the text width
|
||||
_("00 kHz"),
|
||||
{1000, 2000, 5000, 10000, 20000},
|
||||
freq,
|
||||
3.0,
|
||||
unit => (h - TPAD - BPAD) * unit / freq,
|
||||
p => p,
|
||||
unit => _("%d kHz").printf (unit / 1000));
|
||||
cr.translate (LPAD, TPAD);
|
||||
rate_ruler.draw (cr, layout);
|
||||
cr.identity_matrix ();
|
||||
|
||||
// File properties.
|
||||
cr.move_to (LPAD, TPAD - GAP);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (9 * FONT_SCALE).to_string ()));
|
||||
layout.set_width ((int) (w - LPAD - RPAD) * Pango.SCALE);
|
||||
layout.set_ellipsize (EllipsizeMode.END);
|
||||
layout.set_text (info, -1);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
layout.get_pixel_size (out text_width, out text_height);
|
||||
// File properties.
|
||||
cr.move_to (LPAD, TPAD - GAP);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (9 * FONT_SCALE).to_string ()));
|
||||
layout.set_width ((int) (w - LPAD - RPAD) * Pango.SCALE);
|
||||
layout.set_ellipsize (EllipsizeMode.END);
|
||||
layout.set_text (info, -1);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
layout.get_pixel_size (out text_width, out text_height);
|
||||
|
||||
// File name.
|
||||
cr.move_to (LPAD, TPAD - 2 * GAP - text_height);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans Bold " + (10 * FONT_SCALE).to_string ()));
|
||||
layout.set_width ((int) (w - LPAD - RPAD) * Pango.SCALE);
|
||||
layout.set_ellipsize (EllipsizeMode.START);
|
||||
layout.set_text (file_name, -1);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
}
|
||||
// File name.
|
||||
cr.move_to (LPAD, TPAD - 2 * GAP - text_height);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans Bold " + (10 * FONT_SCALE).to_string ()));
|
||||
layout.set_width ((int) (w - LPAD - RPAD) * Pango.SCALE);
|
||||
layout.set_ellipsize (EllipsizeMode.START);
|
||||
layout.set_text (file_name, -1);
|
||||
cairo_show_layout_line (cr, layout.get_line (0));
|
||||
}
|
||||
|
||||
// Border around the spectrogram.
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
cr.set_line_width (1);
|
||||
cr.set_antialias (Antialias.NONE);
|
||||
cr.rectangle (LPAD, TPAD, w - LPAD - RPAD, h - TPAD - BPAD);
|
||||
cr.stroke ();
|
||||
// Border around the spectrogram.
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
cr.set_line_width (1);
|
||||
cr.set_antialias (Antialias.NONE);
|
||||
cr.rectangle (LPAD, TPAD, w - LPAD - RPAD, h - TPAD - BPAD);
|
||||
cr.stroke ();
|
||||
|
||||
// The palette.
|
||||
cr.translate (w - RPAD + GAP, h - BPAD);
|
||||
cr.scale (1, -(h - TPAD - BPAD + 1) / palette.get_height ());
|
||||
cr.set_source_surface (palette, 0, 0);
|
||||
cr.paint ();
|
||||
cr.identity_matrix ();
|
||||
// The palette.
|
||||
cr.translate (w - RPAD + GAP, h - BPAD);
|
||||
cr.scale (1, -(h - TPAD - BPAD + 1) / palette.get_height ());
|
||||
cr.set_source_surface (palette, 0, 0);
|
||||
cr.paint ();
|
||||
cr.identity_matrix ();
|
||||
|
||||
// Prepare to draw the ruler.
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
cr.set_line_width (1);
|
||||
cr.set_antialias (Antialias.NONE);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (8 * FONT_SCALE).to_string ()));
|
||||
layout.set_width (-1);
|
||||
// Prepare to draw the ruler.
|
||||
cr.set_source_rgb (1, 1, 1);
|
||||
cr.set_line_width (1);
|
||||
cr.set_antialias (Antialias.NONE);
|
||||
layout.set_font_description (FontDescription.from_string (
|
||||
"Sans " + (8 * FONT_SCALE).to_string ()));
|
||||
layout.set_width (-1);
|
||||
|
||||
// Spectral density.
|
||||
var density_ruler = new Ruler (
|
||||
Ruler.Position.RIGHT,
|
||||
// TRANSLATORS: keep "-00" unchanged, it's used to calc the text width
|
||||
_("-00 dB"),
|
||||
{1, 2, 5, 10, 20, 50},
|
||||
-THRESHOLD,
|
||||
3.0,
|
||||
unit => -(h - TPAD - BPAD) * unit / THRESHOLD,
|
||||
p => h - TPAD - BPAD - p,
|
||||
unit => _("%d dB").printf (-unit));
|
||||
cr.translate (w - RPAD + GAP + RULER, TPAD);
|
||||
density_ruler.draw (cr, layout);
|
||||
cr.identity_matrix ();
|
||||
}
|
||||
// Spectral density.
|
||||
var density_ruler = new Ruler (
|
||||
Ruler.Position.RIGHT,
|
||||
// TRANSLATORS: keep "-00" unchanged, it's used to calc the text width
|
||||
_("-00 dB"),
|
||||
{1, 2, 5, 10, 20, 50},
|
||||
-THRESHOLD,
|
||||
3.0,
|
||||
unit => -(h - TPAD - BPAD) * unit / THRESHOLD,
|
||||
p => h - TPAD - BPAD - p,
|
||||
unit => _("%d dB").printf (-unit));
|
||||
cr.translate (w - RPAD + GAP + RULER, TPAD);
|
||||
density_ruler.draw (cr, layout);
|
||||
cr.identity_matrix ();
|
||||
}
|
||||
|
||||
private void put_pixel (ImageSurface surface, int x, int y, uint32 color) {
|
||||
var i = y * surface.get_stride () + x * 4;
|
||||
unowned uchar[] data = surface.get_data ();
|
||||
private void put_pixel (ImageSurface surface, int x, int y, uint32 color) {
|
||||
var i = y * surface.get_stride () + x * 4;
|
||||
unowned uchar[] data = surface.get_data ();
|
||||
|
||||
// Translate uchar* to uint32* to avoid dealing with endianness.
|
||||
uint32 *p = (uint32 *) (&data[i]);
|
||||
*p = color;
|
||||
}
|
||||
// Translate uchar* to uint32* to avoid dealing with endianness.
|
||||
uint32 *p = (uint32 *) (&data[i]);
|
||||
*p = color;
|
||||
}
|
||||
|
||||
// Modified version of Dan Bruton's algorithm:
|
||||
// http://www.physics.sfasu.edu/astro/color/spectra.html
|
||||
private uint32 get_color (double level) {
|
||||
level *= 0.6625;
|
||||
double r = 0.0, g = 0.0, b = 0.0;
|
||||
if (level >= 0 && level < 0.15) {
|
||||
r = (0.15 - level) / (0.15 + 0.075);
|
||||
g = 0.0;
|
||||
b = 1.0;
|
||||
} else if (level >= 0.15 && level < 0.275) {
|
||||
r = 0.0;
|
||||
g = (level - 0.15) / (0.275 - 0.15);
|
||||
b = 1.0;
|
||||
} else if (level >= 0.275 && level < 0.325) {
|
||||
r = 0.0;
|
||||
g = 1.0;
|
||||
b = (0.325 - level) / (0.325 - 0.275);
|
||||
} else if (level >= 0.325 && level < 0.5) {
|
||||
r = (level - 0.325) / (0.5 - 0.325);
|
||||
g = 1.0;
|
||||
b = 0.0;
|
||||
} else if (level >= 0.5 && level < 0.6625) {
|
||||
r = 1.0;
|
||||
g = (0.6625 - level) / (0.6625 - 0.5f);
|
||||
b = 0.0;
|
||||
}
|
||||
// Modified version of Dan Bruton's algorithm:
|
||||
// http://www.physics.sfasu.edu/astro/color/spectra.html
|
||||
private uint32 get_color (double level) {
|
||||
level *= 0.6625;
|
||||
double r = 0.0, g = 0.0, b = 0.0;
|
||||
if (level >= 0 && level < 0.15) {
|
||||
r = (0.15 - level) / (0.15 + 0.075);
|
||||
g = 0.0;
|
||||
b = 1.0;
|
||||
} else if (level >= 0.15 && level < 0.275) {
|
||||
r = 0.0;
|
||||
g = (level - 0.15) / (0.275 - 0.15);
|
||||
b = 1.0;
|
||||
} else if (level >= 0.275 && level < 0.325) {
|
||||
r = 0.0;
|
||||
g = 1.0;
|
||||
b = (0.325 - level) / (0.325 - 0.275);
|
||||
} else if (level >= 0.325 && level < 0.5) {
|
||||
r = (level - 0.325) / (0.5 - 0.325);
|
||||
g = 1.0;
|
||||
b = 0.0;
|
||||
} else if (level >= 0.5 && level < 0.6625) {
|
||||
r = 1.0;
|
||||
g = (0.6625 - level) / (0.6625 - 0.5f);
|
||||
b = 0.0;
|
||||
}
|
||||
|
||||
// Intensity correction.
|
||||
double cf = 1.0;
|
||||
if (level >= 0.0 && level < 0.1) {
|
||||
cf = level / 0.1;
|
||||
}
|
||||
cf *= 255.0;
|
||||
// Intensity correction.
|
||||
double cf = 1.0;
|
||||
if (level >= 0.0 && level < 0.1) {
|
||||
cf = level / 0.1;
|
||||
}
|
||||
cf *= 255.0;
|
||||
|
||||
// Pack RGB values into Cairo-happy format.
|
||||
uint32 rr = (uint32) (r * cf + 0.5);
|
||||
uint32 gg = (uint32) (g * cf + 0.5);
|
||||
uint32 bb = (uint32) (b * cf + 0.5);
|
||||
return (rr << 16) + (gg << 8) + bb;
|
||||
}
|
||||
}
|
||||
// Pack RGB values into Cairo-happy format.
|
||||
uint32 rr = (uint32) (r * cf + 0.5);
|
||||
uint32 gg = (uint32) (g * cf + 0.5);
|
||||
uint32 bb = (uint32) (b * cf + 0.5);
|
||||
return (rr << 16) + (gg << 8) + bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,29 +20,29 @@ using Gdk;
|
||||
using Gtk;
|
||||
|
||||
namespace Spek {
|
||||
public class Window : Gtk.Window {
|
||||
public class Window : Gtk.Window {
|
||||
|
||||
private UIManager ui;
|
||||
private MessageBar message_bar;
|
||||
private Spectrogram spectrogram;
|
||||
private string description;
|
||||
private string cur_dir;
|
||||
private FileFilter filter_all;
|
||||
private FileFilter filter_audio;
|
||||
private FileFilter filter_png;
|
||||
private UIManager ui;
|
||||
private MessageBar message_bar;
|
||||
private Spectrogram spectrogram;
|
||||
private string description;
|
||||
private string cur_dir;
|
||||
private FileFilter filter_all;
|
||||
private FileFilter filter_audio;
|
||||
private FileFilter filter_png;
|
||||
|
||||
private const ActionEntry[] ACTION_ENTRIES = {
|
||||
{ "File", null, N_("_File") },
|
||||
{ "FileOpen", Stock.OPEN, null, null, null, on_file_open },
|
||||
{ "FileSave", Stock.SAVE, null, null, null, on_file_save },
|
||||
{ "FileQuit", Stock.QUIT, null, null, null, on_file_quit },
|
||||
{ "Edit", null, N_("_Edit") },
|
||||
{ "EditPreferences", Stock.PREFERENCES, null, "<Ctrl>E", null, on_edit_preferences },
|
||||
{ "Help", null, N_("_Help") },
|
||||
{ "HelpAbout", Stock.ABOUT, null, "F1", null, on_help_about }
|
||||
};
|
||||
private const ActionEntry[] ACTION_ENTRIES = {
|
||||
{ "File", null, N_("_File") },
|
||||
{ "FileOpen", Stock.OPEN, null, null, null, on_file_open },
|
||||
{ "FileSave", Stock.SAVE, null, null, null, on_file_save },
|
||||
{ "FileQuit", Stock.QUIT, null, null, null, on_file_quit },
|
||||
{ "Edit", null, N_("_Edit") },
|
||||
{ "EditPreferences", Stock.PREFERENCES, null, "<Ctrl>E", null, on_edit_preferences },
|
||||
{ "Help", null, N_("_Help") },
|
||||
{ "HelpAbout", Stock.ABOUT, null, "F1", null, on_help_about }
|
||||
};
|
||||
|
||||
private const string UI = """
|
||||
private const string UI = """
|
||||
<ui>
|
||||
<menubar name='MenuBar'>
|
||||
<menu action='File'>
|
||||
@ -68,275 +68,275 @@ namespace Spek {
|
||||
</ui>
|
||||
""";
|
||||
|
||||
private const Gtk.TargetEntry[] DEST_TARGET_ENTRIES = {
|
||||
{ "text/uri-list", 0, 0 }
|
||||
};
|
||||
private const Gtk.TargetEntry[] DEST_TARGET_ENTRIES = {
|
||||
{ "text/uri-list", 0, 0 }
|
||||
};
|
||||
|
||||
public Window (string? file_name) {
|
||||
description = title = _("Spek - Acoustic Spectrum Analyser");
|
||||
set_default_icon_name ("spek");
|
||||
set_default_size (640, 480);
|
||||
destroy.connect (Gtk.main_quit);
|
||||
public Window (string? file_name) {
|
||||
description = title = _("Spek - Acoustic Spectrum Analyser");
|
||||
set_default_icon_name ("spek");
|
||||
set_default_size (640, 480);
|
||||
destroy.connect (Gtk.main_quit);
|
||||
|
||||
var actions = new Gtk.ActionGroup ("Actions");
|
||||
actions.set_translation_domain (Config.GETTEXT_PACKAGE);
|
||||
actions.add_actions (ACTION_ENTRIES, this);
|
||||
ui = new UIManager ();
|
||||
ui.insert_action_group (actions, 0);
|
||||
add_accel_group (ui.get_accel_group ());
|
||||
try {
|
||||
ui.add_ui_from_string (UI, -1);
|
||||
} catch (Error e) {
|
||||
warning ("Could not load the UI: %s\n", e.message);
|
||||
}
|
||||
var actions = new Gtk.ActionGroup ("Actions");
|
||||
actions.set_translation_domain (Config.GETTEXT_PACKAGE);
|
||||
actions.add_actions (ACTION_ENTRIES, this);
|
||||
ui = new UIManager ();
|
||||
ui.insert_action_group (actions, 0);
|
||||
add_accel_group (ui.get_accel_group ());
|
||||
try {
|
||||
ui.add_ui_from_string (UI, -1);
|
||||
} catch (Error e) {
|
||||
warning ("Could not load the UI: %s\n", e.message);
|
||||
}
|
||||
|
||||
var menubar = ui.get_widget ("/MenuBar");
|
||||
var toolbar = (Toolbar) ui.get_widget ("/ToolBar");
|
||||
toolbar.set_style (ToolbarStyle.BOTH_HORIZ);
|
||||
((ToolItem) ui.get_widget ("/ToolBar/FileOpen")).is_important = true;
|
||||
((ToolItem) ui.get_widget ("/ToolBar/FileSave")).is_important = true;
|
||||
((ToolItem) ui.get_widget ("/ToolBar/HelpAbout")).is_important = true;
|
||||
var menubar = ui.get_widget ("/MenuBar");
|
||||
var toolbar = (Toolbar) ui.get_widget ("/ToolBar");
|
||||
toolbar.set_style (ToolbarStyle.BOTH_HORIZ);
|
||||
((ToolItem) ui.get_widget ("/ToolBar/FileOpen")).is_important = true;
|
||||
((ToolItem) ui.get_widget ("/ToolBar/FileSave")).is_important = true;
|
||||
((ToolItem) ui.get_widget ("/ToolBar/HelpAbout")).is_important = true;
|
||||
|
||||
message_bar = new MessageBar (_("A new version of Spek is available on <a href=\"http://www.spek-project.org\">www.spek-project.org</a>"));
|
||||
message_bar = new MessageBar (_("A new version of Spek is available on <a href=\"http://www.spek-project.org\">www.spek-project.org</a>"));
|
||||
|
||||
spectrogram = new Spectrogram ();
|
||||
cur_dir = Environment.get_home_dir ();
|
||||
spectrogram = new Spectrogram ();
|
||||
cur_dir = Environment.get_home_dir ();
|
||||
|
||||
filter_all = new FileFilter ();
|
||||
filter_all.set_name (_("All files"));
|
||||
filter_all.add_pattern ("*");
|
||||
filter_png = new FileFilter ();
|
||||
filter_png.set_name (_("PNG images"));
|
||||
filter_png.add_pattern ("*.png");
|
||||
filter_audio = new FileFilter ();
|
||||
filter_audio.set_name (_("Audio files"));
|
||||
foreach (var ext in audio_extensions) {
|
||||
filter_audio.add_pattern (ext);
|
||||
}
|
||||
filter_all = new FileFilter ();
|
||||
filter_all.set_name (_("All files"));
|
||||
filter_all.add_pattern ("*");
|
||||
filter_png = new FileFilter ();
|
||||
filter_png.set_name (_("PNG images"));
|
||||
filter_png.add_pattern ("*.png");
|
||||
filter_audio = new FileFilter ();
|
||||
filter_audio.set_name (_("Audio files"));
|
||||
foreach (var ext in audio_extensions) {
|
||||
filter_audio.add_pattern (ext);
|
||||
}
|
||||
|
||||
var vbox = new VBox (false, 0);
|
||||
vbox.pack_start (menubar, false, true, 0);
|
||||
vbox.pack_start (toolbar, false, true, 0);
|
||||
vbox.pack_start (message_bar, false, true, 0);
|
||||
vbox.pack_start (spectrogram, true, true, 0);
|
||||
add (vbox);
|
||||
menubar.show_all ();
|
||||
toolbar.show_all ();
|
||||
spectrogram.show_all ();
|
||||
vbox.show ();
|
||||
var vbox = new VBox (false, 0);
|
||||
vbox.pack_start (menubar, false, true, 0);
|
||||
vbox.pack_start (toolbar, false, true, 0);
|
||||
vbox.pack_start (message_bar, false, true, 0);
|
||||
vbox.pack_start (spectrogram, true, true, 0);
|
||||
add (vbox);
|
||||
menubar.show_all ();
|
||||
toolbar.show_all ();
|
||||
spectrogram.show_all ();
|
||||
vbox.show ();
|
||||
|
||||
Platform.fix_ui (ui);
|
||||
show ();
|
||||
Platform.fix_ui (ui);
|
||||
show ();
|
||||
|
||||
// Set up Drag and Drop
|
||||
drag_dest_set (this, DestDefaults.ALL, DEST_TARGET_ENTRIES, DragAction.COPY);
|
||||
drag_data_received.connect (on_dropped);
|
||||
// Set up Drag and Drop
|
||||
drag_dest_set (this, DestDefaults.ALL, DEST_TARGET_ENTRIES, DragAction.COPY);
|
||||
drag_data_received.connect (on_dropped);
|
||||
|
||||
if (file_name != null) {
|
||||
open_file (file_name);
|
||||
}
|
||||
if (file_name != null) {
|
||||
open_file (file_name);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.create<void*> (check_version, false);
|
||||
} catch (ThreadError e) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.create<void*> (check_version, false);
|
||||
} catch (ThreadError e) {
|
||||
}
|
||||
}
|
||||
|
||||
void on_dropped (DragContext cx, int x, int y, SelectionData data, uint info, uint time) {
|
||||
if (data.get_length () > 0 && data.get_format () == 8) {
|
||||
string[] files = data.get_uris ();
|
||||
if (files.length > 0) {
|
||||
try {
|
||||
open_file (Filename.from_uri (files[0]));
|
||||
drag_finish (cx, true, false, time);
|
||||
return;
|
||||
} catch (ConvertError e) {}
|
||||
}
|
||||
}
|
||||
drag_finish (cx, false, false, time);
|
||||
}
|
||||
void on_dropped (DragContext cx, int x, int y, SelectionData data, uint info, uint time) {
|
||||
if (data.get_length () > 0 && data.get_format () == 8) {
|
||||
string[] files = data.get_uris ();
|
||||
if (files.length > 0) {
|
||||
try {
|
||||
open_file (Filename.from_uri (files[0]));
|
||||
drag_finish (cx, true, false, time);
|
||||
return;
|
||||
} catch (ConvertError e) {}
|
||||
}
|
||||
}
|
||||
drag_finish (cx, false, false, time);
|
||||
}
|
||||
|
||||
private void open_file (string file_name) {
|
||||
cur_dir = Path.get_dirname (file_name);
|
||||
spectrogram.open (file_name);
|
||||
private void open_file (string file_name) {
|
||||
cur_dir = Path.get_dirname (file_name);
|
||||
spectrogram.open (file_name);
|
||||
|
||||
// TRANSLATORS: window title, %s is replaced with the file name
|
||||
title = _("Spek - %s").printf (Path.get_basename (file_name));
|
||||
}
|
||||
// TRANSLATORS: window title, %s is replaced with the file name
|
||||
title = _("Spek - %s").printf (Path.get_basename (file_name));
|
||||
}
|
||||
|
||||
private void on_file_open () {
|
||||
var chooser = new FileChooserDialog (
|
||||
_("Open File"), this, FileChooserAction.OPEN,
|
||||
Stock.CANCEL, ResponseType.CANCEL,
|
||||
Stock.OPEN, ResponseType.ACCEPT, null);
|
||||
chooser.set_default_response (ResponseType.ACCEPT);
|
||||
chooser.select_multiple = false;
|
||||
chooser.set_current_folder (cur_dir);
|
||||
chooser.add_filter (filter_all);
|
||||
chooser.add_filter (filter_audio);
|
||||
chooser.set_filter (filter_audio);
|
||||
if (chooser.run () == ResponseType.ACCEPT) {
|
||||
open_file (chooser.get_filename ());
|
||||
}
|
||||
chooser.destroy ();
|
||||
}
|
||||
private void on_file_open () {
|
||||
var chooser = new FileChooserDialog (
|
||||
_("Open File"), this, FileChooserAction.OPEN,
|
||||
Stock.CANCEL, ResponseType.CANCEL,
|
||||
Stock.OPEN, ResponseType.ACCEPT, null);
|
||||
chooser.set_default_response (ResponseType.ACCEPT);
|
||||
chooser.select_multiple = false;
|
||||
chooser.set_current_folder (cur_dir);
|
||||
chooser.add_filter (filter_all);
|
||||
chooser.add_filter (filter_audio);
|
||||
chooser.set_filter (filter_audio);
|
||||
if (chooser.run () == ResponseType.ACCEPT) {
|
||||
open_file (chooser.get_filename ());
|
||||
}
|
||||
chooser.destroy ();
|
||||
}
|
||||
|
||||
private void on_file_save () {
|
||||
var chooser = new FileChooserDialog (
|
||||
_("Save Spectrogram"), this, FileChooserAction.SAVE,
|
||||
Stock.CANCEL, ResponseType.CANCEL,
|
||||
Stock.SAVE, ResponseType.ACCEPT, null);
|
||||
chooser.set_default_response (ResponseType.ACCEPT);
|
||||
chooser.set_current_folder (cur_dir);
|
||||
private void on_file_save () {
|
||||
var chooser = new FileChooserDialog (
|
||||
_("Save Spectrogram"), this, FileChooserAction.SAVE,
|
||||
Stock.CANCEL, ResponseType.CANCEL,
|
||||
Stock.SAVE, ResponseType.ACCEPT, null);
|
||||
chooser.set_default_response (ResponseType.ACCEPT);
|
||||
chooser.set_current_folder (cur_dir);
|
||||
|
||||
// Suggested name is <file_name>.png
|
||||
var file_name = Path.get_basename (spectrogram.file_name ?? _("Untitled"));
|
||||
file_name += ".png";
|
||||
chooser.set_current_name (file_name);
|
||||
chooser.add_filter (filter_png);
|
||||
chooser.set_filter (filter_png);
|
||||
if (chooser.run () == ResponseType.ACCEPT) {
|
||||
file_name = chooser.get_filename ();
|
||||
cur_dir = Path.get_dirname (file_name);
|
||||
spectrogram.save (file_name);
|
||||
}
|
||||
chooser.destroy ();
|
||||
}
|
||||
// Suggested name is <file_name>.png
|
||||
var file_name = Path.get_basename (spectrogram.file_name ?? _("Untitled"));
|
||||
file_name += ".png";
|
||||
chooser.set_current_name (file_name);
|
||||
chooser.add_filter (filter_png);
|
||||
chooser.set_filter (filter_png);
|
||||
if (chooser.run () == ResponseType.ACCEPT) {
|
||||
file_name = chooser.get_filename ();
|
||||
cur_dir = Path.get_dirname (file_name);
|
||||
spectrogram.save (file_name);
|
||||
}
|
||||
chooser.destroy ();
|
||||
}
|
||||
|
||||
private void on_file_quit () {
|
||||
destroy ();
|
||||
}
|
||||
private void on_file_quit () {
|
||||
destroy ();
|
||||
}
|
||||
|
||||
private void on_edit_preferences () {
|
||||
var dlg = new PreferencesDialog ();
|
||||
dlg.transient_for = this;
|
||||
dlg.run ();
|
||||
}
|
||||
private void on_edit_preferences () {
|
||||
var dlg = new PreferencesDialog ();
|
||||
dlg.transient_for = this;
|
||||
dlg.run ();
|
||||
}
|
||||
|
||||
private void on_help_about () {
|
||||
string[] authors = {
|
||||
"Primary Development:",
|
||||
"\tAlexander Kojevnikov (maintainer)",
|
||||
"",
|
||||
"Contributors:",
|
||||
"\tFabian Deutsch",
|
||||
"\tJonathan Gonzalez V",
|
||||
"\tStefan Kost",
|
||||
"\tThibault North"
|
||||
};
|
||||
string[] artists = {
|
||||
"Olga Vasylevska"
|
||||
};
|
||||
string license = "Copyright (C) 2010-2011 Alexander Kojevnikov";
|
||||
license += "\n\n";
|
||||
license += "Spek is free software: you can redistribute it and/or modify ";
|
||||
license += "it under the terms of the GNU General Public License as published by ";
|
||||
license += "the Free Software Foundation, either version 3 of the License, or ";
|
||||
license += "(at your option) any later version.";
|
||||
license += "\n\n";
|
||||
license += "Spek is distributed in the hope that it will be useful, ";
|
||||
license += "but WITHOUT ANY WARRANTY; without even the implied warranty of ";
|
||||
license += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ";
|
||||
license += "GNU General Public License for more details.";
|
||||
license += "\n\n";
|
||||
license += "You should have received a copy of the GNU General Public License ";
|
||||
license += "along with Spek. If not, see http://www.gnu.org/licenses/";
|
||||
private void on_help_about () {
|
||||
string[] authors = {
|
||||
"Primary Development:",
|
||||
"\tAlexander Kojevnikov (maintainer)",
|
||||
"",
|
||||
"Contributors:",
|
||||
"\tFabian Deutsch",
|
||||
"\tJonathan Gonzalez V",
|
||||
"\tStefan Kost",
|
||||
"\tThibault North"
|
||||
};
|
||||
string[] artists = {
|
||||
"Olga Vasylevska"
|
||||
};
|
||||
string license = "Copyright (C) 2010-2011 Alexander Kojevnikov";
|
||||
license += "\n\n";
|
||||
license += "Spek is free software: you can redistribute it and/or modify ";
|
||||
license += "it under the terms of the GNU General Public License as published by ";
|
||||
license += "the Free Software Foundation, either version 3 of the License, or ";
|
||||
license += "(at your option) any later version.";
|
||||
license += "\n\n";
|
||||
license += "Spek is distributed in the hope that it will be useful, ";
|
||||
license += "but WITHOUT ANY WARRANTY; without even the implied warranty of ";
|
||||
license += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ";
|
||||
license += "GNU General Public License for more details.";
|
||||
license += "\n\n";
|
||||
license += "You should have received a copy of the GNU General Public License ";
|
||||
license += "along with Spek. If not, see http://www.gnu.org/licenses/";
|
||||
|
||||
var dlg = new AboutDialog ();
|
||||
dlg.program_name = "Spek";
|
||||
dlg.version = Config.PACKAGE_VERSION;
|
||||
dlg.copyright = _("Copyright \xc2\xa9 2010-2011 Alexander Kojevnikov");
|
||||
dlg.comments = description;
|
||||
dlg.set ("authors", authors);
|
||||
// dlg.set ("documenters", documenters);
|
||||
dlg.set ("artists", artists);
|
||||
dlg.website_label = _("Spek Website");
|
||||
dlg.website = "http://www.spek-project.org/";
|
||||
dlg.license = license;
|
||||
dlg.wrap_license = true;
|
||||
try {
|
||||
dlg.logo = IconTheme.get_default ().load_icon ("spek", 128, IconLookupFlags.FORCE_SVG);
|
||||
} catch (Error e) {
|
||||
dlg.logo_icon_name = "spek";
|
||||
}
|
||||
dlg.translator_credits = _("translator-credits");
|
||||
dlg.set_transient_for (this);
|
||||
dlg.destroy_with_parent = true;
|
||||
dlg.response.connect (id => dlg.destroy ());
|
||||
dlg.set_url_hook (url_hook);
|
||||
dlg.modal = true;
|
||||
dlg.present ();
|
||||
}
|
||||
var dlg = new AboutDialog ();
|
||||
dlg.program_name = "Spek";
|
||||
dlg.version = Config.PACKAGE_VERSION;
|
||||
dlg.copyright = _("Copyright \xc2\xa9 2010-2011 Alexander Kojevnikov");
|
||||
dlg.comments = description;
|
||||
dlg.set ("authors", authors);
|
||||
// dlg.set ("documenters", documenters);
|
||||
dlg.set ("artists", artists);
|
||||
dlg.website_label = _("Spek Website");
|
||||
dlg.website = "http://www.spek-project.org/";
|
||||
dlg.license = license;
|
||||
dlg.wrap_license = true;
|
||||
try {
|
||||
dlg.logo = IconTheme.get_default ().load_icon ("spek", 128, IconLookupFlags.FORCE_SVG);
|
||||
} catch (Error e) {
|
||||
dlg.logo_icon_name = "spek";
|
||||
}
|
||||
dlg.translator_credits = _("translator-credits");
|
||||
dlg.set_transient_for (this);
|
||||
dlg.destroy_with_parent = true;
|
||||
dlg.response.connect (id => dlg.destroy ());
|
||||
dlg.set_url_hook (url_hook);
|
||||
dlg.modal = true;
|
||||
dlg.present ();
|
||||
}
|
||||
|
||||
private void url_hook (AboutDialog about, string link) {
|
||||
Platform.show_uri (link);
|
||||
}
|
||||
private void url_hook (AboutDialog about, string link) {
|
||||
Platform.show_uri (link);
|
||||
}
|
||||
|
||||
// TODO: s/audio/media/
|
||||
private string[] audio_extensions = {
|
||||
"*.3gp",
|
||||
"*.aac",
|
||||
"*.aif",
|
||||
"*.aifc",
|
||||
"*.aiff",
|
||||
"*.amr",
|
||||
"*.awb",
|
||||
"*.ape",
|
||||
"*.au",
|
||||
"*.dts",
|
||||
"*.flac",
|
||||
"*.gsm",
|
||||
"*.m4a",
|
||||
"*.m4p",
|
||||
"*.mp3",
|
||||
"*.mp4",
|
||||
"*.mp+",
|
||||
"*.mpc",
|
||||
"*.mpp",
|
||||
"*.oga",
|
||||
"*.ogg",
|
||||
"*.ra",
|
||||
"*.ram",
|
||||
"*.snd",
|
||||
"*.wav",
|
||||
"*.wma",
|
||||
"*.wv"
|
||||
};
|
||||
// TODO: s/audio/media/
|
||||
private string[] audio_extensions = {
|
||||
"*.3gp",
|
||||
"*.aac",
|
||||
"*.aif",
|
||||
"*.aifc",
|
||||
"*.aiff",
|
||||
"*.amr",
|
||||
"*.awb",
|
||||
"*.ape",
|
||||
"*.au",
|
||||
"*.dts",
|
||||
"*.flac",
|
||||
"*.gsm",
|
||||
"*.m4a",
|
||||
"*.m4p",
|
||||
"*.mp3",
|
||||
"*.mp4",
|
||||
"*.mp+",
|
||||
"*.mpc",
|
||||
"*.mpp",
|
||||
"*.oga",
|
||||
"*.ogg",
|
||||
"*.ra",
|
||||
"*.ram",
|
||||
"*.snd",
|
||||
"*.wav",
|
||||
"*.wma",
|
||||
"*.wv"
|
||||
};
|
||||
|
||||
private void * check_version () {
|
||||
// Does the user want to check for updates?
|
||||
var prefs = Preferences.instance;
|
||||
var check = prefs.check_update;
|
||||
if (!check) {
|
||||
return null;
|
||||
}
|
||||
private void * check_version () {
|
||||
// Does the user want to check for updates?
|
||||
var prefs = Preferences.instance;
|
||||
var check = prefs.check_update;
|
||||
if (!check) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// When was the last update?
|
||||
var time_val = TimeVal ();
|
||||
time_val.get_current_time ();
|
||||
Date today = Date ();
|
||||
today.set_time_val (time_val);
|
||||
int day = prefs.last_update;
|
||||
int diff = (int) today.get_julian () - day;
|
||||
if (diff < 7) {
|
||||
return null;
|
||||
}
|
||||
// When was the last update?
|
||||
var time_val = TimeVal ();
|
||||
time_val.get_current_time ();
|
||||
Date today = Date ();
|
||||
today.set_time_val (time_val);
|
||||
int day = prefs.last_update;
|
||||
int diff = (int) today.get_julian () - day;
|
||||
if (diff < 7) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the version number.
|
||||
var version = Platform.read_line ("http://www.spek-project.org/version");
|
||||
if (version == null) {
|
||||
return null;
|
||||
}
|
||||
// Get the version number.
|
||||
var version = Platform.read_line ("http://www.spek-project.org/version");
|
||||
if (version == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (version != null && version > Config.PACKAGE_VERSION) {
|
||||
Idle.add (() => { message_bar.show_all (); return false; });
|
||||
}
|
||||
if (version != null && version > Config.PACKAGE_VERSION) {
|
||||
Idle.add (() => { message_bar.show_all (); return false; });
|
||||
}
|
||||
|
||||
// Update the preferences.
|
||||
prefs.check_update = check;
|
||||
prefs.last_update = (int) today.get_julian ();
|
||||
prefs.save ();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Update the preferences.
|
||||
prefs.check_update = check;
|
||||
prefs.last_update = (int) today.get_julian ();
|
||||
prefs.save ();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,59 +17,59 @@
|
||||
*/
|
||||
|
||||
namespace Spek {
|
||||
bool version = false;
|
||||
[CCode (array_length = false, array_null_terminated = true)]
|
||||
string[] files = null;
|
||||
bool version = false;
|
||||
[CCode (array_length = false, array_null_terminated = true)]
|
||||
string[] files = null;
|
||||
|
||||
const OptionEntry[] options = {
|
||||
{ "version", 'V', 0, OptionArg.NONE, ref version, N_("Display the version and exit"), null },
|
||||
{ "", 0, 0, OptionArg.FILENAME_ARRAY, ref files, null, null },
|
||||
{ null }
|
||||
};
|
||||
const OptionEntry[] options = {
|
||||
{ "version", 'V', 0, OptionArg.NONE, ref version, N_("Display the version and exit"), null },
|
||||
{ "", 0, 0, OptionArg.FILENAME_ARRAY, ref files, null, null },
|
||||
{ null }
|
||||
};
|
||||
|
||||
int main (string[] args) {
|
||||
Platform.fix_args (args);
|
||||
int main (string[] args) {
|
||||
Platform.fix_args (args);
|
||||
|
||||
if (Preferences.instance.language.length > 0) {
|
||||
Environment.set_variable ("LANGUAGE", Preferences.instance.language, true);
|
||||
}
|
||||
if (Preferences.instance.language.length > 0) {
|
||||
Environment.set_variable ("LANGUAGE", Preferences.instance.language, true);
|
||||
}
|
||||
|
||||
Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Platform.locale_dir ());
|
||||
Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
|
||||
Intl.textdomain (Config.GETTEXT_PACKAGE);
|
||||
Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Platform.locale_dir ());
|
||||
Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
|
||||
Intl.textdomain (Config.GETTEXT_PACKAGE);
|
||||
|
||||
try {
|
||||
Gtk.init_with_args (ref args, _("[FILE]"), (OptionEntry[]) options, Config.GETTEXT_PACKAGE);
|
||||
} catch (Error e) {
|
||||
print (e.message);
|
||||
print ("\n");
|
||||
print (_("Run `%s --help` to see a full list of available command line options.\n"), args[0]);
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
Gtk.init_with_args (ref args, _("[FILE]"), (OptionEntry[]) options, Config.GETTEXT_PACKAGE);
|
||||
} catch (Error e) {
|
||||
print (e.message);
|
||||
print ("\n");
|
||||
print (_("Run `%s --help` to see a full list of available command line options.\n"), args[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (version) {
|
||||
// TRANSLATORS: first %s is the package name, second %s is the package version.
|
||||
print (_("%s version %s\n"), Config.PACKAGE_NAME, Config.PACKAGE_VERSION);
|
||||
return 0;
|
||||
}
|
||||
if (version) {
|
||||
// TRANSLATORS: first %s is the package name, second %s is the package version.
|
||||
print (_("%s version %s\n"), Config.PACKAGE_NAME, Config.PACKAGE_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (files != null && files.length != 1) {
|
||||
print (_("Specify a single file\n"));
|
||||
return 1;
|
||||
}
|
||||
if (files != null && files.length != 1) {
|
||||
print (_("Specify a single file\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
Platform.init ();
|
||||
Audio.init ();
|
||||
var file_name = files == null ? null : files[0];
|
||||
if (file_name != null && file_name.has_prefix ("file://")) {
|
||||
try {
|
||||
file_name = Filename.from_uri (file_name);
|
||||
} catch (ConvertError e) {
|
||||
}
|
||||
}
|
||||
var window = new Window (file_name);
|
||||
Gtk.main ();
|
||||
window.destroy ();
|
||||
return 0;
|
||||
}
|
||||
Platform.init ();
|
||||
Audio.init ();
|
||||
var file_name = files == null ? null : files[0];
|
||||
if (file_name != null && file_name.has_prefix ("file://")) {
|
||||
try {
|
||||
file_name = Filename.from_uri (file_name);
|
||||
} catch (ConvertError e) {
|
||||
}
|
||||
}
|
||||
var window = new Window (file_name);
|
||||
Gtk.main ();
|
||||
window.destroy ();
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
[CCode (prefix = "", lower_case_cprefix = "", cheader_filename = "config.h")]
|
||||
namespace Config {
|
||||
/* Package information */
|
||||
public const string PACKAGE_NAME;
|
||||
public const string PACKAGE_STRING;
|
||||
public const string PACKAGE_VERSION;
|
||||
/* Package information */
|
||||
public const string PACKAGE_NAME;
|
||||
public const string PACKAGE_STRING;
|
||||
public const string PACKAGE_VERSION;
|
||||
|
||||
/* Gettext package */
|
||||
public const string GETTEXT_PACKAGE;
|
||||
/* Gettext package */
|
||||
public const string GETTEXT_PACKAGE;
|
||||
|
||||
/* Configured paths - these variables are not present in config.h, they are
|
||||
* passed to underlying C code as cmd line macros. */
|
||||
public const string LOCALEDIR; /* /usr/local/share/locale */
|
||||
public const string PKGDATADIR; /* /usr/local/share/spek */
|
||||
public const string PKGLIBDIR; /* /usr/local/lib/spek */
|
||||
/* Configured paths - these variables are not present in config.h, they are
|
||||
* passed to underlying C code as cmd line macros. */
|
||||
public const string LOCALEDIR; /* /usr/local/share/locale */
|
||||
public const string PKGDATADIR; /* /usr/local/share/spek */
|
||||
public const string PKGLIBDIR; /* /usr/local/lib/spek */
|
||||
}
|
||||
|
@ -1,29 +1,29 @@
|
||||
[CCode (cprefix = "SpekAudio", lower_case_cprefix = "spek_audio_", cheader_filename = "spek-audio.h")]
|
||||
namespace Spek.Audio {
|
||||
[Compact]
|
||||
[CCode (free_function = "spek_audio_close")]
|
||||
public class Context {
|
||||
public string file_name;
|
||||
public string codec_name;
|
||||
public string error;
|
||||
public int bit_rate;
|
||||
public int sample_rate;
|
||||
public int bits_per_sample;
|
||||
public int width;
|
||||
public bool fp;
|
||||
public int channels;
|
||||
public double duration;
|
||||
public uint8 *buffer;
|
||||
public int64 frames_per_interval;
|
||||
public int64 error_per_interval;
|
||||
public int64 error_base;
|
||||
[Compact]
|
||||
[CCode (free_function = "spek_audio_close")]
|
||||
public class Context {
|
||||
public string file_name;
|
||||
public string codec_name;
|
||||
public string error;
|
||||
public int bit_rate;
|
||||
public int sample_rate;
|
||||
public int bits_per_sample;
|
||||
public int width;
|
||||
public bool fp;
|
||||
public int channels;
|
||||
public double duration;
|
||||
public uint8 *buffer;
|
||||
public int64 frames_per_interval;
|
||||
public int64 error_per_interval;
|
||||
public int64 error_base;
|
||||
|
||||
[CCode (cname = "spek_audio_open")]
|
||||
public Context (string file_name);
|
||||
[CCode (cname = "spek_audio_start")]
|
||||
public int start (int samples);
|
||||
[CCode (cname = "spek_audio_read")]
|
||||
public int read ();
|
||||
}
|
||||
public static void init ();
|
||||
[CCode (cname = "spek_audio_open")]
|
||||
public Context (string file_name);
|
||||
[CCode (cname = "spek_audio_start")]
|
||||
public int start (int samples);
|
||||
[CCode (cname = "spek_audio_read")]
|
||||
public int read ();
|
||||
}
|
||||
public static void init ();
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
[CCode (cprefix = "SpekFft", lower_case_cprefix = "spek_fft_", cheader_filename = "spek-fft.h")]
|
||||
namespace Spek.Fft {
|
||||
[Compact]
|
||||
[CCode (free_function = "spek_fft_destroy")]
|
||||
public class Plan {
|
||||
[CCode (array_length = false)]
|
||||
public unowned float[] input;
|
||||
[CCode (array_length = false)]
|
||||
public unowned float[] output;
|
||||
[Compact]
|
||||
[CCode (free_function = "spek_fft_destroy")]
|
||||
public class Plan {
|
||||
[CCode (array_length = false)]
|
||||
public unowned float[] input;
|
||||
[CCode (array_length = false)]
|
||||
public unowned float[] output;
|
||||
|
||||
[CCode (cname = "spek_fft_plan_new")]
|
||||
public Plan (int n, int threshold);
|
||||
[CCode (cname = "spek_fft_execute")]
|
||||
public void execute ();
|
||||
}
|
||||
[CCode (cname = "spek_fft_plan_new")]
|
||||
public Plan (int n, int threshold);
|
||||
[CCode (cname = "spek_fft_execute")]
|
||||
public void execute ();
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
[CCode (cprefix = "SpekPlatform", lower_case_cprefix = "spek_platform_", cheader_filename = "spek-platform.h")]
|
||||
namespace Spek.Platform {
|
||||
public static void init ();
|
||||
public static void fix_args (string[] args);
|
||||
public static void fix_ui (Gtk.UIManager ui);
|
||||
public static unowned string locale_dir ();
|
||||
public static void show_uri (string uri);
|
||||
public static string read_line (string uri);
|
||||
public static double get_font_scale ();
|
||||
public static void init ();
|
||||
public static void fix_args (string[] args);
|
||||
public static void fix_ui (Gtk.UIManager ui);
|
||||
public static unowned string locale_dir ();
|
||||
public static void show_uri (string uri);
|
||||
public static string read_line (string uri);
|
||||
public static double get_font_scale ();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user