major plugin revamp based on x-fixer's code
This commit is contained in:
parent
838408a3ee
commit
9745f25e78
@ -37,4 +37,4 @@ all default: $(DEFAULT_BUILD)
|
||||
|
||||
VERSION=\"1.1.1\"
|
||||
|
||||
CONFIG_CFLAGS=-DHAVE_INTTYPES_H
|
||||
CONFIG_CFLAGS=-D_GNU_SOURCE -DHAVE_INTTYPES_H -DHAVE_WCSDUP -DHAVE_WCSCASECMP
|
||||
|
@ -147,10 +147,16 @@ AM_PROG_AS
|
||||
AC_PROG_CXX
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
dnl In order to have access to any available wcsdup() and wcscasecmp()
|
||||
AC_GNU_SOURCE
|
||||
|
||||
dnl check for getopt in standard library
|
||||
dnl AC_CHECK_FUNCS(getopt_long , , [LIBOBJS="$LIBOBJS getopt.o getopt1.o"] )
|
||||
AC_CHECK_FUNCS(getopt_long, [], [])
|
||||
|
||||
dnl Check for uncommon wide char functions
|
||||
AC_CHECK_FUNCS(wcsdup, wcscasecmp, [], [])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
case "$host_cpu" in
|
||||
i*86) cpu_ia32=true ; AC_DEFINE(FLAC__CPU_IA32) ;;
|
||||
|
@ -1,169 +1,719 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "canonical_tag.h"
|
||||
#include "id3v2.h"
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/assert.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
static void local__safe_free(void *object)
|
||||
{
|
||||
if(0 != object)
|
||||
free(object);
|
||||
}
|
||||
|
||||
static void local__copy_field(char **dest, const char *src, unsigned n)
|
||||
{
|
||||
if(n > 0) {
|
||||
const char *p = src + n;
|
||||
while(p > src && *(--p) == ' ')
|
||||
;
|
||||
n = p - src + 1;
|
||||
if(0 != (*dest = malloc(n+1))) {
|
||||
memcpy(*dest, src, n);
|
||||
(*dest)[n] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
static FLAC__bool local__get_id3v1_tag_as_canonical(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__Id3v1_Tag id3v1_tag;
|
||||
|
||||
if(FLAC_plugin__id3v1_tag_get(filename, &id3v1_tag)) {
|
||||
FLAC_plugin__canonical_tag_convert_from_id3v1(tag, &id3v1_tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new()
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag *object = (FLAC_Plugin__CanonicalTag*)malloc(sizeof(FLAC_Plugin__CanonicalTag));
|
||||
if(0 != object)
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__ASSERT(0 != object);
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
free(object);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__ASSERT(0 != object);
|
||||
object->title = 0;
|
||||
object->composer = 0;
|
||||
object->performer = 0;
|
||||
object->album = 0;
|
||||
object->year_recorded = 0;
|
||||
object->year_performed = 0;
|
||||
object->track_number = 0;
|
||||
object->tracks_in_album = 0;
|
||||
object->genre = 0;
|
||||
object->comment = 0;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__ASSERT(0 != object);
|
||||
local__safe_free(object->title);
|
||||
local__safe_free(object->composer);
|
||||
local__safe_free(object->performer);
|
||||
local__safe_free(object->album);
|
||||
local__safe_free(object->year_recorded);
|
||||
local__safe_free(object->year_performed);
|
||||
local__safe_free(object->track_number);
|
||||
local__safe_free(object->tracks_in_album);
|
||||
local__safe_free(object->genre);
|
||||
local__safe_free(object->comment);
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
}
|
||||
|
||||
static void local__grab(char **dest, char **src)
|
||||
{
|
||||
if(0 == *dest) {
|
||||
*dest = *src;
|
||||
*src = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, FLAC_Plugin__CanonicalTag *src)
|
||||
{
|
||||
local__grab(&dest->title, &src->title);
|
||||
local__grab(&dest->composer, &src->composer);
|
||||
local__grab(&dest->performer, &src->performer);
|
||||
local__grab(&dest->album, &src->album);
|
||||
local__grab(&dest->year_recorded, &src->year_recorded);
|
||||
local__grab(&dest->year_performed, &src->year_performed);
|
||||
local__grab(&dest->track_number, &src->track_number);
|
||||
local__grab(&dest->tracks_in_album, &src->tracks_in_album);
|
||||
local__grab(&dest->genre, &src->genre);
|
||||
local__grab(&dest->comment, &src->comment);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *object, const FLAC_Plugin__Id3v1_Tag *id3v1_tag)
|
||||
{
|
||||
local__copy_field(&object->title, id3v1_tag->title, 30);
|
||||
local__copy_field(&object->composer, id3v1_tag->artist, 30);
|
||||
local__copy_field(&object->performer, id3v1_tag->artist, 30);
|
||||
local__copy_field(&object->album, id3v1_tag->album, 30);
|
||||
local__copy_field(&object->year_performed, id3v1_tag->year, 4);
|
||||
|
||||
/* Check for v1.1 tags. */
|
||||
if (id3v1_tag->comment.v1_1.zero == 0) {
|
||||
if(0 != (object->track_number = malloc(4)))
|
||||
sprintf(object->track_number, "%u", (unsigned)id3v1_tag->comment.v1_1.track);
|
||||
local__copy_field(&object->comment, id3v1_tag->comment.v1_1.comment, 28);
|
||||
}
|
||||
else {
|
||||
object->track_number = strdup("0");
|
||||
local__copy_field(&object->comment, id3v1_tag->comment.v1_0.comment, 30);
|
||||
}
|
||||
|
||||
object->genre = strdup(FLAC_plugin__id3v1_tag_get_genre_as_string(id3v1_tag->genre));
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag id3v1_tag, id3v2_tag;
|
||||
|
||||
FLAC_plugin__vorbiscomment_get(filename, tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v2_tag);
|
||||
(void)FLAC_plugin__id3v2_tag_get(filename, &id3v2_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v1_tag);
|
||||
(void)local__get_id3v1_tag_as_canonical(filename, &id3v1_tag);
|
||||
|
||||
/* merge tags, preferring, in order: vorbis comments, id3v2, id3v1 */
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v2_tag);
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v1_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&id3v1_tag);
|
||||
FLAC_plugin__canonical_tag_clear(&id3v2_tag);
|
||||
}
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "canonical_tag.h"
|
||||
#include "id3v2.h"
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/assert.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
#if 0
|
||||
#define __USE_GNU /*@@@@@@ needed on glibc systems to get wcsdup() and wcscasecmp() */
|
||||
#endif
|
||||
#include <wchar.h>
|
||||
|
||||
/*
|
||||
* Here lies hackage to get any missing wide character string functions we
|
||||
* need. The fallback implementations here are from glibc.
|
||||
*/
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(HAVE_WCSDUP)
|
||||
/* Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
/* Duplicate S, returning an identical malloc'd string. */
|
||||
wchar_t *
|
||||
wcsdup (s)
|
||||
const wchar_t *s;
|
||||
{
|
||||
size_t len = (__wcslen (s) + 1) * sizeof (wchar_t);
|
||||
void *new = malloc (len);
|
||||
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
|
||||
return (wchar_t *) memcpy (new, (void *) s, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(HAVE_WCSCASECMP)
|
||||
/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <wctype.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#ifndef weak_alias
|
||||
# define __wcscasecmp wcscasecmp
|
||||
# define TOLOWER(Ch) towlower (Ch)
|
||||
#else
|
||||
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
||||
# define __wcscasecmp __wcscasecmp_l
|
||||
# define TOLOWER(Ch) __towlower_l ((Ch), loc)
|
||||
# else
|
||||
# define TOLOWER(Ch) towlower (Ch)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
||||
# define LOCALE_PARAM , loc
|
||||
# define LOCALE_PARAM_DECL __locale_t loc;
|
||||
#else
|
||||
# define LOCALE_PARAM
|
||||
# define LOCALE_PARAM_DECL
|
||||
#endif
|
||||
|
||||
/* Compare S1 and S2, ignoring case, returning less than, equal to or
|
||||
greater than zero if S1 is lexicographically less than,
|
||||
equal to or greater than S2. */
|
||||
int
|
||||
__wcscasecmp (s1, s2 LOCALE_PARAM)
|
||||
const wchar_t *s1;
|
||||
const wchar_t *s2;
|
||||
LOCALE_PARAM_DECL
|
||||
{
|
||||
wint_t c1, c2;
|
||||
|
||||
if (s1 == s2)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
c1 = TOLOWER (*s1++);
|
||||
c2 = TOLOWER (*s2++);
|
||||
if (c1 == L'\0')
|
||||
break;
|
||||
}
|
||||
while (c1 == c2);
|
||||
|
||||
return c1 - c2;
|
||||
}
|
||||
#ifndef __wcscasecmp
|
||||
weak_alias (__wcscasecmp, wcscasecmp)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
/* @@@ cheesy and does base 10 only */
|
||||
wchar_t *local__itow(int value, wchar_t *string)
|
||||
{
|
||||
if (value == 0) {
|
||||
string[0] = (wchar_t)'0';
|
||||
string[1] = (wchar_t)0;
|
||||
}
|
||||
else {
|
||||
/* convert backwards, then reverse string */
|
||||
wchar_t *start = string, *s;
|
||||
if (value < 0) {
|
||||
*start++ = (wchar_t)'-';
|
||||
value = -value; /* @@@ overflow at INT_MIN */
|
||||
}
|
||||
s = start;
|
||||
while (value > 0) {
|
||||
*s++ = (wchar_t)((value % 10) + '0');
|
||||
value /= 10;
|
||||
}
|
||||
*s-- = (wchar_t)0;
|
||||
while (s > start) {
|
||||
wchar_t tmp = *s;
|
||||
*s-- = *start;
|
||||
*start++ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* helpers
|
||||
*/
|
||||
|
||||
/* TODO: should be moved out somewhere? @@@ */
|
||||
|
||||
wchar_t *FLAC_plugin__convert_ansi_to_wide(const char *src)
|
||||
{
|
||||
int len;
|
||||
wchar_t *dest;
|
||||
|
||||
FLAC__ASSERT(0 != src);
|
||||
|
||||
len = strlen(src) + 1;
|
||||
/* copy */
|
||||
dest = malloc(len*sizeof(wchar_t));
|
||||
if (dest) mbstowcs(dest, src, len);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* TODO: more validation? @@@ */
|
||||
static __inline int utf8len(const FLAC__byte *utf8)
|
||||
{
|
||||
FLAC__ASSERT(0 != utf8);
|
||||
if ((*utf8 & 0x80) == 0)
|
||||
return 1;
|
||||
else if ((*utf8 & 0xE0) == 0xC0)
|
||||
return 2;
|
||||
else if ((*utf8 & 0xF0) == 0xE0)
|
||||
return 3;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/* TODO: validation? @@@ */
|
||||
static __inline int utf8_to_ucs2(const FLAC__byte *utf8, wchar_t *ucs2)
|
||||
{
|
||||
int len;
|
||||
FLAC__ASSERT(utf8!=0 && *utf8!=0 && ucs2!=0);
|
||||
|
||||
if (!(len = utf8len(utf8))) return 0;
|
||||
|
||||
if (len == 1)
|
||||
*ucs2 = *utf8;
|
||||
else if (len == 2)
|
||||
*ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F);
|
||||
else if (len == 3)
|
||||
*ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F);
|
||||
else {
|
||||
FLAC__ASSERT(len == 0);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
wchar_t *FLAC_plugin__convert_utf8_to_ucs2(const char *src, unsigned length)
|
||||
{
|
||||
wchar_t *out, *p;
|
||||
const char *s;
|
||||
int len = 0;
|
||||
/* calculate length */
|
||||
for (s=src; length && *s; len++)
|
||||
{
|
||||
int l = utf8len(s);
|
||||
if (!l) break;
|
||||
s += l;
|
||||
length -= l;
|
||||
}
|
||||
/* allocate */
|
||||
len++;
|
||||
p = out = (wchar_t*)malloc(len * sizeof(wchar_t));
|
||||
if (!out) return NULL;
|
||||
/* convert */
|
||||
for (s=src; --len; p++)
|
||||
{
|
||||
int l = utf8_to_ucs2(s, p);
|
||||
/* l==0 is possible, because real conversion */
|
||||
/* might do more careful validation */
|
||||
if (!l) break;
|
||||
s += l;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static __inline int ucs2len(wchar_t ucs2)
|
||||
{
|
||||
if (ucs2 < 0x0080)
|
||||
return 1;
|
||||
else if (ucs2 < 0x0800)
|
||||
return 2;
|
||||
else return 3;
|
||||
}
|
||||
|
||||
static __inline int ucs2_to_utf8(wchar_t ucs2, FLAC__byte *utf8)
|
||||
{
|
||||
if (ucs2 < 0x080)
|
||||
{
|
||||
utf8[0] = (FLAC__byte)ucs2;
|
||||
return 1;
|
||||
}
|
||||
else if (ucs2 < 0x800)
|
||||
{
|
||||
utf8[0] = 0xc0 | (ucs2 >> 6);
|
||||
utf8[1] = 0x80 | (ucs2 & 0x3f);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
utf8[0] = 0xe0 | (ucs2 >> 12);
|
||||
utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f);
|
||||
utf8[2] = 0x80 | (ucs2 & 0x3f);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
char *FLAC_plugin__convert_ucs2_to_utf8(const wchar_t *src)
|
||||
{
|
||||
const wchar_t *s;
|
||||
char *out, *p;
|
||||
int len = 0;
|
||||
FLAC__ASSERT(0 != src);
|
||||
/* calculate length */
|
||||
for (s=src; *s; s++)
|
||||
len += ucs2len(*s);
|
||||
/* allocate */
|
||||
len++;
|
||||
p = out = malloc(len);
|
||||
if (!out) return NULL;
|
||||
/* convert */
|
||||
for (s=src; *s; s++)
|
||||
{
|
||||
int l = ucs2_to_utf8(*s, p);
|
||||
p += l;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* init/clear/delete
|
||||
*/
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new()
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag *object = (FLAC_Plugin__CanonicalTag*)malloc(sizeof(FLAC_Plugin__CanonicalTag));
|
||||
if (object != 0)
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
free(object);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
object->head = object->tail = 0;
|
||||
object->count = 0;
|
||||
}
|
||||
|
||||
static void FLAC_plugin__canonical_tag_clear_entry(FLAC__tag_entry *entry)
|
||||
{
|
||||
free(entry->name);
|
||||
free(entry->value);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__tag_entry *entry = object->head;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
FLAC__tag_entry *next = entry->next;
|
||||
FLAC_plugin__canonical_tag_clear_entry(entry);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
}
|
||||
|
||||
/*
|
||||
* internal
|
||||
*/
|
||||
|
||||
static FLAC__tag_entry *FLAC_plugin__canonical_find(const FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
FLAC__tag_entry *entry = tag->head;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#define FLAC__WCSCASECMP wcsicmp
|
||||
#else
|
||||
#define FLAC__WCSCASECMP wcscasecmp
|
||||
#endif
|
||||
if (!FLAC__WCSCASECMP(name, entry->name))
|
||||
#undef FLAC__WCSCASECMP
|
||||
break;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* NOTE: does NOT copy strings. takes ownership over passed strings. */
|
||||
static void FLAC_plugin__canonical_add_tail(FLAC_Plugin__CanonicalTag *tag, wchar_t *name, wchar_t *value)
|
||||
{
|
||||
FLAC__tag_entry *entry = (FLAC__tag_entry*)malloc(sizeof(FLAC__tag_entry));
|
||||
if (!entry)
|
||||
{
|
||||
free(name);
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
/* init */
|
||||
entry->name = name;
|
||||
entry->value = value;
|
||||
/* add */
|
||||
entry->prev = tag->tail;
|
||||
if (tag->tail)
|
||||
tag->tail->next = entry;
|
||||
tag->tail = entry;
|
||||
if (!tag->head)
|
||||
tag->head = entry;
|
||||
entry->next = 0;
|
||||
tag->count++;
|
||||
}
|
||||
|
||||
static void FLAC_plugin__canonical_add_new(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value)
|
||||
{
|
||||
FLAC_plugin__canonical_add_tail(tag, wcsdup(name), wcsdup(value));
|
||||
}
|
||||
|
||||
/* NOTE: does NOT copy value, but copies name */
|
||||
static void FLAC_plugin__canonical_set_nc(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, wchar_t *value)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
free(entry->value);
|
||||
entry->value = value;
|
||||
}
|
||||
else FLAC_plugin__canonical_add_tail(tag, wcsdup(name), value);
|
||||
}
|
||||
|
||||
/* NOTE: does NOT copy strings. takes ownership over passed strings. (except sep!) */
|
||||
static void FLAC_plugin__canonical_add_nc(FLAC_Plugin__CanonicalTag *tag, wchar_t *name, wchar_t *value, const wchar_t *sep)
|
||||
{
|
||||
FLAC__tag_entry *entry;
|
||||
|
||||
if (sep && (entry = FLAC_plugin__canonical_find(tag, name)))
|
||||
{
|
||||
unsigned newlen = wcslen(entry->value) + wcslen(value) + wcslen(sep) + 1;
|
||||
wchar_t *newvalue = realloc(entry->value, newlen*sizeof(wchar_t));
|
||||
|
||||
if (newvalue)
|
||||
{
|
||||
entry->value = newvalue;
|
||||
wcscat(entry->value, sep);
|
||||
wcscat(entry->value, value);
|
||||
}
|
||||
|
||||
free(name);
|
||||
free(value);
|
||||
}
|
||||
else FLAC_plugin__canonical_add_tail(tag, name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* manipulation
|
||||
*/
|
||||
|
||||
void FLAC_plugin__canonical_set(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value)
|
||||
{
|
||||
FLAC_plugin__canonical_set_nc(tag, name, wcsdup(value));
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_set_new(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
if (!entry) FLAC_plugin__canonical_add_new(tag, name, value);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_set_ansi(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const char *value)
|
||||
{
|
||||
wchar_t *val = FLAC_plugin__convert_ansi_to_wide(value);
|
||||
if (val) FLAC_plugin__canonical_set_nc(tag, name, val);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_add(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value, const wchar_t *sep)
|
||||
{
|
||||
FLAC__tag_entry *entry;
|
||||
|
||||
if (sep && (entry = FLAC_plugin__canonical_find(tag, name)))
|
||||
{
|
||||
unsigned newlen = wcslen(entry->value) + wcslen(value) + wcslen(sep) + 1;
|
||||
wchar_t *newvalue = realloc(entry->value, newlen*sizeof(wchar_t));
|
||||
|
||||
if (newvalue)
|
||||
{
|
||||
entry->value = newvalue;
|
||||
wcscat(entry->value, sep);
|
||||
wcscat(entry->value, value);
|
||||
}
|
||||
}
|
||||
else FLAC_plugin__canonical_add_new(tag, name, value);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_add_utf8(FLAC_Plugin__CanonicalTag *tag, const char *name, const char *value, unsigned namelen, unsigned vallen, const char *sep)
|
||||
{
|
||||
wchar_t *n = FLAC_plugin__convert_utf8_to_ucs2(name, namelen);
|
||||
wchar_t *v = FLAC_plugin__convert_utf8_to_ucs2(value, vallen);
|
||||
wchar_t *s = sep ? FLAC_plugin__convert_utf8_to_ucs2(sep, -1) : 0;
|
||||
|
||||
if (n && v)
|
||||
{
|
||||
FLAC_plugin__canonical_add_nc(tag, n, v, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n) free(n);
|
||||
if (v) free(v);
|
||||
}
|
||||
if (s) free(s);
|
||||
}
|
||||
|
||||
const wchar_t *FLAC_plugin__canonical_get(const FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
return entry ? entry->value : 0;
|
||||
}
|
||||
|
||||
FLAC__bool FLAC_plugin__canonical_remove(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
else tag->head = entry->next;
|
||||
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
else tag->tail = entry->prev;
|
||||
|
||||
FLAC_plugin__canonical_tag_clear_entry(entry);
|
||||
tag->count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_remove_all(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
while (FLAC_plugin__canonical_remove(tag, name));
|
||||
}
|
||||
|
||||
char *FLAC_plugin__canonical_get_formatted(FLAC__tag_iterator it)
|
||||
{
|
||||
int len1 = wcslen(it->name);
|
||||
int len2 = wcslen(it->value);
|
||||
int len = len1 + len2 + 1;
|
||||
wchar_t *val = malloc((len+1) * sizeof(wchar_t));
|
||||
|
||||
if (val)
|
||||
{
|
||||
char *res;
|
||||
|
||||
memcpy(val, it->name, len1 * sizeof(wchar_t));
|
||||
val[len1] = '=';
|
||||
memcpy(val+len1+1, it->value, len2 * sizeof(wchar_t));
|
||||
val[len] = 0;
|
||||
|
||||
res = FLAC_plugin__convert_ucs2_to_utf8(val);
|
||||
free(val);
|
||||
return res;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* merging
|
||||
*/
|
||||
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, const FLAC_Plugin__CanonicalTag *src)
|
||||
{
|
||||
FLAC__tag_entry *entry = src->head;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
FLAC_plugin__canonical_set_new(dest, entry->name, entry->value);
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
static wchar_t *local__copy_field(const char *src, unsigned n)
|
||||
{
|
||||
const char *p = src + n;
|
||||
wchar_t *dest;
|
||||
FLAC__ASSERT(n > 0);
|
||||
|
||||
while (p>src && *(--p)==' ');
|
||||
|
||||
n = p - src + 1;
|
||||
if (!n) return NULL;
|
||||
|
||||
if ((dest = malloc((n+1)*sizeof(wchar_t))) != 0)
|
||||
{
|
||||
mbstowcs(dest, src, n);
|
||||
dest[n] = 0;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void local__add_id3_field(FLAC_Plugin__CanonicalTag *object, const char *value, size_t length, const wchar_t *new_name)
|
||||
{
|
||||
wchar_t *tmp;
|
||||
if (0 != value && length > 0) {
|
||||
tmp = local__copy_field(value, length);
|
||||
if (tmp)
|
||||
FLAC_plugin__canonical_add_tail(object, wcsdup(new_name), tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *object, const FLAC_Plugin__Id3v1_Tag *id3v1_tag)
|
||||
{
|
||||
wchar_t *tmp;
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
|
||||
local__add_id3_field(object, id3v1_tag->title, 30, L"TITLE");
|
||||
local__add_id3_field(object, id3v1_tag->artist, 30, L"ARTIST");
|
||||
local__add_id3_field(object, id3v1_tag->album, 30, L"ALBUM");
|
||||
local__add_id3_field(object, id3v1_tag->year, 4, L"YEAR");
|
||||
|
||||
/* check for v1.1 tags */
|
||||
if (id3v1_tag->zero == 0)
|
||||
{
|
||||
if (id3v1_tag->track && (tmp=(wchar_t*)malloc(sizeof(id3v1_tag->track)*4*sizeof(wchar_t)))!=0)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_itow(id3v1_tag->track, tmp, 10);
|
||||
#else
|
||||
local__itow(id3v1_tag->track, tmp);
|
||||
#endif
|
||||
FLAC_plugin__canonical_add_tail(object, wcsdup(L"TRACKNUMBER"), tmp);
|
||||
}
|
||||
local__add_id3_field(object, id3v1_tag->comment, 28, L"DESCRIPTION");
|
||||
}
|
||||
else
|
||||
{
|
||||
local__add_id3_field(object, id3v1_tag->comment, 30, L"DESCRIPTION");
|
||||
}
|
||||
|
||||
tmp = FLAC_plugin__convert_ansi_to_wide(FLAC_plugin__id3v1_tag_get_genre_as_string(id3v1_tag->genre));
|
||||
if (tmp) FLAC_plugin__canonical_add_tail(object, wcsdup(L"GENRE"), tmp);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v2(FLAC_Plugin__CanonicalTag *object, const FLAC_Plugin__Id3v2_Tag *id3v2_tag)
|
||||
{
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
|
||||
local__add_id3_field(object, id3v2_tag->title , strlen(id3v2_tag->title) , L"TITLE");
|
||||
local__add_id3_field(object, id3v2_tag->composer , strlen(id3v2_tag->composer) , L"ARTIST");
|
||||
local__add_id3_field(object, id3v2_tag->performer , strlen(id3v2_tag->performer) , L"PERFORMER");
|
||||
local__add_id3_field(object, id3v2_tag->album , strlen(id3v2_tag->album) , L"ALBUM");
|
||||
local__add_id3_field(object, id3v2_tag->year_recorded , strlen(id3v2_tag->year_recorded) , L"YEAR_RECORDED");
|
||||
local__add_id3_field(object, id3v2_tag->year_performed , strlen(id3v2_tag->year_performed) , L"YEAR_PERFORMED");
|
||||
local__add_id3_field(object, id3v2_tag->track_number , strlen(id3v2_tag->track_number) , L"TRACKNUMBER");
|
||||
local__add_id3_field(object, id3v2_tag->tracks_in_album, strlen(id3v2_tag->tracks_in_album), L"TRACKS_IN_ALBUM");
|
||||
local__add_id3_field(object, id3v2_tag->genre , strlen(id3v2_tag->genre) , L"GENRE");
|
||||
local__add_id3_field(object, id3v2_tag->comment , strlen(id3v2_tag->comment) , L"DESCRIPTION");
|
||||
}
|
||||
|
||||
static FLAC__bool local__get_id3v1_tag_as_canonical(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__Id3v1_Tag id3v1_tag;
|
||||
|
||||
if (FLAC_plugin__id3v1_tag_get(filename, &id3v1_tag))
|
||||
{
|
||||
FLAC_plugin__canonical_tag_convert_from_id3v1(tag, &id3v1_tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static FLAC__bool local__get_id3v2_tag_as_canonical(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__Id3v2_Tag id3v2_tag;
|
||||
|
||||
if (FLAC_plugin__id3v2_tag_get(filename, &id3v2_tag))
|
||||
{
|
||||
FLAC_plugin__canonical_tag_convert_from_id3v2(tag, &id3v2_tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_add_id3v1(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag id3v1_tag;
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v1_tag);
|
||||
(void)local__get_id3v1_tag_as_canonical(filename, &id3v1_tag);
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v1_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&id3v1_tag);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_add_id3v2(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag id3v2_tag;
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v2_tag);
|
||||
(void)local__get_id3v2_tag_as_canonical(filename, &id3v2_tag);
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v2_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&id3v2_tag);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep)
|
||||
{
|
||||
FLAC_plugin__vorbiscomment_get(filename, tag, sep);
|
||||
FLAC_plugin__canonical_tag_add_id3v2(filename, tag);
|
||||
FLAC_plugin__canonical_tag_add_id3v1(filename, tag);
|
||||
}
|
||||
|
@ -1,55 +1,118 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
#define FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
|
||||
#include "id3v1.h"
|
||||
|
||||
typedef struct {
|
||||
char *title;
|
||||
char *composer;
|
||||
char *performer;
|
||||
char *album;
|
||||
char *year_recorded;
|
||||
char *year_performed;
|
||||
char *track_number;
|
||||
char *tracks_in_album;
|
||||
char *genre;
|
||||
char *comment;
|
||||
} FLAC_Plugin__CanonicalTag;
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new();
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *);
|
||||
|
||||
/* For each null field in dest, move the corresponding field from src
|
||||
* WATCHOUT: note that src is not-const, because fields are 'moved' from
|
||||
* src to dest and the src field is set to null.
|
||||
*/
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, FLAC_Plugin__CanonicalTag *src);
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *, const FLAC_Plugin__Id3v1_Tag *);
|
||||
|
||||
/* Returns a merged tag based on any Vorbis comments, id3v2 tag, and id3v1.
|
||||
* In case of overlaps the preceding precedence applies.
|
||||
*/
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
|
||||
#endif
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
#define FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
|
||||
#include "id3v1.h"
|
||||
#include "id3v2.h"
|
||||
|
||||
/* TODO: splay tree? */
|
||||
typedef struct tagFLAC__tag_entry FLAC__tag_entry;
|
||||
struct tagFLAC__tag_entry
|
||||
{
|
||||
FLAC__tag_entry *next, *prev;
|
||||
/* TODO: name in ascii? */
|
||||
wchar_t *name;
|
||||
wchar_t *value;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FLAC__tag_entry *head, *tail;
|
||||
unsigned count;
|
||||
} FLAC_Plugin__CanonicalTag;
|
||||
|
||||
|
||||
typedef FLAC__tag_entry *FLAC__tag_iterator;
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new();
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *);
|
||||
|
||||
/* note that multiple fields with the same name are allowed.
|
||||
* set - adds field if it's not present yet, or replaces
|
||||
* existing field if it's present.
|
||||
*/
|
||||
void FLAC_plugin__canonical_set(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value);
|
||||
void FLAC_plugin__canonical_set_ansi(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const char *value);
|
||||
/* set_new - only adds field if it's not present yet. */
|
||||
void FLAC_plugin__canonical_set_new(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value);
|
||||
/* add - adds field if it's not present yet, or merges value with existing
|
||||
* field, if it's present. (sep - separator string to use when merging;
|
||||
* if sep==NULL no merging occurs - always adds new field)
|
||||
*/
|
||||
void FLAC_plugin__canonical_add(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value, const wchar_t *sep);
|
||||
void FLAC_plugin__canonical_add_utf8(FLAC_Plugin__CanonicalTag *tag, const char *name, const char *value, unsigned namelen, unsigned vallen, const char *sep); /* 'namelen'/'vallen' may be (unsigned)(-1) if 'name'/'value' is NUL-terminated */
|
||||
|
||||
/* gets value of the first field with the given name (NULL if field not found) */
|
||||
const wchar_t *FLAC_plugin__canonical_get(const FLAC_Plugin__CanonicalTag *tag, const wchar_t *name);
|
||||
/* removes first field with the given name.
|
||||
* (returns 'true' if deleted, 'false' if not found)
|
||||
*/
|
||||
FLAC__bool FLAC_plugin__canonical_remove(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name);
|
||||
/* removes all fields with the given name. */
|
||||
void FLAC_plugin__canonical_remove_all(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name);
|
||||
|
||||
/* enumeration */
|
||||
static __inline unsigned FLAC_plugin__canonical_get_count(FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
return tag->count;
|
||||
}
|
||||
static __inline FLAC__tag_iterator FLAC_plugin__canonical_first(FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
return tag->head;
|
||||
}
|
||||
static __inline FLAC__tag_iterator FLAC_plugin__canonical_next(FLAC__tag_iterator it)
|
||||
{
|
||||
return it->next;
|
||||
}
|
||||
static __inline wchar_t *FLAC_plugin__canonical_get_name(FLAC__tag_iterator it)
|
||||
{
|
||||
return it->name;
|
||||
}
|
||||
static __inline wchar_t *FLAC_plugin__canonical_get_value(FLAC__tag_iterator it)
|
||||
{
|
||||
return it->value;
|
||||
}
|
||||
|
||||
/* returns a new string containing the current entry in UTF-8 in "NAME=VALUE" form */
|
||||
char *FLAC_plugin__canonical_get_formatted(FLAC__tag_iterator it);
|
||||
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, const FLAC_Plugin__CanonicalTag *src);
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *, const FLAC_Plugin__Id3v1_Tag *);
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v2(FLAC_Plugin__CanonicalTag *, const FLAC_Plugin__Id3v2_Tag *);
|
||||
|
||||
void FLAC_plugin__canonical_tag_add_id3v1(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
void FLAC_plugin__canonical_tag_add_id3v2(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
|
||||
/* Returns a merged tag based on any Vorbis comments, id3v2 tag, and id3v1.
|
||||
* In case of overlaps the preceding precedence applies.
|
||||
*
|
||||
* sep - separator to use when merging fields with same name (in VorbisComment).
|
||||
* should be in UTF-8. if sep==NULL, no merging occurs, so multiple fields
|
||||
* with the same name can exist.
|
||||
*/
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep);
|
||||
|
||||
/* helpers */
|
||||
wchar_t *FLAC_plugin__convert_ansi_to_wide(const char *src);
|
||||
wchar_t *FLAC_plugin__convert_utf8_to_ucs2(const char *src, unsigned length); /* 'length' may be (unsigned)(-1) if 'src' is NUL-terminated */
|
||||
char *FLAC_plugin__convert_ucs2_to_utf8(const wchar_t *src);
|
||||
|
||||
#endif
|
||||
|
@ -1,229 +1,214 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
#include "id3v1.h"
|
||||
#include "locale_hack.h"
|
||||
|
||||
|
||||
/*
|
||||
* Do not sort genres!!
|
||||
* Last Update: 2000/04/30
|
||||
*/
|
||||
static const char * const FLAC_plugin__id3v1_tag_genre_table[] =
|
||||
{
|
||||
"Blues", /* 0 */
|
||||
"Classic Rock",
|
||||
"Country",
|
||||
"Dance",
|
||||
"Disco",
|
||||
"Funk", /* 5 */
|
||||
"Grunge",
|
||||
"Hip-Hop",
|
||||
"Jazz",
|
||||
"Metal",
|
||||
"New Age", /* 10 */
|
||||
"Oldies",
|
||||
"Other",
|
||||
"Pop",
|
||||
"R&B",
|
||||
"Rap", /* 15 */
|
||||
"Reggae",
|
||||
"Rock",
|
||||
"Techno",
|
||||
"Industrial",
|
||||
"Alternative", /* 20 */
|
||||
"Ska",
|
||||
"Death Metal",
|
||||
"Pranks",
|
||||
"Soundtrack",
|
||||
"Euro-Techno", /* 25 */
|
||||
"Ambient",
|
||||
"Trip-Hop",
|
||||
"Vocal",
|
||||
"Jazz+Funk",
|
||||
"Fusion", /* 30 */
|
||||
"Trance",
|
||||
"Classical",
|
||||
"Instrumental",
|
||||
"Acid",
|
||||
"House", /* 35 */
|
||||
"Game",
|
||||
"Sound Clip",
|
||||
"Gospel",
|
||||
"Noise",
|
||||
"Altern Rock", /* 40 */
|
||||
"Bass",
|
||||
"Soul",
|
||||
"Punk",
|
||||
"Space",
|
||||
"Meditative", /* 45 */
|
||||
"Instrumental Pop",
|
||||
"Instrumental Rock",
|
||||
"Ethnic",
|
||||
"Gothic",
|
||||
"Darkwave", /* 50 */
|
||||
"Techno-Industrial",
|
||||
"Electronic",
|
||||
"Pop-Folk",
|
||||
"Eurodance",
|
||||
"Dream", /* 55 */
|
||||
"Southern Rock",
|
||||
"Comedy",
|
||||
"Cult",
|
||||
"Gangsta",
|
||||
"Top 40", /* 60 */
|
||||
"Christian Rap",
|
||||
"Pop/Funk",
|
||||
"Jungle",
|
||||
"Native American",
|
||||
"Cabaret", /* 65 */
|
||||
"New Wave",
|
||||
"Psychadelic",
|
||||
"Rave",
|
||||
"Showtunes",
|
||||
"Trailer", /* 70 */
|
||||
"Lo-Fi",
|
||||
"Tribal",
|
||||
"Acid Punk",
|
||||
"Acid Jazz",
|
||||
"Polka", /* 75 */
|
||||
"Retro",
|
||||
"Musical",
|
||||
"Rock & Roll",
|
||||
"Hard Rock",
|
||||
"Folk", /* 80 */
|
||||
"Folk/Rock",
|
||||
"National Folk",
|
||||
"Fast Fusion",
|
||||
"Swing",
|
||||
"Bebob", /* 85 */
|
||||
"Latin",
|
||||
"Revival",
|
||||
"Celtic",
|
||||
"Bluegrass",
|
||||
"Avantgarde", /* 90 */
|
||||
"Gothic Rock",
|
||||
"Progressive Rock",
|
||||
"Psychedelic Rock",
|
||||
"Symphonic Rock",
|
||||
"Slow Rock", /* 95 */
|
||||
"Big Band",
|
||||
"Chorus",
|
||||
"Easy Listening",
|
||||
"Acoustic",
|
||||
"Humour", /* 100 */
|
||||
"Speech",
|
||||
"Chanson",
|
||||
"Opera",
|
||||
"Chamber Music",
|
||||
"Sonata", /* 105 */
|
||||
"Symphony",
|
||||
"Booty Bass",
|
||||
"Primus",
|
||||
"Porn Groove",
|
||||
"Satire", /* 110 */
|
||||
"Slow Jam",
|
||||
"Club",
|
||||
"Tango",
|
||||
"Samba",
|
||||
"Folklore", /* 115 */
|
||||
"Ballad",
|
||||
"Power Ballad",
|
||||
"Rhythmic Soul",
|
||||
"Freestyle",
|
||||
"Duet", /* 120 */
|
||||
"Punk Rock",
|
||||
"Drum Solo",
|
||||
"A Capella",
|
||||
"Euro-House",
|
||||
"Dance Hall", /* 125 */
|
||||
"Goa",
|
||||
"Drum & Bass",
|
||||
"Club-House",
|
||||
"Hardcore",
|
||||
"Terror", /* 130 */
|
||||
"Indie",
|
||||
"BritPop",
|
||||
"Negerpunk",
|
||||
"Polsk Punk",
|
||||
"Beat", /* 135 */
|
||||
"Christian Gangsta Rap",
|
||||
"Heavy Metal",
|
||||
"Black Metal",
|
||||
"Crossover",
|
||||
"Contemporary Christian",/* 140 */
|
||||
"Christian Rock",
|
||||
"Merengue",
|
||||
"Salsa",
|
||||
"Thrash Metal",
|
||||
"Anime", /* 145 */
|
||||
"JPop",
|
||||
"Synthpop"
|
||||
};
|
||||
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v1_tag_get(const char *filename, FLAC_Plugin__Id3v1_Tag *tag)
|
||||
{
|
||||
char raw[128];
|
||||
FILE *f;
|
||||
|
||||
FLAC__ASSERT(0 != filename);
|
||||
FLAC__ASSERT(0 != tag);
|
||||
|
||||
memset(tag, 0, sizeof(FLAC_Plugin__Id3v1_Tag));
|
||||
|
||||
if(0 == (f = fopen(filename, "rb")))
|
||||
return false;
|
||||
if(-1 == fseek(f, -128, SEEK_END)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
if(fread(raw, 1, 128, f) < 128) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
if(strncmp(raw, "TAG", 3))
|
||||
return false;
|
||||
else {
|
||||
memcpy(tag->tag, raw, 3);
|
||||
memcpy(tag->title, raw+3, 30);
|
||||
memcpy(tag->artist, raw+33, 30);
|
||||
memcpy(tag->album, raw+63, 30);
|
||||
memcpy(tag->year, raw+93, 4);
|
||||
memcpy(tag->comment.v1_0.comment, raw+97, 30);
|
||||
tag->genre = raw[127];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *FLAC_plugin__id3v1_tag_get_genre_as_string(unsigned char genre_code)
|
||||
{
|
||||
if (genre_code < FLAC_plugin__id3v1_tag_genre_table_max())
|
||||
return gettext(FLAC_plugin__id3v1_tag_genre_table[genre_code]);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
unsigned FLAC_plugin__id3v1_tag_genre_table_max()
|
||||
{
|
||||
return sizeof(FLAC_plugin__id3v1_tag_genre_table) / sizeof(FLAC_plugin__id3v1_tag_genre_table[0]) - 1;
|
||||
}
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
#include "id3v1.h"
|
||||
#include "locale_hack.h"
|
||||
|
||||
|
||||
/*
|
||||
* Do not sort genres!!
|
||||
* Last Update: 2000/04/30
|
||||
*/
|
||||
static const char * const FLAC_plugin__id3v1_tag_genre_table[] =
|
||||
{
|
||||
"Blues", /* 0 */
|
||||
"Classic Rock",
|
||||
"Country",
|
||||
"Dance",
|
||||
"Disco",
|
||||
"Funk", /* 5 */
|
||||
"Grunge",
|
||||
"Hip-Hop",
|
||||
"Jazz",
|
||||
"Metal",
|
||||
"New Age", /* 10 */
|
||||
"Oldies",
|
||||
"Other",
|
||||
"Pop",
|
||||
"R&B",
|
||||
"Rap", /* 15 */
|
||||
"Reggae",
|
||||
"Rock",
|
||||
"Techno",
|
||||
"Industrial",
|
||||
"Alternative", /* 20 */
|
||||
"Ska",
|
||||
"Death Metal",
|
||||
"Pranks",
|
||||
"Soundtrack",
|
||||
"Euro-Techno", /* 25 */
|
||||
"Ambient",
|
||||
"Trip-Hop",
|
||||
"Vocal",
|
||||
"Jazz+Funk",
|
||||
"Fusion", /* 30 */
|
||||
"Trance",
|
||||
"Classical",
|
||||
"Instrumental",
|
||||
"Acid",
|
||||
"House", /* 35 */
|
||||
"Game",
|
||||
"Sound Clip",
|
||||
"Gospel",
|
||||
"Noise",
|
||||
"Altern Rock", /* 40 */
|
||||
"Bass",
|
||||
"Soul",
|
||||
"Punk",
|
||||
"Space",
|
||||
"Meditative", /* 45 */
|
||||
"Instrumental Pop",
|
||||
"Instrumental Rock",
|
||||
"Ethnic",
|
||||
"Gothic",
|
||||
"Darkwave", /* 50 */
|
||||
"Techno-Industrial",
|
||||
"Electronic",
|
||||
"Pop-Folk",
|
||||
"Eurodance",
|
||||
"Dream", /* 55 */
|
||||
"Southern Rock",
|
||||
"Comedy",
|
||||
"Cult",
|
||||
"Gangsta",
|
||||
"Top 40", /* 60 */
|
||||
"Christian Rap",
|
||||
"Pop/Funk",
|
||||
"Jungle",
|
||||
"Native American",
|
||||
"Cabaret", /* 65 */
|
||||
"New Wave",
|
||||
"Psychadelic",
|
||||
"Rave",
|
||||
"Showtunes",
|
||||
"Trailer", /* 70 */
|
||||
"Lo-Fi",
|
||||
"Tribal",
|
||||
"Acid Punk",
|
||||
"Acid Jazz",
|
||||
"Polka", /* 75 */
|
||||
"Retro",
|
||||
"Musical",
|
||||
"Rock & Roll",
|
||||
"Hard Rock",
|
||||
"Folk", /* 80 */
|
||||
"Folk/Rock",
|
||||
"National Folk",
|
||||
"Fast Fusion",
|
||||
"Swing",
|
||||
"Bebob", /* 85 */
|
||||
"Latin",
|
||||
"Revival",
|
||||
"Celtic",
|
||||
"Bluegrass",
|
||||
"Avantgarde", /* 90 */
|
||||
"Gothic Rock",
|
||||
"Progressive Rock",
|
||||
"Psychedelic Rock",
|
||||
"Symphonic Rock",
|
||||
"Slow Rock", /* 95 */
|
||||
"Big Band",
|
||||
"Chorus",
|
||||
"Easy Listening",
|
||||
"Acoustic",
|
||||
"Humour", /* 100 */
|
||||
"Speech",
|
||||
"Chanson",
|
||||
"Opera",
|
||||
"Chamber Music",
|
||||
"Sonata", /* 105 */
|
||||
"Symphony",
|
||||
"Booty Bass",
|
||||
"Primus",
|
||||
"Porn Groove",
|
||||
"Satire", /* 110 */
|
||||
"Slow Jam",
|
||||
"Club",
|
||||
"Tango",
|
||||
"Samba",
|
||||
"Folklore", /* 115 */
|
||||
"Ballad",
|
||||
"Power Ballad",
|
||||
"Rhythmic Soul",
|
||||
"Freestyle",
|
||||
"Duet", /* 120 */
|
||||
"Punk Rock",
|
||||
"Drum Solo",
|
||||
"A Capella",
|
||||
"Euro-House",
|
||||
"Dance Hall", /* 125 */
|
||||
"Goa",
|
||||
"Drum & Bass",
|
||||
"Club-House",
|
||||
"Hardcore",
|
||||
"Terror", /* 130 */
|
||||
"Indie",
|
||||
"BritPop",
|
||||
"Negerpunk",
|
||||
"Polsk Punk",
|
||||
"Beat", /* 135 */
|
||||
"Christian Gangsta Rap",
|
||||
"Heavy Metal",
|
||||
"Black Metal",
|
||||
"Crossover",
|
||||
"Contemporary Christian",/* 140 */
|
||||
"Christian Rock",
|
||||
"Merengue",
|
||||
"Salsa",
|
||||
"Thrash Metal",
|
||||
"Anime", /* 145 */
|
||||
"JPop",
|
||||
"Synthpop"
|
||||
};
|
||||
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v1_tag_get(const char *filename, FLAC_Plugin__Id3v1_Tag *tag)
|
||||
{
|
||||
FILE *f;
|
||||
int res;
|
||||
|
||||
FLAC__ASSERT(0 != filename);
|
||||
FLAC__ASSERT(0 != tag);
|
||||
|
||||
memset(tag, 0, sizeof(FLAC_Plugin__Id3v1_Tag));
|
||||
|
||||
if(0 == (f = fopen(filename, "rb")))
|
||||
return false;
|
||||
if(-1 == fseek(f, -128, SEEK_END)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
res = fread(tag, 128, 1, f);
|
||||
fclose(f);
|
||||
return res==1 && !strncmp(tag->tag, "TAG", 3);
|
||||
}
|
||||
|
||||
const char *FLAC_plugin__id3v1_tag_get_genre_as_string(unsigned char genre_code)
|
||||
{
|
||||
if (genre_code < (sizeof(FLAC_plugin__id3v1_tag_genre_table)/sizeof(FLAC_plugin__id3v1_tag_genre_table[0])))
|
||||
return gettext(FLAC_plugin__id3v1_tag_genre_table[genre_code]);
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
unsigned FLAC_plugin__id3v1_tag_genre_table_max()
|
||||
{
|
||||
return sizeof(FLAC_plugin__id3v1_tag_genre_table) / sizeof(FLAC_plugin__id3v1_tag_genre_table[0]) - 1;
|
||||
}
|
||||
|
@ -23,25 +23,23 @@
|
||||
|
||||
#include "FLAC/ordinals.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
char tag[3];
|
||||
char title[30];
|
||||
char artist[30];
|
||||
char album[30];
|
||||
char year[4];
|
||||
union {
|
||||
struct {
|
||||
char comment[30];
|
||||
} v1_0;
|
||||
struct {
|
||||
char comment[28];
|
||||
char zero;
|
||||
unsigned char track;
|
||||
} v1_1;
|
||||
} comment;
|
||||
/* always use layout of id3 v1.1 */
|
||||
char comment[28];
|
||||
char zero;
|
||||
unsigned char track;
|
||||
unsigned char genre;
|
||||
} FLAC_Plugin__Id3v1_Tag;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v1_tag_get(const char *filename, FLAC_Plugin__Id3v1_Tag *tag);
|
||||
|
||||
|
||||
|
@ -24,6 +24,11 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
|
||||
#include <stdlib.h> /* for free() */
|
||||
#include <string.h> /* for memset() */
|
||||
|
||||
#ifdef FLAC__HAS_ID3LIB
|
||||
#include <id3.h>
|
||||
#include <stdio.h>
|
||||
@ -32,8 +37,6 @@
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
|
||||
#include "id3v1.h" /* for genre stuff */
|
||||
#include "locale_hack.h"
|
||||
|
||||
@ -113,25 +116,25 @@ static size_t local__ID3Field_GetASCII_wrapper(const ID3Field *field, char *buff
|
||||
* = 3.7.13 : first item num is 0 for ID3Field_GetASCII
|
||||
* >= 3.8.0 : doesn't need item num for ID3Field_GetASCII
|
||||
*/
|
||||
# if (ID3LIB_MAJOR >= 3)
|
||||
# if (ID3LIB_MAJOR >= 3)
|
||||
/* (>= 3.x.x) */
|
||||
# if (ID3LIB_MINOR <= 7)
|
||||
# if (ID3LIB_MINOR <= 7)
|
||||
/* (3.0.0 to 3.7.x) */
|
||||
# if (ID3LIB_PATCH >= 13)
|
||||
# if (ID3LIB_PATCH >= 13)
|
||||
/* (>= 3.7.13) */
|
||||
return ID3Field_GetASCII(field, buffer, maxChars, itemNum);
|
||||
# else
|
||||
# else
|
||||
return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
|
||||
# endif
|
||||
# else
|
||||
# endif
|
||||
# else
|
||||
/* (>= to 3.8.0) */
|
||||
/*return ID3Field_GetASCII(field, buffer, maxChars); */
|
||||
return ID3Field_GetASCIIItem(field, buffer, maxChars, itemNum);
|
||||
# endif
|
||||
# else
|
||||
# endif
|
||||
# else
|
||||
/* Not tested (< 3.x.x) */
|
||||
return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
@ -161,7 +164,7 @@ static const char *local__genre_to_string(unsigned genre_code)
|
||||
* Returns true on success, else false.
|
||||
* If a tag entry exists (ex: title), we allocate memory, else value stays to NULL
|
||||
*/
|
||||
static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__Id3v2_Tag *tag)
|
||||
{
|
||||
FILE *file;
|
||||
ID3Tag *id3_tag = 0; /* Tag defined by id3lib */
|
||||
@ -368,8 +371,22 @@ static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__CanonicalTag
|
||||
}
|
||||
#endif /* ifdef FLAC__HAS_ID3LIB */
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__Id3v2_Tag *tag)
|
||||
{
|
||||
FLAC__ASSERT(0 != tag);
|
||||
if(
|
||||
0 != tag->title ||
|
||||
0 != tag->composer ||
|
||||
0 != tag->performer ||
|
||||
0 != tag->album ||
|
||||
0 != tag->year_recorded ||
|
||||
0 != tag->year_performed ||
|
||||
0 != tag->track_number ||
|
||||
0 != tag->tracks_in_album ||
|
||||
0 != tag->genre ||
|
||||
0 != tag->comment
|
||||
)
|
||||
return false;
|
||||
#ifdef FLAC__HAS_ID3LIB
|
||||
return local__get_tag(filename, tag);
|
||||
#else
|
||||
@ -377,3 +394,29 @@ FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__Canonic
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FLAC_plugin__id3v2_tag_clear(FLAC_Plugin__Id3v2_Tag *tag)
|
||||
{
|
||||
FLAC__ASSERT(0 != tag);
|
||||
if(0 != tag->title)
|
||||
free(tag->title);
|
||||
if(0 != tag->composer)
|
||||
free(tag->composer);
|
||||
if(0 != tag->performer)
|
||||
free(tag->performer);
|
||||
if(0 != tag->album)
|
||||
free(tag->album);
|
||||
if(0 != tag->year_recorded)
|
||||
free(tag->year_recorded);
|
||||
if(0 != tag->year_performed)
|
||||
free(tag->year_performed);
|
||||
if(0 != tag->track_number)
|
||||
free(tag->track_number);
|
||||
if(0 != tag->tracks_in_album)
|
||||
free(tag->tracks_in_album);
|
||||
if(0 != tag->genre)
|
||||
free(tag->genre);
|
||||
if(0 != tag->comment)
|
||||
free(tag->comment);
|
||||
memset(tag, 0, sizeof(*tag));
|
||||
}
|
||||
|
@ -19,8 +19,39 @@
|
||||
#ifndef FLAC__PLUGIN_COMMON__ID3V2_H
|
||||
#define FLAC__PLUGIN_COMMON__ID3V2_H
|
||||
|
||||
#include "canonical_tag.h"
|
||||
#include "FLAC/ordinals.h"
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
/*
|
||||
* This is a simple structure that holds pointers to field values (in ASCII)
|
||||
* for fields we care about.
|
||||
*/
|
||||
typedef struct {
|
||||
char *title;
|
||||
char *composer;
|
||||
char *performer;
|
||||
char *album;
|
||||
char *year_recorded;
|
||||
char *year_performed;
|
||||
char *track_number;
|
||||
char *tracks_in_album;
|
||||
char *genre;
|
||||
char *comment;
|
||||
} FLAC_Plugin__Id3v2_Tag;
|
||||
|
||||
/* Fills up an existing FLAC_Plugin__Id3v2_Tag. All pointers must be NULL on
|
||||
* entry or the function will return false. For any field for which there is
|
||||
* no corresponding ID3 frame, it's pointer will be NULL.
|
||||
*
|
||||
* If loading fails, all pointers will be cleared and the function will return
|
||||
* false.
|
||||
*
|
||||
* If the function returns true, be sure to call FLAC_plugin__id3v2_tag_clear()
|
||||
* when you are done with 'tag'.
|
||||
*/
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__Id3v2_Tag *tag);
|
||||
|
||||
/* free()s any non-NULL pointers in 'tag'. Does NOT free(tag).
|
||||
*/
|
||||
void FLAC_plugin__id3v2_tag_clear(FLAC_Plugin__Id3v2_Tag *tag);
|
||||
|
||||
#endif
|
||||
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
||||
# PROP Intermediate_Dir "Release_static"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /Ox /Og /Oi /Os /Op /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /WX /GX /Ox /Og /Oi /Os /Op /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
@ -1,180 +1,110 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
static int local__vcentry_matches(const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry *entry)
|
||||
{
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#define FLAC__STRNCASECMP strnicmp
|
||||
#else
|
||||
#define FLAC__STRNCASECMP strncasecmp
|
||||
#endif
|
||||
const FLAC__byte *eq = memchr(entry->entry, '=', entry->length);
|
||||
const unsigned field_name_length = strlen(field_name);
|
||||
return (0 != eq && (unsigned)(eq-entry->entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry->entry, field_name_length));
|
||||
}
|
||||
|
||||
static void local__vcentry_parse_value(const FLAC__StreamMetadata_VorbisComment_Entry *entry, char **dest)
|
||||
{
|
||||
const FLAC__byte *eq = memchr(entry->entry, '=', entry->length);
|
||||
|
||||
if(0 == eq)
|
||||
return;
|
||||
else {
|
||||
const unsigned value_length = entry->length - (unsigned)((++eq) - entry->entry);
|
||||
|
||||
*dest = malloc(value_length + 1);
|
||||
if(0 != *dest) {
|
||||
memcpy(*dest, eq, value_length);
|
||||
(*dest)[value_length] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void local__vc_change_field(FLAC__StreamMetadata *block, const char *name, const char *value)
|
||||
{
|
||||
int i, l;
|
||||
char *s;
|
||||
|
||||
/* find last */
|
||||
for (l = -1; (i = FLAC__metadata_object_vorbiscomment_find_entry_from(block, l + 1, name)) != -1; l = i)
|
||||
;
|
||||
|
||||
if(!value || !strlen(value)) {
|
||||
if (l != -1)
|
||||
FLAC__metadata_object_vorbiscomment_delete_comment(block, l);
|
||||
return;
|
||||
}
|
||||
|
||||
s = malloc(strlen(name) + strlen(value) + 2);
|
||||
if(s) {
|
||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
|
||||
sprintf(s, "%s=%s", name, value);
|
||||
|
||||
entry.length = strlen(s);
|
||||
entry.entry = (FLAC__byte *)s;
|
||||
|
||||
if(l == -1)
|
||||
FLAC__metadata_object_vorbiscomment_insert_comment(block, block->data.vorbis_comment.num_comments, entry, /*copy=*/true);
|
||||
else
|
||||
FLAC__metadata_object_vorbiscomment_set_comment(block, l, entry, /*copy=*/true);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
if(0 != iterator) {
|
||||
if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
|
||||
FLAC__bool got_vorbis_comments = false;
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||
FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
if(0 != block) {
|
||||
unsigned i;
|
||||
const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
|
||||
for(i = 0; i < vc->num_comments; i++) {
|
||||
if(local__vcentry_matches("artist", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->composer);
|
||||
else if(local__vcentry_matches("performer", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->performer);
|
||||
else if(local__vcentry_matches("album", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->album);
|
||||
else if(local__vcentry_matches("title", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->title);
|
||||
else if(local__vcentry_matches("tracknumber", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->track_number);
|
||||
else if(local__vcentry_matches("genre", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->genre);
|
||||
else if(local__vcentry_matches("description", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->comment);
|
||||
else if(local__vcentry_matches("date", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->year_recorded);
|
||||
}
|
||||
FLAC__metadata_object_delete(block);
|
||||
got_vorbis_comments = true;
|
||||
}
|
||||
}
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
}
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__bool FLAC_plugin__vorbiscomment_set(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC__bool got_vorbis_comments = false;
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
FLAC__StreamMetadata *block;
|
||||
|
||||
if(!iterator || !FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/false, /*preserve_file_stats=*/true))
|
||||
return false;
|
||||
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
got_vorbis_comments = true;
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
|
||||
if(!got_vorbis_comments) {
|
||||
/* create a new block */
|
||||
block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
|
||||
if(!block) {
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
|
||||
local__vc_change_field(block, "ARTIST", tag->composer);
|
||||
local__vc_change_field(block, "PERFORMER", tag->performer);
|
||||
local__vc_change_field(block, "ALBUM", tag->album);
|
||||
local__vc_change_field(block, "TITLE", tag->title);
|
||||
local__vc_change_field(block, "TRACKNUMBER", tag->track_number);
|
||||
local__vc_change_field(block, "GENRE", tag->genre);
|
||||
local__vc_change_field(block, "DESCRIPTION", tag->comment);
|
||||
local__vc_change_field(block, "DATE", tag->year_recorded);
|
||||
|
||||
if(!got_vorbis_comments) {
|
||||
if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, block, /*use_padding=*/true)) {
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!FLAC__metadata_simple_iterator_set_block(iterator, block, /*use_padding=*/true)) {
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return true;
|
||||
}
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
|
||||
static void local__add_vcentry(FLAC_Plugin__CanonicalTag *tag, FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *sep)
|
||||
{
|
||||
FLAC__byte *value = memchr(entry->entry, '=', entry->length);
|
||||
int len;
|
||||
if (!value) return;
|
||||
len = value - entry->entry;
|
||||
value++;
|
||||
FLAC_plugin__canonical_add_utf8(tag, entry->entry, value, len, entry->length-len-1, sep);
|
||||
}
|
||||
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep)
|
||||
{
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
if(0 != iterator) {
|
||||
if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
|
||||
FLAC__bool got_vorbis_comments = false;
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||
FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
if(0 != block) {
|
||||
unsigned i;
|
||||
const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
|
||||
|
||||
for(i = 0; i < vc->num_comments; i++)
|
||||
local__add_vcentry(tag, vc->comments+i, sep);
|
||||
|
||||
FLAC__metadata_object_delete(block);
|
||||
got_vorbis_comments = true;
|
||||
}
|
||||
}
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
}
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__bool FLAC_plugin__vorbiscomment_set(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC__bool got_vorbis_comments = false, result;
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
FLAC__StreamMetadata *block;
|
||||
FLAC__tag_iterator it;
|
||||
unsigned position = 0;
|
||||
|
||||
if (!iterator || !FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/false, /*preserve_file_stats=*/true))
|
||||
return false;
|
||||
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
got_vorbis_comments = true;
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
|
||||
if(!got_vorbis_comments) {
|
||||
/* create a new block */
|
||||
block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
|
||||
if(!block) {
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
|
||||
FLAC__metadata_object_vorbiscomment_resize_comments(block, FLAC_plugin__canonical_get_count(tag));
|
||||
|
||||
for (it=FLAC_plugin__canonical_first(tag); it; it=FLAC_plugin__canonical_next(it))
|
||||
{
|
||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
/* replace entry */
|
||||
entry.entry = FLAC_plugin__canonical_get_formatted(it);
|
||||
entry.length = strlen(entry.entry);
|
||||
FLAC__metadata_object_vorbiscomment_set_comment(block, position++, entry, /*copy=*/false);
|
||||
}
|
||||
|
||||
if (!got_vorbis_comments)
|
||||
result = FLAC__metadata_simple_iterator_insert_block_after(iterator, block, /*use_padding=*/true);
|
||||
else
|
||||
result = FLAC__metadata_simple_iterator_set_block(iterator, block, /*use_padding=*/true);
|
||||
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return result;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "canonical_tag.h"
|
||||
#include "FLAC/ordinals.h"
|
||||
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep);
|
||||
FLAC__bool FLAC_plugin__vorbiscomment_set(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,21 @@
|
||||
/* in_flac - Winamp2 FLAC input plugin
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <stdio.h>
|
||||
@ -7,10 +25,11 @@
|
||||
|
||||
|
||||
static char buffer[256];
|
||||
static char ini_name[MAX_PATH];
|
||||
|
||||
//
|
||||
// Read/write config
|
||||
//
|
||||
/*
|
||||
* Read/write config
|
||||
*/
|
||||
|
||||
#define RI(x, def) (x = GetPrivateProfileInt("FLAC", #x, def, ini_name))
|
||||
#define WI(x) WritePrivateProfileString("FLAC", #x, itoa(x, buffer, 10), ini_name)
|
||||
@ -18,38 +37,65 @@ static char buffer[256];
|
||||
#define WS(x) WritePrivateProfileString("FLAC", #x, x, ini_name)
|
||||
|
||||
static const char default_format[] = "[%artist% - ]$if2(%title%,%filename%)";
|
||||
static const char default_sep[] = ", ";
|
||||
|
||||
void InitConfig()
|
||||
{
|
||||
char *p;
|
||||
|
||||
GetModuleFileName(NULL, ini_name, sizeof(ini_name));
|
||||
p = strrchr(ini_name, '.');
|
||||
if (!p) p = ini_name + strlen(ini_name);
|
||||
strcpy(p, ".ini");
|
||||
|
||||
flac_cfg.title.tag_format_w = NULL;
|
||||
}
|
||||
|
||||
void ReadConfig()
|
||||
{
|
||||
RS(flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format), default_format);
|
||||
RS(flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format), default_format);
|
||||
if (flac_cfg.title.tag_format_w)
|
||||
free(flac_cfg.title.tag_format_w);
|
||||
flac_cfg.title.tag_format_w = FLAC_plugin__convert_ansi_to_wide(flac_cfg.title.tag_format);
|
||||
/* @@@ FIXME: trailing spaces */
|
||||
RS(flac_cfg.title.sep, sizeof(flac_cfg.title.sep), default_sep);
|
||||
RI(flac_cfg.title.read_v1, 1);
|
||||
RI(flac_cfg.tag.reserve_space, 1);
|
||||
|
||||
RI(flac_cfg.output.replaygain.enable, 1);
|
||||
RI(flac_cfg.output.replaygain.album_mode, 0);
|
||||
RI(flac_cfg.output.replaygain.hard_limit, 0);
|
||||
RI(flac_cfg.output.replaygain.preamp, 0);
|
||||
RI(flac_cfg.output.resolution.normal.dither_24_to_16, 0);
|
||||
RI(flac_cfg.output.resolution.replaygain.dither, 0);
|
||||
RI(flac_cfg.output.resolution.replaygain.noise_shaping, 1);
|
||||
RI(flac_cfg.output.resolution.replaygain.bps_out, 16);
|
||||
RI(flac_cfg.display.show_bps, 1);
|
||||
RI(flac_cfg.output.misk.stop_err, 0);
|
||||
RI(flac_cfg.output.replaygain.enable, 1);
|
||||
RI(flac_cfg.output.replaygain.album_mode, 0);
|
||||
RI(flac_cfg.output.replaygain.hard_limit, 0);
|
||||
RI(flac_cfg.output.replaygain.preamp, 0);
|
||||
RI(flac_cfg.output.resolution.normal.dither_24_to_16, 0);
|
||||
RI(flac_cfg.output.resolution.replaygain.dither, 0);
|
||||
RI(flac_cfg.output.resolution.replaygain.noise_shaping, 1);
|
||||
RI(flac_cfg.output.resolution.replaygain.bps_out, 16);
|
||||
}
|
||||
|
||||
void WriteConfig()
|
||||
{
|
||||
WS(flac_cfg.title.tag_format);
|
||||
WS(flac_cfg.title.tag_format);
|
||||
WI(flac_cfg.title.read_v1);
|
||||
WI(flac_cfg.tag.reserve_space);
|
||||
WS(flac_cfg.title.sep);
|
||||
|
||||
WI(flac_cfg.output.replaygain.enable);
|
||||
WI(flac_cfg.output.replaygain.album_mode);
|
||||
WI(flac_cfg.output.replaygain.hard_limit);
|
||||
WI(flac_cfg.output.replaygain.preamp);
|
||||
WI(flac_cfg.output.resolution.normal.dither_24_to_16);
|
||||
WI(flac_cfg.output.resolution.replaygain.dither);
|
||||
WI(flac_cfg.output.resolution.replaygain.noise_shaping);
|
||||
WI(flac_cfg.output.resolution.replaygain.bps_out);
|
||||
WI(flac_cfg.display.show_bps);
|
||||
WI(flac_cfg.output.misk.stop_err);
|
||||
WI(flac_cfg.output.replaygain.enable);
|
||||
WI(flac_cfg.output.replaygain.album_mode);
|
||||
WI(flac_cfg.output.replaygain.hard_limit);
|
||||
WI(flac_cfg.output.replaygain.preamp);
|
||||
WI(flac_cfg.output.resolution.normal.dither_24_to_16);
|
||||
WI(flac_cfg.output.resolution.replaygain.dither);
|
||||
WI(flac_cfg.output.resolution.replaygain.noise_shaping);
|
||||
WI(flac_cfg.output.resolution.replaygain.bps_out);
|
||||
}
|
||||
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
/*
|
||||
* Dialog
|
||||
*/
|
||||
|
||||
#define PREAMP_RANGE 24
|
||||
|
||||
@ -59,284 +105,308 @@ void WriteConfig()
|
||||
#define GetPos(x) SendDlgItemMessage(hwnd, x, TBM_GETPOS, 0, 0)
|
||||
#define Enable(x,y) EnableWindow(GetDlgItem(hwnd, x), y)
|
||||
|
||||
|
||||
static INT_PTR CALLBACK GeneralProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
// init
|
||||
case WM_INITDIALOG:
|
||||
SetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format);
|
||||
return TRUE;
|
||||
// commands
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
// ok
|
||||
case IDOK:
|
||||
GetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format));
|
||||
break;
|
||||
// reset
|
||||
case IDC_RESET:
|
||||
SetDlgItemText(hwnd, IDC_TITLE, default_format);
|
||||
break;
|
||||
// help
|
||||
case IDC_TAGZ_HELP:
|
||||
MessageBox(hwnd, tagz_manual, "Help", 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (msg)
|
||||
{
|
||||
/* init */
|
||||
case WM_INITDIALOG:
|
||||
SendDlgItemMessage(hwnd, IDC_TITLE, EM_LIMITTEXT, 255, 0);
|
||||
SendDlgItemMessage(hwnd, IDC_SEP, EM_LIMITTEXT, 15, 0);
|
||||
|
||||
return 0;
|
||||
SetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format);
|
||||
SetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep);
|
||||
Check(IDC_ID3V1, flac_cfg.title.read_v1);
|
||||
/*! Check(IDC_RESERVE, flac_cfg.tag.reserve_space); */
|
||||
Check(IDC_BPS, flac_cfg.display.show_bps);
|
||||
Check(IDC_ERRORS, flac_cfg.output.misk.stop_err);
|
||||
return TRUE;
|
||||
/* commands */
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
/* ok */
|
||||
case IDOK:
|
||||
GetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format));
|
||||
if (flac_cfg.title.tag_format_w)
|
||||
free(flac_cfg.title.tag_format_w);
|
||||
GetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep, sizeof(flac_cfg.title.sep));
|
||||
flac_cfg.title.tag_format_w = FLAC_plugin__convert_ansi_to_wide(flac_cfg.title.tag_format);
|
||||
|
||||
flac_cfg.title.read_v1 = GetCheck(IDC_ID3V1);
|
||||
/*! flac_cfg.tag.reserve_space = GetCheck(IDC_RESERVE); */
|
||||
flac_cfg.display.show_bps = GetCheck(IDC_BPS);
|
||||
flac_cfg.output.misk.stop_err = GetCheck(IDC_ERRORS);
|
||||
break;
|
||||
/* reset */
|
||||
case IDC_RESET:
|
||||
Check(IDC_ID3V1, 1);
|
||||
Check(IDC_RESERVE, 1);
|
||||
Check(IDC_BPS, 1);
|
||||
Check(IDC_ERRORS, 0);
|
||||
/* fall throught */
|
||||
/* default */
|
||||
case IDC_TAGZ_DEFAULT:
|
||||
SetDlgItemText(hwnd, IDC_TITLE, default_format);
|
||||
break;
|
||||
/* help */
|
||||
case IDC_TAGZ_HELP:
|
||||
MessageBox(hwnd, tagz_manual, "Help", 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void UpdatePreamp(HWND hwnd, HWND hamp)
|
||||
{
|
||||
int pos = SendMessage(hamp, TBM_GETPOS, 0, 0) - PREAMP_RANGE;
|
||||
sprintf(buffer, "%d dB", pos);
|
||||
SetDlgItemText(hwnd, IDC_PA, buffer);
|
||||
int pos = SendMessage(hamp, TBM_GETPOS, 0, 0) - PREAMP_RANGE;
|
||||
sprintf(buffer, "%d dB", pos);
|
||||
SetDlgItemText(hwnd, IDC_PA, buffer);
|
||||
}
|
||||
|
||||
static void UpdateRG(HWND hwnd)
|
||||
{
|
||||
int on = GetCheck(IDC_ENABLE);
|
||||
Enable(IDC_ALBUM, on);
|
||||
Enable(IDC_LIMITER, on);
|
||||
Enable(IDC_PREAMP, on);
|
||||
Enable(IDC_PA, on);
|
||||
int on = GetCheck(IDC_ENABLE);
|
||||
Enable(IDC_ALBUM, on);
|
||||
Enable(IDC_LIMITER, on);
|
||||
Enable(IDC_PREAMP, on);
|
||||
Enable(IDC_PA, on);
|
||||
}
|
||||
|
||||
static void UpdateDither(HWND hwnd)
|
||||
{
|
||||
int on = GetCheck(IDC_DITHERRG);
|
||||
Enable(IDC_SHAPE, on);
|
||||
int on = GetCheck(IDC_DITHERRG);
|
||||
Enable(IDC_SHAPE, on);
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK OutputProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
// init
|
||||
case WM_INITDIALOG:
|
||||
Check(IDC_ENABLE, flac_cfg.output.replaygain.enable);
|
||||
Check(IDC_ALBUM, flac_cfg.output.replaygain.album_mode);
|
||||
Check(IDC_LIMITER, flac_cfg.output.replaygain.hard_limit);
|
||||
Check(IDC_DITHER, flac_cfg.output.resolution.normal.dither_24_to_16);
|
||||
Check(IDC_DITHERRG, flac_cfg.output.resolution.replaygain.dither);
|
||||
// prepare preamp slider
|
||||
{
|
||||
HWND hamp = GetDlgItem(hwnd, IDC_PREAMP);
|
||||
SendMessage(hamp, TBM_SETRANGE, 1, MAKELONG(0, PREAMP_RANGE*2));
|
||||
SendMessage(hamp, TBM_SETPOS, 1, flac_cfg.output.replaygain.preamp+PREAMP_RANGE);
|
||||
UpdatePreamp(hwnd, hamp);
|
||||
}
|
||||
// fill comboboxes
|
||||
{
|
||||
HWND hlist = GetDlgItem(hwnd, IDC_TO);
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"16 bps");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"24 bps");
|
||||
SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.bps_out/8 - 2, 0);
|
||||
|
||||
hlist = GetDlgItem(hwnd, IDC_SHAPE);
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"None");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Low");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Medium");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"High");
|
||||
SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.noise_shaping, 0);
|
||||
}
|
||||
UpdateRG(hwnd);
|
||||
UpdateDither(hwnd);
|
||||
return TRUE;
|
||||
// commands
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
// ok
|
||||
case IDOK:
|
||||
flac_cfg.output.replaygain.enable = GetCheck(IDC_ENABLE);
|
||||
flac_cfg.output.replaygain.album_mode = GetCheck(IDC_ALBUM);
|
||||
flac_cfg.output.replaygain.hard_limit = GetCheck(IDC_LIMITER);
|
||||
flac_cfg.output.replaygain.preamp = GetPos(IDC_PREAMP) - PREAMP_RANGE;
|
||||
flac_cfg.output.resolution.normal.dither_24_to_16 = GetCheck(IDC_DITHER);
|
||||
flac_cfg.output.resolution.replaygain.dither = GetCheck(IDC_DITHERRG);
|
||||
flac_cfg.output.resolution.replaygain.noise_shaping = GetSel(IDC_SHAPE);
|
||||
flac_cfg.output.resolution.replaygain.bps_out = (GetSel(IDC_TO)+2)*8;
|
||||
break;
|
||||
// reset
|
||||
case IDC_RESET:
|
||||
Check(IDC_ENABLE, 1);
|
||||
Check(IDC_ALBUM, 0);
|
||||
Check(IDC_LIMITER, 0);
|
||||
Check(IDC_DITHER, 0);
|
||||
Check(IDC_DITHERRG, 0);
|
||||
switch (msg)
|
||||
{
|
||||
/* init */
|
||||
case WM_INITDIALOG:
|
||||
Check(IDC_ENABLE, flac_cfg.output.replaygain.enable);
|
||||
Check(IDC_ALBUM, flac_cfg.output.replaygain.album_mode);
|
||||
Check(IDC_LIMITER, flac_cfg.output.replaygain.hard_limit);
|
||||
Check(IDC_DITHER, flac_cfg.output.resolution.normal.dither_24_to_16);
|
||||
Check(IDC_DITHERRG, flac_cfg.output.resolution.replaygain.dither);
|
||||
/* prepare preamp slider */
|
||||
{
|
||||
HWND hamp = GetDlgItem(hwnd, IDC_PREAMP);
|
||||
SendMessage(hamp, TBM_SETRANGE, 1, MAKELONG(0, PREAMP_RANGE*2));
|
||||
SendMessage(hamp, TBM_SETPOS, 1, flac_cfg.output.replaygain.preamp+PREAMP_RANGE);
|
||||
UpdatePreamp(hwnd, hamp);
|
||||
}
|
||||
/* fill comboboxes */
|
||||
{
|
||||
HWND hlist = GetDlgItem(hwnd, IDC_TO);
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"16 bps");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"24 bps");
|
||||
SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.bps_out/8 - 2, 0);
|
||||
|
||||
SendDlgItemMessage(hwnd, IDC_PREAMP, TBM_SETPOS, 1, PREAMP_RANGE);
|
||||
SendDlgItemMessage(hwnd, IDC_TO, CB_SETCURSEL, 0, 0);
|
||||
SendDlgItemMessage(hwnd, IDC_SHAPE, CB_SETCURSEL, 1, 0);
|
||||
hlist = GetDlgItem(hwnd, IDC_SHAPE);
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"None");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Low");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Medium");
|
||||
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"High");
|
||||
SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.noise_shaping, 0);
|
||||
}
|
||||
UpdateRG(hwnd);
|
||||
UpdateDither(hwnd);
|
||||
return TRUE;
|
||||
/* commands */
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
/* ok */
|
||||
case IDOK:
|
||||
flac_cfg.output.replaygain.enable = GetCheck(IDC_ENABLE);
|
||||
flac_cfg.output.replaygain.album_mode = GetCheck(IDC_ALBUM);
|
||||
flac_cfg.output.replaygain.hard_limit = GetCheck(IDC_LIMITER);
|
||||
flac_cfg.output.replaygain.preamp = GetPos(IDC_PREAMP) - PREAMP_RANGE;
|
||||
flac_cfg.output.resolution.normal.dither_24_to_16 = GetCheck(IDC_DITHER);
|
||||
flac_cfg.output.resolution.replaygain.dither = GetCheck(IDC_DITHERRG);
|
||||
flac_cfg.output.resolution.replaygain.noise_shaping = GetSel(IDC_SHAPE);
|
||||
flac_cfg.output.resolution.replaygain.bps_out = (GetSel(IDC_TO)+2)*8;
|
||||
break;
|
||||
/* reset */
|
||||
case IDC_RESET:
|
||||
Check(IDC_ENABLE, 1);
|
||||
Check(IDC_ALBUM, 0);
|
||||
Check(IDC_LIMITER, 0);
|
||||
Check(IDC_DITHER, 0);
|
||||
Check(IDC_DITHERRG, 0);
|
||||
|
||||
UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP));
|
||||
UpdateRG(hwnd);
|
||||
UpdateDither(hwnd);
|
||||
break;
|
||||
// active check-boxes
|
||||
case IDC_ENABLE:
|
||||
UpdateRG(hwnd);
|
||||
break;
|
||||
case IDC_DITHERRG:
|
||||
UpdateDither(hwnd);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// scroller
|
||||
case WM_HSCROLL:
|
||||
if (GetDlgCtrlID((HWND)lParam)==IDC_PREAMP)
|
||||
UpdatePreamp(hwnd, (HWND)lParam);
|
||||
return 0;
|
||||
}
|
||||
SendDlgItemMessage(hwnd, IDC_PREAMP, TBM_SETPOS, 1, PREAMP_RANGE);
|
||||
SendDlgItemMessage(hwnd, IDC_TO, CB_SETCURSEL, 0, 0);
|
||||
SendDlgItemMessage(hwnd, IDC_SHAPE, CB_SETCURSEL, 1, 0);
|
||||
|
||||
return 0;
|
||||
UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP));
|
||||
UpdateRG(hwnd);
|
||||
UpdateDither(hwnd);
|
||||
break;
|
||||
/* active check-boxes */
|
||||
case IDC_ENABLE:
|
||||
UpdateRG(hwnd);
|
||||
break;
|
||||
case IDC_DITHERRG:
|
||||
UpdateDither(hwnd);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* scroller */
|
||||
case WM_HSCROLL:
|
||||
if (GetDlgCtrlID((HWND)lParam)==IDC_PREAMP)
|
||||
UpdatePreamp(hwnd, (HWND)lParam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NUM_PAGES 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HWND htab;
|
||||
HWND hdlg;
|
||||
RECT r;
|
||||
HWND all[NUM_PAGES];
|
||||
HWND htab;
|
||||
HWND hdlg;
|
||||
RECT r;
|
||||
HWND all[NUM_PAGES];
|
||||
} LOCALDATA;
|
||||
|
||||
static void ScreenToClientRect(HWND hwnd, RECT *rect)
|
||||
{
|
||||
POINT pt = { rect->left, rect->top };
|
||||
ScreenToClient(hwnd, &pt);
|
||||
rect->left = pt.x;
|
||||
rect->top = pt.y;
|
||||
POINT pt = { rect->left, rect->top };
|
||||
ScreenToClient(hwnd, &pt);
|
||||
rect->left = pt.x;
|
||||
rect->top = pt.y;
|
||||
|
||||
pt.x = rect->right;
|
||||
pt.y = rect->bottom;
|
||||
ScreenToClient(hwnd, &pt);
|
||||
rect->right = pt.x;
|
||||
rect->bottom = pt.y;
|
||||
pt.x = rect->right;
|
||||
pt.y = rect->bottom;
|
||||
ScreenToClient(hwnd, &pt);
|
||||
rect->right = pt.x;
|
||||
rect->bottom = pt.y;
|
||||
}
|
||||
|
||||
static void SendCommand(HWND hwnd, int command)
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
SendMessage(data->hdlg, WM_COMMAND, command, 0);
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
SendMessage(data->hdlg, WM_COMMAND, command, 0);
|
||||
}
|
||||
|
||||
static void BroadcastCommand(HWND hwnd, int command)
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
int i;
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
int i;
|
||||
|
||||
for (i=0; i<NUM_PAGES; i++)
|
||||
SendMessage(data->all[i], WM_COMMAND, command, 0);
|
||||
for (i=0; i<NUM_PAGES; i++)
|
||||
SendMessage(data->all[i], WM_COMMAND, command, 0);
|
||||
}
|
||||
|
||||
static void OnSelChange(HWND hwnd)
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
int index = TabCtrl_GetCurSel(data->htab);
|
||||
if (index < 0) return;
|
||||
// hide previous
|
||||
if (data->hdlg)
|
||||
ShowWindow(data->hdlg, SW_HIDE);
|
||||
// display
|
||||
data->hdlg = data->all[index];
|
||||
SetWindowPos(data->hdlg, HWND_TOP, data->r.left, data->r.top, data->r.right-data->r.left, data->r.bottom-data->r.top, SWP_SHOWWINDOW);
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
int index = TabCtrl_GetCurSel(data->htab);
|
||||
if (index < 0) return;
|
||||
/* hide previous */
|
||||
if (data->hdlg)
|
||||
ShowWindow(data->hdlg, SW_HIDE);
|
||||
/* display */
|
||||
data->hdlg = data->all[index];
|
||||
SetWindowPos(data->hdlg, HWND_TOP, data->r.left, data->r.top, data->r.right-data->r.left, data->r.bottom-data->r.top, SWP_SHOWWINDOW);
|
||||
SetFocus(hwnd);
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static activePage = 0;
|
||||
static activePage = 0;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
// init
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
|
||||
HINSTANCE inst = (HINSTANCE)lParam;
|
||||
TCITEM item;
|
||||
switch (msg)
|
||||
{
|
||||
/* init */
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
|
||||
HINSTANCE inst = (HINSTANCE)lParam;
|
||||
TCITEM item;
|
||||
|
||||
// init
|
||||
SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
|
||||
data->htab = GetDlgItem(hwnd, IDC_TABS);
|
||||
data->hdlg = NULL;
|
||||
// add pages
|
||||
item.mask = TCIF_TEXT;
|
||||
data->all[0] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_GENERAL), hwnd, GeneralProc);
|
||||
item.pszText = "General";
|
||||
TabCtrl_InsertItem(data->htab, 0, &item);
|
||||
/* init */
|
||||
SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
|
||||
data->htab = GetDlgItem(hwnd, IDC_TABS);
|
||||
data->hdlg = NULL;
|
||||
/* add pages */
|
||||
item.mask = TCIF_TEXT;
|
||||
data->all[0] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_GENERAL), hwnd, GeneralProc);
|
||||
item.pszText = "General";
|
||||
TabCtrl_InsertItem(data->htab, 0, &item);
|
||||
|
||||
data->all[1] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_OUTPUT), hwnd, OutputProc);
|
||||
item.pszText = "Output";
|
||||
TabCtrl_InsertItem(data->htab, 1, &item);
|
||||
// get rect (after adding pages)
|
||||
GetWindowRect(data->htab, &data->r);
|
||||
ScreenToClientRect(hwnd, &data->r);
|
||||
TabCtrl_AdjustRect(data->htab, 0, &data->r);
|
||||
// simulate item change
|
||||
TabCtrl_SetCurSel(data->htab, activePage);
|
||||
OnSelChange(hwnd);
|
||||
}
|
||||
return TRUE;
|
||||
// destory
|
||||
case WM_DESTROY:
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
int i;
|
||||
data->all[1] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_OUTPUT), hwnd, OutputProc);
|
||||
item.pszText = "Output";
|
||||
TabCtrl_InsertItem(data->htab, 1, &item);
|
||||
/* get rect (after adding pages) */
|
||||
GetWindowRect(data->htab, &data->r);
|
||||
ScreenToClientRect(hwnd, &data->r);
|
||||
TabCtrl_AdjustRect(data->htab, 0, &data->r);
|
||||
/* simulate item change */
|
||||
TabCtrl_SetCurSel(data->htab, activePage);
|
||||
OnSelChange(hwnd);
|
||||
}
|
||||
return TRUE;
|
||||
/* destory */
|
||||
case WM_DESTROY:
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
int i;
|
||||
|
||||
activePage = TabCtrl_GetCurSel(data->htab);
|
||||
activePage = TabCtrl_GetCurSel(data->htab);
|
||||
|
||||
for (i=0; i<NUM_PAGES; i++)
|
||||
DestroyWindow(data->all[i]);
|
||||
for (i=0; i<NUM_PAGES; i++)
|
||||
DestroyWindow(data->all[i]);
|
||||
|
||||
LocalFree(data);
|
||||
}
|
||||
break;
|
||||
// commands
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
// ok/cancel
|
||||
case IDOK:
|
||||
BroadcastCommand(hwnd, IDOK);
|
||||
/* fall through */
|
||||
case IDCANCEL:
|
||||
EndDialog(hwnd, LOWORD(wParam));
|
||||
return TRUE;
|
||||
case IDC_RESET:
|
||||
SendCommand(hwnd, IDC_RESET);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// notification
|
||||
case WM_NOTIFY:
|
||||
if (LOWORD(wParam) == IDC_TABS)
|
||||
{
|
||||
NMHDR *hdr = (NMHDR*)lParam;
|
||||
LocalFree(data);
|
||||
}
|
||||
break;
|
||||
/* commands */
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
/* ok/cancel */
|
||||
case IDOK:
|
||||
BroadcastCommand(hwnd, IDOK);
|
||||
/* fall through */
|
||||
case IDCANCEL:
|
||||
EndDialog(hwnd, LOWORD(wParam));
|
||||
return TRUE;
|
||||
case IDC_RESET:
|
||||
SendCommand(hwnd, IDC_RESET);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* notification */
|
||||
case WM_NOTIFY:
|
||||
if (LOWORD(wParam) == IDC_TABS)
|
||||
{
|
||||
NMHDR *hdr = (NMHDR*)lParam;
|
||||
|
||||
switch (hdr->code)
|
||||
{
|
||||
case TCN_SELCHANGE:
|
||||
OnSelChange(hwnd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (hdr->code)
|
||||
{
|
||||
case TCN_SELCHANGE:
|
||||
OnSelChange(hwnd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int DoConfig(HINSTANCE inst, HWND parent)
|
||||
{
|
||||
return DialogBoxParam(inst, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc, (LONG)inst) == IDOK;
|
||||
return DialogBoxParam(inst, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc, (LONG)inst) == IDOK;
|
||||
}
|
||||
|
@ -1,41 +1,50 @@
|
||||
/* in_flac - Winamp2 FLAC input plugin
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//
|
||||
// common stuff
|
||||
//
|
||||
#include "playback.h"
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
BOOL enable;
|
||||
BOOL album_mode;
|
||||
INT preamp;
|
||||
BOOL hard_limit;
|
||||
} replaygain;
|
||||
struct {
|
||||
struct {
|
||||
BOOL dither_24_to_16;
|
||||
} normal;
|
||||
struct {
|
||||
BOOL dither;
|
||||
INT noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */
|
||||
INT bps_out;
|
||||
} replaygain;
|
||||
} resolution;
|
||||
} output_config_t;
|
||||
/*
|
||||
* common stuff
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
char tag_format[256];
|
||||
char sep[16];
|
||||
WCHAR *tag_format_w;
|
||||
BOOL read_v1;
|
||||
} title;
|
||||
struct {
|
||||
BOOL reserve_space;
|
||||
} tag;
|
||||
struct {
|
||||
FLAC__bool show_bps;
|
||||
} display;
|
||||
output_config_t output;
|
||||
} flac_config_t;
|
||||
|
||||
extern flac_config_t flac_cfg;
|
||||
extern char ini_name[MAX_PATH];
|
||||
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
/*
|
||||
* prototypes
|
||||
*/
|
||||
|
||||
void InitConfig();
|
||||
void ReadConfig();
|
||||
void WriteConfig();
|
||||
int DoConfig(HINSTANCE inst, HWND parent);
|
||||
int DoConfig(HINSTANCE inst, HWND parent);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "in_flac_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /Ox /Og /Oi /Os /Op /Gf /Gy /I "include" /I ".." /I "..\..\include" /D "NDEBUG" /D VERSION=\"1.1.1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /WX /GX /Ox /Og /Oi /Os /Op /Gf /Gy /I "include" /I ".." /I "..\..\include" /D "NDEBUG" /D VERSION=\"1.1.1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TAGZ_UNICODE" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
@ -70,7 +70,8 @@ LINK32=link.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "in_flac_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I ".." /I "..\..\include" /D "_DEBUG" /D "REAL_STDIO" /D VERSION=\"1.1.1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I ".." /I "..\..\include" /D "_DEBUG" /D "REAL_STDIO" /D VERSION=\"1.1.1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TAGZ_UNICODE" /YX /FD /GZ /c
|
||||
# SUBTRACT CPP /WX
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
@ -126,6 +127,14 @@ SOURCE=.\infobox.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\playback.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\playback.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resource.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -1,290 +1,430 @@
|
||||
/* in_flac - Winamp2 FLAC input plugin
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include "FLAC/all.h"
|
||||
#include "plugin_common/all.h"
|
||||
#include "infobox.h"
|
||||
#include "config.h"
|
||||
#include "resource.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
char filename[MAX_PATH];
|
||||
FLAC_Plugin__CanonicalTag tag;
|
||||
} LOCALDATA;
|
||||
|
||||
static char buffer[256];
|
||||
static char buffer[1024];
|
||||
static char *genres = NULL;
|
||||
static int genresSize = 0, genresCount = 0, genresChanged = 0;
|
||||
static DWORD genresSize = 0, genresCount = 0;
|
||||
static BOOL genresChanged = FALSE, isNT;
|
||||
|
||||
static const char infoTitle[] = "FLAC File Info";
|
||||
|
||||
//fixme int64
|
||||
static __inline DWORD FileSize(const char *file)
|
||||
{
|
||||
HANDLE hFile = CreateFile(file, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
DWORD res;
|
||||
/*
|
||||
* Genres
|
||||
*/
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) return 0;
|
||||
res = GetFileSize(hFile, 0);
|
||||
CloseHandle(hFile);
|
||||
return res;
|
||||
}
|
||||
/* TODO: write genres in utf-8 ? */
|
||||
|
||||
static __inline int GetGenresFileName(char *buffer, int size)
|
||||
{
|
||||
char *c;
|
||||
char *c;
|
||||
|
||||
if (!GetModuleFileName(NULL, buffer, size))
|
||||
return 0;
|
||||
c = strrchr(buffer, '\\');
|
||||
if (!c) return 0;
|
||||
strcpy(c+1, "genres.txt");
|
||||
if (!GetModuleFileName(NULL, buffer, size))
|
||||
return 0;
|
||||
c = strrchr(buffer, '\\');
|
||||
if (!c) return 0;
|
||||
strcpy(c+1, "genres.txt");
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void LoadGenres()
|
||||
{
|
||||
HANDLE hFile;
|
||||
DWORD spam;
|
||||
char *c;
|
||||
HANDLE hFile;
|
||||
DWORD spam;
|
||||
char *c;
|
||||
|
||||
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
|
||||
// load file
|
||||
hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return;
|
||||
genresSize = GetFileSize(hFile, 0);
|
||||
if (!genresSize) return;
|
||||
genres = (char*)malloc(genresSize+2);
|
||||
if (!genres) return;
|
||||
if (!ReadFile(hFile, genres, genresSize, &spam, NULL))
|
||||
{
|
||||
free(genres);
|
||||
genres = NULL;
|
||||
return;
|
||||
}
|
||||
genres[genresSize] = 0;
|
||||
genres[genresSize+1] = 0;
|
||||
// replace newlines
|
||||
genresChanged = 0;
|
||||
genresCount = 1;
|
||||
FLAC__ASSERT(0 != genres);
|
||||
|
||||
for (c=genres; *c; c++)
|
||||
{
|
||||
if (*c == 10)
|
||||
{
|
||||
*c = 0;
|
||||
if (*(c+1))
|
||||
genresCount++;
|
||||
else genresSize--;
|
||||
}
|
||||
}
|
||||
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
|
||||
/* load file */
|
||||
hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return;
|
||||
genresSize = GetFileSize(hFile, 0);
|
||||
if (genresSize && (genres = (char*)malloc(genresSize+2)))
|
||||
{
|
||||
if (!ReadFile(hFile, genres, genresSize, &spam, NULL) || spam!=genresSize)
|
||||
{
|
||||
free(genres);
|
||||
genres = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
genres[genresSize] = 0;
|
||||
genres[genresSize+1] = 0;
|
||||
/* replace newlines */
|
||||
genresChanged = FALSE;
|
||||
genresCount = 1;
|
||||
|
||||
CloseHandle(hFile);
|
||||
for (c=genres; *c; c++)
|
||||
{
|
||||
if (*c == 10)
|
||||
{
|
||||
*c = 0;
|
||||
if (*(c+1))
|
||||
genresCount++;
|
||||
else genresSize--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
static void SaveGenres(HWND hlist)
|
||||
{
|
||||
HANDLE hFile;
|
||||
DWORD spam;
|
||||
int i, count, len;
|
||||
HANDLE hFile;
|
||||
DWORD spam;
|
||||
int i, count, len;
|
||||
|
||||
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
|
||||
// write file
|
||||
hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return;
|
||||
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
|
||||
/* write file */
|
||||
hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
count = SendMessage(hlist, CB_GETCOUNT, 0, 0);
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);
|
||||
len = strlen(buffer);
|
||||
if (i != count-1)
|
||||
{
|
||||
buffer[len] = 10;
|
||||
len++;
|
||||
}
|
||||
WriteFile(hFile, buffer, len, &spam, NULL);
|
||||
}
|
||||
count = SendMessage(hlist, CB_GETCOUNT, 0, 0);
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);
|
||||
len = strlen(buffer);
|
||||
if (i != count-1)
|
||||
{
|
||||
buffer[len] = 10;
|
||||
len++;
|
||||
}
|
||||
WriteFile(hFile, buffer, len, &spam, NULL);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
|
||||
#define SetText(x,y) SetDlgItemText(hwnd, x, y)
|
||||
#define GetText(x,y) (GetDlgItemText(hwnd, x, buffer, sizeof(buffer)), y = buffer[0] ? strdup(buffer) : 0)
|
||||
|
||||
static BOOL InitInfobox(HWND hwnd, const char *file)
|
||||
static void AddGenre(HWND hwnd, const char *genre)
|
||||
{
|
||||
LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
|
||||
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
|
||||
|
||||
if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)genre) == CB_ERR)
|
||||
{
|
||||
genresChanged = TRUE;
|
||||
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)genre);
|
||||
}
|
||||
}
|
||||
|
||||
static void InitGenres(HWND hwnd)
|
||||
{
|
||||
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
|
||||
char *c;
|
||||
|
||||
/* set text length limit to 64 chars */
|
||||
SendMessage(hgen, CB_LIMITTEXT, 64, 0);
|
||||
/* try to load genres */
|
||||
if (!genres)
|
||||
LoadGenres(hgen);
|
||||
/* add the to list */
|
||||
if (genres)
|
||||
{
|
||||
SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);
|
||||
|
||||
for (c = genres; *c; c += strlen(c)+1)
|
||||
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);
|
||||
}
|
||||
}
|
||||
|
||||
static void DeinitGenres(HWND hwnd, BOOL final)
|
||||
{
|
||||
if (genresChanged && hwnd)
|
||||
{
|
||||
SaveGenres(GetDlgItem(hwnd, IDC_GENRE));
|
||||
genresChanged = FALSE;
|
||||
final = TRUE;
|
||||
}
|
||||
if (final)
|
||||
{
|
||||
free(genres);
|
||||
genres = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Infobox helpers
|
||||
*/
|
||||
|
||||
#define SetText(x,y) WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, FLAC_plugin__canonical_get(&data->tag, y), -1, buffer, sizeof(buffer), NULL, NULL); \
|
||||
SetDlgItemText(hwnd, x, buffer)
|
||||
|
||||
#define GetText(x,y) GetDlgItemText(hwnd, x, buffer, sizeof(buffer)); \
|
||||
if (*buffer) FLAC_plugin__canonical_set_ansi(&data->tag, y, buffer); \
|
||||
else FLAC_plugin__canonical_remove_all(&data->tag, y)
|
||||
|
||||
#define SetTextW(x,y) SetDlgItemTextW(hwnd, x, FLAC_plugin__canonical_get(&data->tag, y))
|
||||
|
||||
#define GetTextW(x,y) GetDlgItemTextW(hwnd, x, (WCHAR*)buffer, sizeof(buffer)/2); \
|
||||
if (*(WCHAR*)buffer) FLAC_plugin__canonical_set(&data->tag, y, (WCHAR*)buffer); \
|
||||
else FLAC_plugin__canonical_remove_all(&data->tag, y)
|
||||
|
||||
|
||||
static BOOL InitInfoboxInfo(HWND hwnd, const char *file)
|
||||
{
|
||||
LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
|
||||
FLAC__StreamMetadata streaminfo;
|
||||
FLAC_Plugin__CanonicalTag tag;
|
||||
DWORD filesize, length, bps, ratio;
|
||||
DWORD length, bps, ratio, rg;
|
||||
LONGLONG filesize;
|
||||
|
||||
SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
|
||||
// file name
|
||||
strncpy(data->filename, file, sizeof(data->filename));
|
||||
SetDlgItemText(hwnd, IDC_NAME, file);
|
||||
// stream data
|
||||
filesize = FileSize(file);
|
||||
if (!filesize) return FALSE;
|
||||
SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
|
||||
/* file name */
|
||||
strncpy(data->filename, file, sizeof(data->filename));
|
||||
SetDlgItemText(hwnd, IDC_NAME, file);
|
||||
/* stream data and vorbis comment */
|
||||
filesize = FileSize(file);
|
||||
if (!filesize) return FALSE;
|
||||
if (!FLAC__metadata_get_streaminfo(file, &streaminfo))
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
ReadTags(file, &data->tag, false);
|
||||
|
||||
length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
|
||||
bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));
|
||||
ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);
|
||||
length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
|
||||
bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));
|
||||
ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);
|
||||
rg = FLAC_plugin__canonical_get(&data->tag, L"REPLAYGAIN_TRACK_GAIN") ? 1 : 0;
|
||||
rg |= FLAC_plugin__canonical_get(&data->tag, L"REPLAYGAIN_ALBUM_GAIN") ? 2 : 0;
|
||||
|
||||
sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"
|
||||
"File size: %d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n",
|
||||
streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,
|
||||
streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,
|
||||
length/60, length%60, bps, ratio/10, ratio%10);
|
||||
//todo: replaygain
|
||||
sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"
|
||||
"File size: %I64d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n"
|
||||
"ReplayGain: %s\n",
|
||||
streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,
|
||||
streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,
|
||||
length/60, length%60, bps, ratio/10, ratio%10,
|
||||
rg==3 ? "track gain\nReplayGain: album gain" : rg==2 ? "album gain" : rg==1 ? "track gain" : "not present");
|
||||
|
||||
SetDlgItemText(hwnd, IDC_INFO, buffer);
|
||||
// tag
|
||||
FLAC_plugin__canonical_tag_init(&tag);
|
||||
FLAC_plugin__canonical_tag_get_combined(file, &tag);
|
||||
SetDlgItemText(hwnd, IDC_INFO, buffer);
|
||||
/* tag */
|
||||
if (isNT)
|
||||
{
|
||||
SetTextW(IDC_TITLE, L"TITLE");
|
||||
SetTextW(IDC_ARTIST, L"ARTIST");
|
||||
SetTextW(IDC_ALBUM, L"ALBUM");
|
||||
SetTextW(IDC_COMMENT, L"DESCRIPTION");
|
||||
SetTextW(IDC_YEAR, L"DATE");
|
||||
SetTextW(IDC_TRACK, L"TRACKNUMBER");
|
||||
SetTextW(IDC_GENRE, L"GENRE");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetText(IDC_TITLE, L"TITLE");
|
||||
SetText(IDC_ARTIST, L"ARTIST");
|
||||
SetText(IDC_ALBUM, L"ALBUM");
|
||||
SetText(IDC_COMMENT, L"DESCRIPTION");
|
||||
SetText(IDC_YEAR, L"DATE");
|
||||
SetText(IDC_TRACK, L"TRACKNUMBER");
|
||||
SetText(IDC_GENRE, L"GENRE");
|
||||
}
|
||||
|
||||
SetText(IDC_TITLE, tag.title);
|
||||
SetText(IDC_ARTIST, tag.performer ? tag.performer : tag.composer);
|
||||
SetText(IDC_ALBUM, tag.album);
|
||||
SetText(IDC_COMMENT, tag.comment);
|
||||
SetText(IDC_YEAR, tag.year_recorded ? tag.year_recorded : tag.year_performed);
|
||||
SetText(IDC_TRACK, tag.track_number);
|
||||
SetText(IDC_GENRE, tag.genre);
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&tag);
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void __inline SetTag(HWND hwnd, const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
strcpy(buffer, infoTitle);
|
||||
strcpy(buffer, infoTitle);
|
||||
|
||||
if (FLAC_plugin__vorbiscomment_set(filename, tag))
|
||||
strcat(buffer, " [Updated]");
|
||||
else strcat(buffer, " [Failed]");
|
||||
strcat(buffer, " [Updated]");
|
||||
else strcat(buffer, " [Failed]");
|
||||
|
||||
SetWindowText(hwnd, buffer);
|
||||
SetWindowText(hwnd, buffer);
|
||||
}
|
||||
|
||||
static void UpdateTag(HWND hwnd)
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
FLAC_Plugin__CanonicalTag tag;
|
||||
FLAC_plugin__canonical_tag_init(&tag);
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
|
||||
// get fields
|
||||
GetText(IDC_TITLE, tag.title);
|
||||
GetText(IDC_ARTIST, tag.composer);
|
||||
GetText(IDC_ALBUM, tag.album);
|
||||
GetText(IDC_COMMENT, tag.comment);
|
||||
GetText(IDC_YEAR, tag.year_recorded);
|
||||
GetText(IDC_TRACK, tag.track_number);
|
||||
GetText(IDC_GENRE, tag.genre);
|
||||
/* get fields */
|
||||
if (isNT)
|
||||
{
|
||||
GetTextW(IDC_TITLE, L"TITLE");
|
||||
GetTextW(IDC_ARTIST, L"ARTIST");
|
||||
GetTextW(IDC_ALBUM, L"ALBUM");
|
||||
GetTextW(IDC_COMMENT, L"DESCRIPTION");
|
||||
GetTextW(IDC_YEAR, L"DATE");
|
||||
GetTextW(IDC_TRACK, L"TRACKNUMBER");
|
||||
GetTextW(IDC_GENRE, L"GENRE");
|
||||
|
||||
// update genres list
|
||||
if (tag.genre)
|
||||
{
|
||||
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
|
||||
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, FLAC_plugin__canonical_get(&data->tag, L"GENRE"), -1, buffer, sizeof(buffer), NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetText(IDC_TITLE, L"TITLE");
|
||||
GetText(IDC_ARTIST, L"ARTIST");
|
||||
GetText(IDC_ALBUM, L"ALBUM");
|
||||
GetText(IDC_COMMENT, L"DESCRIPTION");
|
||||
GetText(IDC_YEAR, L"DATE");
|
||||
GetText(IDC_TRACK, L"TRACKNUMBER");
|
||||
GetText(IDC_GENRE, L"GENRE");
|
||||
}
|
||||
|
||||
if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)tag.genre) == CB_ERR)
|
||||
{
|
||||
genresChanged = 1;
|
||||
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)tag.genre);
|
||||
}
|
||||
}
|
||||
/* update genres list (buffer should contain genre) */
|
||||
if (buffer[0]) AddGenre(hwnd, buffer);
|
||||
|
||||
// write tag
|
||||
SetTag(hwnd, data->filename, &tag);
|
||||
FLAC_plugin__canonical_tag_clear(&tag);
|
||||
/* write tag */
|
||||
SetTag(hwnd, data->filename, &data->tag);
|
||||
}
|
||||
|
||||
static void RemoveTag(HWND hwnd)
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
FLAC_Plugin__CanonicalTag tag;
|
||||
FLAC_plugin__canonical_tag_init(&tag);
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
FLAC_plugin__canonical_tag_clear(&data->tag);
|
||||
|
||||
SetText(IDC_TITLE, "");
|
||||
SetText(IDC_ARTIST, "");
|
||||
SetText(IDC_ALBUM, "");
|
||||
SetText(IDC_COMMENT, "");
|
||||
SetText(IDC_YEAR, "");
|
||||
SetText(IDC_TRACK, "");
|
||||
SetText(IDC_GENRE, "");
|
||||
SetDlgItemText(hwnd, IDC_TITLE, "");
|
||||
SetDlgItemText(hwnd, IDC_ARTIST, "");
|
||||
SetDlgItemText(hwnd, IDC_ALBUM, "");
|
||||
SetDlgItemText(hwnd, IDC_COMMENT, "");
|
||||
SetDlgItemText(hwnd, IDC_YEAR, "");
|
||||
SetDlgItemText(hwnd, IDC_TRACK, "");
|
||||
SetDlgItemText(hwnd, IDC_GENRE, "");
|
||||
|
||||
SetTag(hwnd, data->filename, &tag);
|
||||
SetTag(hwnd, data->filename, &data->tag);
|
||||
}
|
||||
|
||||
|
||||
static INT_PTR CALLBACK InfoProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
// init
|
||||
case WM_INITDIALOG:
|
||||
SetWindowText(hwnd, infoTitle);
|
||||
// init genres list
|
||||
{
|
||||
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
|
||||
char *c;
|
||||
switch (msg)
|
||||
{
|
||||
/* init */
|
||||
case WM_INITDIALOG:
|
||||
SetWindowText(hwnd, infoTitle);
|
||||
InitGenres(hwnd);
|
||||
/* init fields */
|
||||
if (!InitInfoboxInfo(hwnd, (const char*)lParam))
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
return TRUE;
|
||||
/* destroy */
|
||||
case WM_DESTROY:
|
||||
{
|
||||
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
|
||||
FLAC_plugin__canonical_tag_clear(&data->tag);
|
||||
LocalFree(data);
|
||||
DeinitGenres(hwnd, FALSE);
|
||||
}
|
||||
break;
|
||||
/* commands */
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
/* ok/cancel */
|
||||
case IDOK:
|
||||
case IDCANCEL:
|
||||
EndDialog(hwnd, LOWORD(wParam));
|
||||
return TRUE;
|
||||
/* save */
|
||||
case IDC_UPDATE:
|
||||
UpdateTag(hwnd);
|
||||
break;
|
||||
/* remove */
|
||||
case IDC_REMOVE:
|
||||
RemoveTag(hwnd);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// set text length limit to 64 chars
|
||||
SendMessage(hgen, CB_LIMITTEXT, 64, 0);
|
||||
// try to load genres
|
||||
if (!genres) LoadGenres(hgen);
|
||||
// add the to list
|
||||
if (genres)
|
||||
{
|
||||
SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);
|
||||
|
||||
for (c = genres; *c; c += strlen(c)+1)
|
||||
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);
|
||||
}
|
||||
}
|
||||
// init fields
|
||||
if (!InitInfobox(hwnd, (const char*)lParam))
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
return TRUE;
|
||||
// destroy
|
||||
case WM_DESTROY:
|
||||
if (genresChanged)
|
||||
{
|
||||
SaveGenres(GetDlgItem(hwnd, IDC_GENRE));
|
||||
free(genres);
|
||||
genres = 0;
|
||||
}
|
||||
LocalFree((LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA));
|
||||
break;
|
||||
// commands
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
// ok/cancel
|
||||
case IDOK:
|
||||
case IDCANCEL:
|
||||
EndDialog(hwnd, LOWORD(wParam));
|
||||
return TRUE;
|
||||
// save
|
||||
case IDC_UPDATE:
|
||||
UpdateTag(hwnd);
|
||||
break;
|
||||
// remove
|
||||
case IDC_REMOVE:
|
||||
RemoveTag(hwnd);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
ULONGLONG FileSize(const char *fileName)
|
||||
{
|
||||
LARGE_INTEGER res;
|
||||
HANDLE hFile = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) return 0;
|
||||
res.LowPart = GetFileSize(hFile, &res.HighPart);
|
||||
CloseHandle(hFile);
|
||||
return res.QuadPart;
|
||||
}
|
||||
|
||||
static __inline char *GetFileName(const char *fullname)
|
||||
{
|
||||
const char *c = fullname + strlen(fullname) - 1;
|
||||
|
||||
while (c > fullname)
|
||||
{
|
||||
if (*c=='\\' || *c=='/')
|
||||
{
|
||||
c++;
|
||||
break;
|
||||
}
|
||||
c--;
|
||||
}
|
||||
|
||||
return (char*)c;
|
||||
}
|
||||
|
||||
void ReadTags(const char *fileName, FLAC_Plugin__CanonicalTag *tag, BOOL forDisplay)
|
||||
{
|
||||
FLAC_plugin__canonical_tag_init(tag);
|
||||
FLAC_plugin__vorbiscomment_get(fileName, tag, forDisplay ? flac_cfg.title.sep : NULL);
|
||||
|
||||
if (flac_cfg.title.read_v1)
|
||||
FLAC_plugin__canonical_tag_add_id3v1(fileName, tag);
|
||||
|
||||
/* add file name */
|
||||
if (forDisplay)
|
||||
{
|
||||
char *c;
|
||||
FLAC_plugin__canonical_set_ansi(tag, L"filepath", fileName);
|
||||
|
||||
strcpy(buffer, GetFileName(fileName));
|
||||
if (c = strrchr(buffer, '.')) *c = 0;
|
||||
FLAC_plugin__canonical_set_ansi(tag, L"filename", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Front-end
|
||||
*/
|
||||
|
||||
void InitInfobox()
|
||||
{
|
||||
isNT = !(GetVersion() & 0x80000000);
|
||||
}
|
||||
|
||||
void DeinitInfobox()
|
||||
{
|
||||
DeinitGenres(NULL, true);
|
||||
}
|
||||
|
||||
void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename)
|
||||
{
|
||||
DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);
|
||||
DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);
|
||||
}
|
||||
|
@ -1,5 +1,28 @@
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
/* in_flac - Winamp2 FLAC input plugin
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* prototypes
|
||||
*/
|
||||
|
||||
ULONGLONG FileSize(const char *fileName);
|
||||
void ReadTags(const char *fileName, FLAC_Plugin__CanonicalTag *tag, BOOL forDisplay);
|
||||
|
||||
void InitInfobox();
|
||||
void DeinitInfobox();
|
||||
void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename);
|
||||
|
292
src/plugin_winamp2/playback.c
Normal file
292
src/plugin_winamp2/playback.c
Normal file
@ -0,0 +1,292 @@
|
||||
/* in_flac - Winamp2 FLAC input plugin
|
||||
* Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "playback.h"
|
||||
#include "share/grabbag.h"
|
||||
|
||||
|
||||
static FLAC__int32 reservoir_[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS][FLAC__MAX_BLOCK_SIZE * 2/*for overflow*/];
|
||||
static FLAC__int32 *reservoir__[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS] = { reservoir_[0], reservoir_[1] }; /*@@@ kind of a hard-coded hack */
|
||||
static unsigned wide_samples_in_reservoir_;
|
||||
static output_config_t cfg; /* local copy */
|
||||
|
||||
static unsigned bh_index_last_w, bh_index_last_o, written_time_last;
|
||||
static FLAC__int64 decode_position, decode_position_last;
|
||||
|
||||
/*
|
||||
* callbacks
|
||||
*/
|
||||
|
||||
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
||||
{
|
||||
file_info_struct *file_info = (file_info_struct*)client_data;
|
||||
const unsigned channels = file_info->channels, wide_samples = frame->header.blocksize;
|
||||
unsigned channel;
|
||||
|
||||
(void)decoder;
|
||||
|
||||
if (file_info->abort_flag)
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
|
||||
for (channel = 0; channel < channels; channel++)
|
||||
memcpy(&reservoir_[channel][wide_samples_in_reservoir_], buffer[channel], sizeof(buffer[0][0]) * wide_samples);
|
||||
|
||||
wide_samples_in_reservoir_ += wide_samples;
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
|
||||
{
|
||||
file_info_struct *file_info = (file_info_struct*)client_data;
|
||||
(void)decoder;
|
||||
|
||||
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
|
||||
{
|
||||
FLAC__ASSERT(metadata->data.stream_info.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
|
||||
file_info->total_samples = (unsigned)(metadata->data.stream_info.total_samples&0xfffffffful);
|
||||
file_info->bits_per_sample = metadata->data.stream_info.bits_per_sample;
|
||||
file_info->channels = metadata->data.stream_info.channels;
|
||||
file_info->sample_rate = metadata->data.stream_info.sample_rate;
|
||||
|
||||
if (file_info->bits_per_sample!=8 && file_info->bits_per_sample!=16 && file_info->bits_per_sample!=24)
|
||||
{
|
||||
FLAC_plugin__show_error("This plugin can only handle 8/16/24-bit samples.");
|
||||
file_info->abort_flag = true;
|
||||
return;
|
||||
}
|
||||
file_info->length_in_msec = file_info->total_samples * 10 / (file_info->sample_rate / 100);
|
||||
}
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
{
|
||||
double gain, peak;
|
||||
if (grabbag__replaygain_load_from_vorbiscomment(metadata, cfg.replaygain.album_mode, &gain, &peak))
|
||||
{
|
||||
file_info->has_replaygain = true;
|
||||
file_info->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)cfg.replaygain.preamp, !cfg.replaygain.hard_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
|
||||
{
|
||||
file_info_struct *file_info = (file_info_struct*)client_data;
|
||||
(void)decoder;
|
||||
|
||||
if (cfg.misk.stop_err || status!=FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
|
||||
file_info->abort_flag = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* init/delete
|
||||
*/
|
||||
|
||||
FLAC__bool FLAC_plugin__decoder_init(FLAC__FileDecoder *decoder, const char *filename, FLAC__int64 filesize, file_info_struct *file_info, output_config_t *config)
|
||||
{
|
||||
FLAC__ASSERT(decoder);
|
||||
FLAC_plugin__decoder_finish(decoder);
|
||||
/* init decoder */
|
||||
FLAC__file_decoder_set_md5_checking(decoder, false);
|
||||
FLAC__file_decoder_set_filename(decoder, filename);
|
||||
FLAC__file_decoder_set_metadata_ignore_all(decoder);
|
||||
FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
|
||||
FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback);
|
||||
FLAC__file_decoder_set_write_callback(decoder, write_callback);
|
||||
FLAC__file_decoder_set_error_callback(decoder, error_callback);
|
||||
FLAC__file_decoder_set_client_data(decoder, file_info);
|
||||
|
||||
if (FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK)
|
||||
{
|
||||
FLAC_plugin__show_error("Error while initializing decoder (%s).", FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
|
||||
return false;
|
||||
}
|
||||
/* process */
|
||||
cfg = *config;
|
||||
wide_samples_in_reservoir_ = 0;
|
||||
file_info->is_playing = false;
|
||||
file_info->abort_flag = false;
|
||||
file_info->has_replaygain = false;
|
||||
|
||||
if (!FLAC__file_decoder_process_until_end_of_metadata(decoder))
|
||||
{
|
||||
FLAC_plugin__show_error("Error while processing metadata (%s).", FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
|
||||
return false;
|
||||
}
|
||||
/* check results */
|
||||
if (file_info->abort_flag) return false; /* metadata callback already popped up the error dialog */
|
||||
/* init replaygain */
|
||||
file_info->output_bits_per_sample = file_info->has_replaygain && cfg.replaygain.enable ?
|
||||
cfg.resolution.replaygain.bps_out :
|
||||
cfg.resolution.normal.dither_24_to_16 ? min(file_info->bits_per_sample, 16) : file_info->bits_per_sample;
|
||||
|
||||
if (file_info->has_replaygain && cfg.replaygain.enable && cfg.resolution.replaygain.dither)
|
||||
FLAC__replaygain_synthesis__init_dither_context(&file_info->dither_context, file_info->bits_per_sample, cfg.resolution.replaygain.noise_shaping);
|
||||
/* more inits */
|
||||
file_info->eof = false;
|
||||
file_info->seek_to = -1;
|
||||
file_info->is_playing = true;
|
||||
file_info->average_bps = (unsigned)(filesize / (125.*file_info->total_samples/file_info->sample_rate));
|
||||
|
||||
bh_index_last_w = 0;
|
||||
bh_index_last_o = BITRATE_HIST_SIZE;
|
||||
decode_position = 0;
|
||||
decode_position_last = 0;
|
||||
written_time_last = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FLAC_plugin__decoder_finish(FLAC__FileDecoder *decoder)
|
||||
{
|
||||
if (decoder && FLAC__file_decoder_get_state(decoder)!=FLAC__FILE_DECODER_UNINITIALIZED)
|
||||
FLAC__file_decoder_finish(decoder);
|
||||
}
|
||||
|
||||
void FLAC_plugin__decoder_delete(FLAC__FileDecoder *decoder)
|
||||
{
|
||||
if (decoder)
|
||||
{
|
||||
FLAC_plugin__decoder_finish(decoder);
|
||||
FLAC__file_decoder_delete(decoder);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* decode
|
||||
*/
|
||||
|
||||
int FLAC_plugin__seek(FLAC__FileDecoder *decoder, file_info_struct *file_info)
|
||||
{
|
||||
int pos;
|
||||
const FLAC__uint64 target_sample =
|
||||
(FLAC__uint64)file_info->total_samples*file_info->seek_to / file_info->length_in_msec;
|
||||
|
||||
if (!FLAC__file_decoder_seek_absolute(decoder, target_sample))
|
||||
return -1;
|
||||
|
||||
file_info->seek_to = -1;
|
||||
file_info->eof = false;
|
||||
wide_samples_in_reservoir_ = 0;
|
||||
pos = (int)(target_sample*1000 / file_info->sample_rate);
|
||||
|
||||
bh_index_last_o = bh_index_last_w = (pos/BITRATE_HIST_SEGMENT_MSEC) % BITRATE_HIST_SIZE;
|
||||
if (!FLAC__file_decoder_get_decode_position(decoder, &decode_position))
|
||||
decode_position = 0;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
unsigned FLAC_plugin__decode(FLAC__FileDecoder *decoder, file_info_struct *file_info, char *sample_buffer)
|
||||
{
|
||||
/* fill reservoir */
|
||||
while (wide_samples_in_reservoir_ < SAMPLES_PER_WRITE)
|
||||
{
|
||||
if (FLAC__file_decoder_get_state(decoder) == FLAC__FILE_DECODER_END_OF_FILE)
|
||||
{
|
||||
file_info->eof = true;
|
||||
break;
|
||||
}
|
||||
else if (!FLAC__file_decoder_process_single(decoder))
|
||||
{
|
||||
FLAC_plugin__show_error("Error while processing frame (%s).", FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
|
||||
file_info->eof = true;
|
||||
break;
|
||||
}
|
||||
if (!FLAC__file_decoder_get_decode_position(decoder, &decode_position))
|
||||
decode_position = 0;
|
||||
}
|
||||
/* output samples */
|
||||
if (wide_samples_in_reservoir_ > 0)
|
||||
{
|
||||
const unsigned n = min(wide_samples_in_reservoir_, SAMPLES_PER_WRITE);
|
||||
const unsigned channels = file_info->channels;
|
||||
unsigned i;
|
||||
int bytes;
|
||||
|
||||
if (cfg.replaygain.enable && file_info->has_replaygain)
|
||||
{
|
||||
bytes = FLAC__replaygain_synthesis__apply_gain(
|
||||
sample_buffer,
|
||||
true, /* little_endian_data_out */
|
||||
file_info->output_bits_per_sample == 8, /* unsigned_data_out */
|
||||
reservoir__,
|
||||
n,
|
||||
channels,
|
||||
file_info->bits_per_sample,
|
||||
file_info->output_bits_per_sample,
|
||||
file_info->replay_scale,
|
||||
cfg.replaygain.hard_limit,
|
||||
cfg.resolution.replaygain.dither,
|
||||
&file_info->dither_context
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes = FLAC__plugin_common__pack_pcm_signed_little_endian(
|
||||
sample_buffer,
|
||||
reservoir__,
|
||||
n,
|
||||
channels,
|
||||
file_info->bits_per_sample,
|
||||
file_info->output_bits_per_sample
|
||||
);
|
||||
}
|
||||
|
||||
wide_samples_in_reservoir_ -= n;
|
||||
for (i = 0; i < channels; i++)
|
||||
memmove(&reservoir_[i][0], &reservoir_[i][n], sizeof(reservoir_[0][0]) * wide_samples_in_reservoir_);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
file_info->eof = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int FLAC_plugin__get_rate(unsigned written_time, unsigned output_time, file_info_struct *file_info)
|
||||
{
|
||||
static int bitrate_history_[BITRATE_HIST_SIZE];
|
||||
unsigned bh_index_w = (written_time/BITRATE_HIST_SEGMENT_MSEC) % BITRATE_HIST_SIZE;
|
||||
unsigned bh_index_o = (output_time/BITRATE_HIST_SEGMENT_MSEC) % BITRATE_HIST_SIZE;
|
||||
|
||||
/* written bitrate */
|
||||
if (bh_index_w != bh_index_last_w)
|
||||
{
|
||||
bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE-1)%BITRATE_HIST_SIZE] =
|
||||
decode_position>decode_position_last && written_time > written_time_last ?
|
||||
(unsigned)(8000*(decode_position - decode_position_last)/(written_time - written_time_last)) :
|
||||
file_info->average_bps;
|
||||
|
||||
bh_index_last_w = bh_index_w;
|
||||
written_time_last = written_time;
|
||||
decode_position_last = decode_position;
|
||||
}
|
||||
|
||||
/* output bitrate */
|
||||
if (bh_index_o!=bh_index_last_o && bh_index_o!=bh_index_last_w)
|
||||
{
|
||||
bh_index_last_o = bh_index_o;
|
||||
return bitrate_history_[bh_index_o];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
92
src/plugin_winamp2/playback.h
Normal file
92
src/plugin_winamp2/playback.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* in_flac - Winamp2 FLAC input plugin
|
||||
* Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "FLAC/all.h"
|
||||
#include "share/replaygain_synthesis.h"
|
||||
#include "plugin_common/all.h"
|
||||
|
||||
/*
|
||||
* constants
|
||||
*/
|
||||
|
||||
#define SAMPLES_PER_WRITE 576
|
||||
|
||||
#define BITRATE_HIST_SEGMENT_MSEC 500
|
||||
#define BITRATE_HIST_SIZE 64
|
||||
|
||||
/*
|
||||
* common structures
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
volatile FLAC__bool is_playing;
|
||||
volatile FLAC__bool abort_flag;
|
||||
volatile FLAC__bool eof;
|
||||
volatile int seek_to;
|
||||
unsigned total_samples;
|
||||
unsigned bits_per_sample;
|
||||
unsigned output_bits_per_sample;
|
||||
unsigned channels;
|
||||
unsigned sample_rate;
|
||||
unsigned length_in_msec;
|
||||
unsigned average_bps;
|
||||
FLAC__bool has_replaygain;
|
||||
double replay_scale;
|
||||
DitherContext dither_context;
|
||||
} file_info_struct;
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
FLAC__bool enable;
|
||||
FLAC__bool album_mode;
|
||||
int preamp;
|
||||
FLAC__bool hard_limit;
|
||||
} replaygain;
|
||||
struct {
|
||||
struct {
|
||||
FLAC__bool dither_24_to_16;
|
||||
} normal;
|
||||
struct {
|
||||
FLAC__bool dither;
|
||||
int noise_shaping; /* value must be one of NoiseShaping enum, see plugin_common/replaygain_synthesis.h */
|
||||
int bps_out;
|
||||
} replaygain;
|
||||
} resolution;
|
||||
struct {
|
||||
FLAC__bool stop_err;
|
||||
} misk;
|
||||
} output_config_t;
|
||||
|
||||
/*
|
||||
* protopytes
|
||||
*/
|
||||
|
||||
FLAC__bool FLAC_plugin__decoder_init(FLAC__FileDecoder *decoder, const char *filename, FLAC__int64 filesize, file_info_struct *file_info, output_config_t *config);
|
||||
void FLAC_plugin__decoder_finish(FLAC__FileDecoder *decoder);
|
||||
void FLAC_plugin__decoder_delete(FLAC__FileDecoder *decoder);
|
||||
|
||||
int FLAC_plugin__seek(FLAC__FileDecoder *decoder, file_info_struct *file_info);
|
||||
unsigned FLAC_plugin__decode(FLAC__FileDecoder *decoder, file_info_struct *file_info, char *sample_buffer);
|
||||
int FLAC_plugin__get_rate(unsigned written_time, unsigned output_time, file_info_struct *file_info);
|
||||
|
||||
/*
|
||||
* these should be defined in plug-in
|
||||
*/
|
||||
|
||||
extern void FLAC_plugin__show_error(const char *message,...);
|
@ -23,11 +23,17 @@
|
||||
#define IDC_TITLE 1010
|
||||
#define IDC_TAGZ_HELP 1011
|
||||
#define IDC_ARTIST 1011
|
||||
#define IDC_TAGZ_DEFAULT 1012
|
||||
#define IDC_SEP 1013
|
||||
#define IDC_NAME 1014
|
||||
#define IDC_INFO 1015
|
||||
#define IDC_GENRE 1017
|
||||
#define IDC_REMOVE 1020
|
||||
#define IDC_UPDATE 1021
|
||||
#define IDC_ID3V1 1030
|
||||
#define IDC_RESERVE 1032
|
||||
#define IDC_BPS 1036
|
||||
#define IDC_ERRORS 1037
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
@ -35,7 +41,7 @@
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 106
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1030
|
||||
#define _APS_NEXT_CONTROL_VALUE 1037
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
@ -67,7 +67,7 @@ BEGIN
|
||||
EDITTEXT IDC_ALBUM,43,60,137,12,ES_AUTOHSCROLL
|
||||
RTEXT "&Comment",IDC_STATIC,8,77,31,8
|
||||
EDITTEXT IDC_COMMENT,43,75,137,12,ES_AUTOHSCROLL
|
||||
RTEXT "&Year",IDC_STATIC,8,92,31,8
|
||||
RTEXT "&Date",IDC_STATIC,8,92,31,8
|
||||
EDITTEXT IDC_YEAR,43,90,40,12,ES_AUTOHSCROLL
|
||||
RTEXT "Track &number",IDC_STATIC,90,92,46,8
|
||||
EDITTEXT IDC_TRACK,141,90,39,12,ES_AUTOHSCROLL
|
||||
@ -133,10 +133,23 @@ IDD_CONFIG_GENERAL DIALOG DISCARDABLE 0, 0, 226, 171
|
||||
STYLE DS_CONTROL | WS_CHILD
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
GROUPBOX " Title Formatting ",IDC_STATIC,2,2,220,43
|
||||
LTEXT "&Title:",IDC_STATIC,8,17,16,8
|
||||
GROUPBOX " Title Formatting ",IDC_STATIC,2,2,220,58
|
||||
LTEXT "&Title",IDC_STATIC,8,17,14,8
|
||||
EDITTEXT IDC_TITLE,27,15,188,12,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "default",IDC_TAGZ_DEFAULT,156,28,30,10
|
||||
PUSHBUTTON "help",IDC_TAGZ_HELP,188,28,27,10
|
||||
LTEXT "Separate tag values &with",IDC_STATIC,8,43,79,8
|
||||
EDITTEXT IDC_SEP,91,41,27,12,ES_AUTOHSCROLL
|
||||
CONTROL "Read ID3v&1 tags",IDC_ID3V1,"Button",BS_AUTOCHECKBOX |
|
||||
WS_TABSTOP,147,43,70,10
|
||||
GROUPBOX " Tag Editor ",IDC_STATIC,2,63,220,30
|
||||
CONTROL "Reserve space for &VorbisComment",IDC_RESERVE,"Button",
|
||||
BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,8,76,125,10
|
||||
GROUPBOX " Misk ",IDC_STATIC,2,96,220,72
|
||||
CONTROL "&Show average bitrate while playing",IDC_BPS,"Button",
|
||||
BS_AUTOCHECKBOX | WS_TABSTOP,8,108,125,10
|
||||
CONTROL "Stop on &all errors",IDC_ERRORS,"Button",
|
||||
BS_AUTOCHECKBOX | WS_TABSTOP,8,120,69,10
|
||||
END
|
||||
|
||||
IDD_CONFIG_OUTPUT DIALOG DISCARDABLE 0, 0, 224, 171
|
||||
@ -159,11 +172,11 @@ BEGIN
|
||||
CONTROL "&Dither 24bps to 16bps",IDC_DITHER,"Button",
|
||||
BS_AUTOCHECKBOX | WS_TABSTOP,16,84,85,10
|
||||
GROUPBOX " With ReplayGain ",IDC_STATIC,7,104,209,47
|
||||
CONTROL "E&nable dithering",IDC_DITHERRG,"Button",
|
||||
BS_AUTOCHECKBOX | WS_TABSTOP,16,134,67,10
|
||||
LTEXT "&Output bit depth",IDC_STATIC,16,119,52,8
|
||||
COMBOBOX IDC_TO,71,116,39,43,CBS_DROPDOWNLIST | WS_VSCROLL |
|
||||
WS_TABSTOP
|
||||
CONTROL "E&nable dithering",IDC_DITHERRG,"Button",
|
||||
BS_AUTOCHECKBOX | WS_TABSTOP,16,134,67,10
|
||||
LTEXT "Noise &shaping",IDC_STATIC,113,135,46,8
|
||||
COMBOBOX IDC_SHAPE,164,132,46,48,CBS_DROPDOWNLIST | WS_VSCROLL |
|
||||
WS_TABSTOP
|
||||
|
@ -125,7 +125,7 @@ static char roman_num[]=
|
||||
};
|
||||
|
||||
|
||||
static int is_roman(T_CHAR * ptr)//could be more smart i think
|
||||
static int is_roman(T_CHAR * ptr)/* could be more smart i think */
|
||||
{
|
||||
if (ptr[0]==']' && ptr[1]=='[' && separator(ptr[2])) return 1;
|
||||
while(!separator(*ptr))
|
||||
@ -164,7 +164,7 @@ MAKEFUNC(If)
|
||||
if (n_src!=3) return false;
|
||||
|
||||
out.AddString(src[found_src[0] ? 1 : 2]);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(If2)
|
||||
@ -172,7 +172,7 @@ MAKEFUNC(If2)
|
||||
if (n_src!=2) return false;
|
||||
|
||||
out.AddString(src[found_src[0] ? 0 : 1]);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -181,7 +181,7 @@ MAKEFUNC(Iflonger)
|
||||
if (n_src!=4) return false;
|
||||
|
||||
out.AddString(src[(int)t_strlen(src[0])>t_atoi(src[1]) ? 2 : 3]);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Ifgreater)
|
||||
@ -189,7 +189,7 @@ MAKEFUNC(Ifgreater)
|
||||
if (n_src!=4) return false;
|
||||
|
||||
out.AddString(src[t_atoi(src[0])>t_atoi(src[1]) ? 2 : 3]);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Upper)
|
||||
@ -201,7 +201,7 @@ MAKEFUNC(Upper)
|
||||
while(*s)
|
||||
out.AddChar(toupper(*(s++)));
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Lower)
|
||||
@ -213,7 +213,7 @@ MAKEFUNC(Lower)
|
||||
while(*s)
|
||||
out.AddChar(tolower(*(s++)));
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Pad)
|
||||
@ -222,18 +222,18 @@ MAKEFUNC(Pad)
|
||||
|
||||
T_CHAR *fill=_TX(" ");
|
||||
if (n_src==3 && src[2][0])
|
||||
fill = src[2];
|
||||
fill = src[2];
|
||||
|
||||
int num = t_atoi(src[1]);
|
||||
T_CHAR *p = src[0];
|
||||
|
||||
while (*p) { out.AddChar(*(p++)); num--; }
|
||||
while (*p) { out.AddChar(*(p++)); num--; }
|
||||
|
||||
UINT fl = t_strlen(fill);
|
||||
while (num>0)
|
||||
out.AddChar(fill[(--num)%fl]);
|
||||
out.AddChar(fill[(--num)%fl]);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Cut)
|
||||
@ -245,7 +245,7 @@ MAKEFUNC(Cut)
|
||||
|
||||
while (*p && num>0) {out.AddChar(*(p++));num--;}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(PadCut)
|
||||
@ -254,7 +254,7 @@ MAKEFUNC(PadCut)
|
||||
|
||||
T_CHAR *fill = _TX(" ");
|
||||
if (n_src==3 && src[2][0])
|
||||
fill = src[2];
|
||||
fill = src[2];
|
||||
|
||||
int num = t_atoi(src[1]);
|
||||
T_CHAR *p = src[0];
|
||||
@ -263,13 +263,13 @@ MAKEFUNC(PadCut)
|
||||
|
||||
UINT fl=t_strlen(fill);
|
||||
while (num>0)
|
||||
out.AddChar(fill[(--num)%fl]);
|
||||
out.AddChar(fill[(--num)%fl]);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// abbr(string)
|
||||
// abbr(string,len)
|
||||
/* abbr(string) */
|
||||
/* abbr(string,len) */
|
||||
MAKEFUNC(Abbr)
|
||||
{
|
||||
if (n_src==0 || n_src>2) return false;
|
||||
@ -301,7 +301,7 @@ MAKEFUNC(Abbr)
|
||||
meta++;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -324,7 +324,7 @@ MAKEFUNC(Caps)
|
||||
out.AddChar(c);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Caps2)
|
||||
@ -344,7 +344,7 @@ MAKEFUNC(Caps2)
|
||||
out.AddChar(c);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Longest)
|
||||
@ -359,7 +359,7 @@ MAKEFUNC(Longest)
|
||||
}
|
||||
|
||||
if (ptr) out.AddString(ptr);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Shortest)
|
||||
@ -374,7 +374,7 @@ MAKEFUNC(Shortest)
|
||||
}
|
||||
|
||||
if (ptr) out.AddString(ptr);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Num)
|
||||
@ -387,20 +387,20 @@ MAKEFUNC(Num)
|
||||
sprintf(tmp,tmp1,t_atoi(src[0]));
|
||||
out.AddString(tmp);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Hex)
|
||||
{
|
||||
if (n_src!=2) return false;
|
||||
|
||||
T_CHAR tmp[16];
|
||||
T_CHAR tmp[16];
|
||||
T_CHAR tmp1[16];
|
||||
sprintf(tmp1,_TX("%%0%ux"),t_atoi(src[1]));
|
||||
sprintf(tmp,tmp1,t_atoi(src[0]));
|
||||
out.AddString(tmp);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(StrChr)
|
||||
@ -412,10 +412,10 @@ MAKEFUNC(StrChr)
|
||||
|
||||
while (*p && *p!=s) p++;
|
||||
if (*p==s)
|
||||
out.AddInt(1+p-src[0]);
|
||||
out.AddInt(1+p-src[0]);
|
||||
else out.AddChar('0');
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(StrRChr)
|
||||
@ -432,10 +432,10 @@ MAKEFUNC(StrRChr)
|
||||
}
|
||||
|
||||
if (p1)
|
||||
out.AddInt(1+p1-src[0]);
|
||||
out.AddInt(1+p1-src[0]);
|
||||
else out.AddChar('0');
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(StrStr)
|
||||
@ -445,14 +445,14 @@ MAKEFUNC(StrStr)
|
||||
T_CHAR * p = t_strstr(src[0],src[1]);
|
||||
|
||||
if (p)
|
||||
out.AddInt(1+p-src[0]);
|
||||
out.AddInt(1+p-src[0]);
|
||||
else out.AddChar('0');
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// substr(string, index)
|
||||
// substr(string, index, length)
|
||||
/* substr(string, index) */
|
||||
/* substr(string, index, length) */
|
||||
MAKEFUNC(SubStr)
|
||||
{
|
||||
if (n_src<2 || n_src>3) return false;
|
||||
@ -472,15 +472,15 @@ MAKEFUNC(SubStr)
|
||||
out.AddChar(src[0][n1++]);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Len)
|
||||
{
|
||||
if (n_src!=1) return false;
|
||||
|
||||
out.AddInt(t_strlen(src[0]));
|
||||
return true;
|
||||
out.AddInt(t_strlen(src[0]));
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Add)
|
||||
@ -493,7 +493,7 @@ MAKEFUNC(Add)
|
||||
|
||||
out.AddInt(s);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Sub)
|
||||
@ -508,7 +508,7 @@ MAKEFUNC(Sub)
|
||||
|
||||
out.AddInt(s);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Mul)
|
||||
@ -521,7 +521,7 @@ MAKEFUNC(Mul)
|
||||
|
||||
out.AddInt(s);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Div)
|
||||
@ -540,7 +540,7 @@ MAKEFUNC(Div)
|
||||
|
||||
out.AddInt(s);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Mod)
|
||||
@ -559,7 +559,7 @@ MAKEFUNC(Mod)
|
||||
|
||||
out.AddInt(s);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Max)
|
||||
@ -576,7 +576,7 @@ MAKEFUNC(Max)
|
||||
}
|
||||
out.AddInt(m);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAKEFUNC(Min)
|
||||
@ -593,10 +593,10 @@ MAKEFUNC(Min)
|
||||
}
|
||||
out.AddInt(m);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// replace(string, what_to_replace, replacement)
|
||||
/* replace(string, what_to_replace, replacement) */
|
||||
MAKEFUNC(Replace)
|
||||
{
|
||||
if (n_src!=3) return false;
|
||||
@ -616,7 +616,7 @@ MAKEFUNC(Replace)
|
||||
else out.AddChar(*p++);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct
|
||||
@ -671,11 +671,11 @@ private:
|
||||
int found;
|
||||
|
||||
void Error(T_CHAR *e=0)
|
||||
{
|
||||
str.Reset();
|
||||
str.AddString(e ? e : _TX("[SYNTAX ERROR IN FORMATTING STRING]"));
|
||||
found++; // force displaying
|
||||
}
|
||||
{
|
||||
str.Reset();
|
||||
str.AddString(e ? e : _TX("[SYNTAX ERROR IN FORMATTING STRING]"));
|
||||
found++; /* force displaying */
|
||||
}
|
||||
|
||||
T_CHAR * _FMT(T_CHAR * s,UINT *f=0)
|
||||
{
|
||||
@ -739,7 +739,7 @@ private:
|
||||
*s1=0;
|
||||
const T_CHAR * tag=f(spec,fp);
|
||||
*s1='%';
|
||||
//if (!tag) tag=tag_unknown;
|
||||
/*if (!tag) tag=tag_unknown; */
|
||||
if (tag && tag[0])
|
||||
{
|
||||
found++;
|
||||
@ -784,25 +784,25 @@ private:
|
||||
|
||||
for (n=0; n<TABSIZE(FUNCS); n++)
|
||||
if (!t_stricmp(spec, FUNCS[n].name))
|
||||
break;
|
||||
break;
|
||||
|
||||
*s1='(';
|
||||
|
||||
if (n != TABSIZE(FUNCS))
|
||||
{
|
||||
if (!FUNCS[n].func(nt, temp, temp_f, str))
|
||||
{
|
||||
Error(_TX("[INVALID $"));
|
||||
str.AddString(FUNCS[n].name);
|
||||
str.AddString(_TX(" SYNTAX]"));
|
||||
return;
|
||||
}
|
||||
{
|
||||
Error(_TX("[INVALID $"));
|
||||
str.AddString(FUNCS[n].name);
|
||||
str.AddString(_TX(" SYNTAX]"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(_TX("[UNKNOWN FUNCTION]"));
|
||||
return;
|
||||
}
|
||||
{
|
||||
Error(_TX("[UNKNOWN FUNCTION]"));
|
||||
return;
|
||||
}
|
||||
|
||||
for(n=0;n<nt;n++) free(temp[n]);
|
||||
spec=s2+1;
|
||||
@ -897,8 +897,6 @@ T_CHAR * tagz_format_r(const T_CHAR* spec,TAGFUNC f,TAGFREEFUNC ff,void * fp)
|
||||
return FMT(spec,f,ff,fp);
|
||||
}
|
||||
|
||||
//char tagz_manual[]="TODO: WTFM";
|
||||
|
||||
const char tagz_manual[]="Syntax reference: \n"
|
||||
"\n"
|
||||
"* %tagname% - inserts field named <tagname>, eg. \"%artist%\"\n"
|
||||
|
@ -14,7 +14,7 @@ typedef unsigned short T_CHAR;
|
||||
#define T_CHAR char
|
||||
#endif
|
||||
|
||||
typedef const T_CHAR* (*TAGFUNC)(const T_CHAR *tag,void *p); // return 0 if not found
|
||||
typedef const T_CHAR* (*TAGFUNC)(const T_CHAR *tag,void *p); /* return 0 if not found */
|
||||
typedef void (*TAGFREEFUNC)(const T_CHAR *tag,void *p);
|
||||
|
||||
|
||||
|
@ -135,36 +135,14 @@ const CharsetInfo charset_trans_array[] = {
|
||||
/*
|
||||
* Commons conversion functions
|
||||
*/
|
||||
char *convert_from_file_to_user(const char *string)
|
||||
char *convert_from_utf8_to_user(const char *string)
|
||||
{
|
||||
return FLAC_plugin__charset_convert_string(string, flac_cfg.title.file_char_set, flac_cfg.title.user_char_set);
|
||||
return FLAC_plugin__charset_convert_string(string, "UTF-8", flac_cfg.title.user_char_set);
|
||||
}
|
||||
|
||||
char *convert_from_user_to_file(const char *string)
|
||||
char *convert_from_user_to_utf8(const char *string)
|
||||
{
|
||||
return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, flac_cfg.title.file_char_set);
|
||||
}
|
||||
|
||||
void convert_from_file_to_user_in_place(char **string)
|
||||
{
|
||||
if(0 != *string) {
|
||||
char *tmp;
|
||||
|
||||
tmp = convert_from_file_to_user(*string);
|
||||
free(*string);
|
||||
*string = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void convert_from_user_to_file_in_place(char **string)
|
||||
{
|
||||
if(0 != *string) {
|
||||
char *tmp;
|
||||
|
||||
tmp = convert_from_user_to_file(*string);
|
||||
free(*string);
|
||||
*string = tmp;
|
||||
}
|
||||
return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, "UTF-8");
|
||||
}
|
||||
|
||||
GList *Charset_Create_List (void)
|
||||
|
@ -41,10 +41,11 @@ extern const CharsetInfo charset_trans_array[];
|
||||
* Prototypes *
|
||||
**************/
|
||||
|
||||
char *convert_from_file_to_user(const char *string);
|
||||
char *convert_from_user_to_file(const char *string);
|
||||
void convert_from_file_to_user_in_place(char **string);
|
||||
void convert_from_user_to_file_in_place(char **string);
|
||||
/*
|
||||
* The returned strings are malloc()ed an must be free()d by the caller
|
||||
*/
|
||||
char *convert_from_utf8_to_user(const char *string);
|
||||
char *convert_from_user_to_utf8(const char *string);
|
||||
|
||||
GList *Charset_Create_List (void);
|
||||
gchar *Charset_Get_Name_From_Title (gchar *charset_title);
|
||||
|
@ -48,7 +48,6 @@ flac_config_t flac_cfg = {
|
||||
FALSE, /* tag_override */
|
||||
NULL, /* tag_format */
|
||||
FALSE, /* convert_char_set */
|
||||
NULL, /* file_char_set */
|
||||
NULL /* user_char_set */
|
||||
},
|
||||
/* output */
|
||||
@ -108,7 +107,6 @@ static void flac_configurewin_ok(GtkWidget * widget, gpointer data)
|
||||
(void)widget, (void)data; /* unused arguments */
|
||||
g_free(flac_cfg.title.tag_format);
|
||||
flac_cfg.title.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry)));
|
||||
flac_cfg.title.file_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(fileCharacterSetEntry));
|
||||
flac_cfg.title.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry));
|
||||
|
||||
filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL);
|
||||
@ -119,7 +117,6 @@ static void flac_configurewin_ok(GtkWidget * widget, gpointer data)
|
||||
xmms_cfg_write_boolean(cfg, "flac", "title.tag_override", flac_cfg.title.tag_override);
|
||||
xmms_cfg_write_string(cfg, "flac", "title.tag_format", flac_cfg.title.tag_format);
|
||||
xmms_cfg_write_boolean(cfg, "flac", "title.convert_char_set", flac_cfg.title.convert_char_set);
|
||||
xmms_cfg_write_string(cfg, "flac", "title.file_char_set", flac_cfg.title.file_char_set);
|
||||
xmms_cfg_write_string(cfg, "flac", "title.user_char_set", flac_cfg.title.user_char_set);
|
||||
/* output */
|
||||
xmms_cfg_write_boolean(cfg, "flac", "output.replaygain.enable", flac_cfg.output.replaygain.enable);
|
||||
@ -293,7 +290,6 @@ void FLAC_XMMS__configure(void)
|
||||
list = Charset_Create_List();
|
||||
gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),list);
|
||||
gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list);
|
||||
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.file_char_set));
|
||||
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.user_char_set));
|
||||
gtk_widget_set_sensitive(fileCharacterSetEntry, flac_cfg.title.convert_char_set);
|
||||
gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
|
||||
|
@ -28,7 +28,6 @@ typedef struct {
|
||||
gboolean tag_override;
|
||||
gchar *tag_format;
|
||||
gboolean convert_char_set;
|
||||
gchar *file_char_set;
|
||||
gchar *user_char_set;
|
||||
} title;
|
||||
|
||||
|
@ -88,12 +88,6 @@ static const gchar *vorbis_genres[] =
|
||||
N_("Anime"), N_("JPop"), N_("Synthpop")
|
||||
};
|
||||
|
||||
static void local__safe_free(void *object)
|
||||
{
|
||||
if(0 != object)
|
||||
free(object);
|
||||
}
|
||||
|
||||
static void label_set_text(GtkWidget * label, char *str, ...)
|
||||
{
|
||||
va_list args;
|
||||
@ -107,45 +101,53 @@ static void label_set_text(GtkWidget * label, char *str, ...)
|
||||
g_free(tempstr);
|
||||
}
|
||||
|
||||
static void set_entry_tag(GtkEntry * entry, gchar * tag)
|
||||
static void set_entry_tag(GtkEntry * entry, const wchar_t * tag)
|
||||
{
|
||||
char *text;
|
||||
|
||||
if(tag) {
|
||||
char *utf8 = FLAC_plugin__convert_ucs2_to_utf8(tag);
|
||||
if(flac_cfg.title.convert_char_set) {
|
||||
text = convert_from_file_to_user(tag);
|
||||
char *text = convert_from_utf8_to_user(utf8);
|
||||
gtk_entry_set_text(entry, text);
|
||||
free(text);
|
||||
}
|
||||
else
|
||||
gtk_entry_set_text(entry, tag);
|
||||
else {
|
||||
gtk_entry_set_text(entry, utf8);
|
||||
}
|
||||
free(utf8);
|
||||
}
|
||||
else
|
||||
gtk_entry_set_text(entry, "");
|
||||
}
|
||||
|
||||
static char *get_entry_tag(GtkEntry * entry)
|
||||
static void get_entry_tag(GtkEntry * entry, const char *name)
|
||||
{
|
||||
gchar *text;
|
||||
char *utf8;
|
||||
|
||||
text = gtk_entry_get_text(entry);
|
||||
if (!text || strlen(text) == 0)
|
||||
return 0;
|
||||
return;
|
||||
if(flac_cfg.title.convert_char_set)
|
||||
return convert_from_user_to_file(text);
|
||||
utf8 = convert_from_user_to_utf8(text);
|
||||
else
|
||||
return strdup(text);
|
||||
utf8 = text;
|
||||
|
||||
FLAC_plugin__canonical_add_utf8(canonical_tag, name, utf8, (unsigned)(-1), (unsigned)(-1), /*sep=*/0);
|
||||
|
||||
if(flac_cfg.title.convert_char_set)
|
||||
free(utf8);
|
||||
}
|
||||
|
||||
static void show_tag()
|
||||
{
|
||||
set_entry_tag(GTK_ENTRY(title_entry), canonical_tag->title);
|
||||
set_entry_tag(GTK_ENTRY(artist_entry), canonical_tag->composer);
|
||||
set_entry_tag(GTK_ENTRY(album_entry), canonical_tag->album);
|
||||
set_entry_tag(GTK_ENTRY(date_entry), canonical_tag->year_recorded);
|
||||
set_entry_tag(GTK_ENTRY(tracknum_entry), canonical_tag->track_number);
|
||||
set_entry_tag(GTK_ENTRY(comment_entry), canonical_tag->comment);
|
||||
set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), canonical_tag->genre);
|
||||
set_entry_tag(GTK_ENTRY(title_entry) , FLAC_plugin__canonical_get(canonical_tag, L"TITLE"));
|
||||
set_entry_tag(GTK_ENTRY(artist_entry) , FLAC_plugin__canonical_get(canonical_tag, L"ARTIST"));
|
||||
set_entry_tag(GTK_ENTRY(album_entry) , FLAC_plugin__canonical_get(canonical_tag, L"ALBUM"));
|
||||
set_entry_tag(GTK_ENTRY(date_entry) , FLAC_plugin__canonical_get(canonical_tag, L"DATE"));
|
||||
set_entry_tag(GTK_ENTRY(tracknum_entry) , FLAC_plugin__canonical_get(canonical_tag, L"TRACKNUMBER"));
|
||||
set_entry_tag(GTK_ENTRY(comment_entry) , FLAC_plugin__canonical_get(canonical_tag, L"DESCRIPTION"));
|
||||
set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FLAC_plugin__canonical_get(canonical_tag, L"GENRE"));
|
||||
}
|
||||
|
||||
static void save_tag(GtkWidget * w, gpointer data)
|
||||
@ -153,21 +155,22 @@ static void save_tag(GtkWidget * w, gpointer data)
|
||||
(void)w;
|
||||
(void)data;
|
||||
|
||||
local__safe_free(canonical_tag->title);
|
||||
local__safe_free(canonical_tag->composer);
|
||||
local__safe_free(canonical_tag->album);
|
||||
local__safe_free(canonical_tag->year_recorded);
|
||||
local__safe_free(canonical_tag->track_number);
|
||||
local__safe_free(canonical_tag->comment);
|
||||
local__safe_free(canonical_tag->genre);
|
||||
canonical_tag->title = get_entry_tag(GTK_ENTRY(title_entry));
|
||||
canonical_tag->composer = get_entry_tag(GTK_ENTRY(artist_entry));
|
||||
canonical_tag->album = get_entry_tag(GTK_ENTRY(album_entry));
|
||||
canonical_tag->year_recorded = get_entry_tag(GTK_ENTRY(date_entry));
|
||||
canonical_tag->track_number = get_entry_tag(GTK_ENTRY(tracknum_entry));
|
||||
canonical_tag->comment = get_entry_tag(GTK_ENTRY(comment_entry));
|
||||
canonical_tag->genre = get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry));
|
||||
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"TITLE")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"ARTIST")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"ALBUM")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"DATE")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"TRACKNUMBER")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"DESCRIPTION")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"GENRE")) ;
|
||||
|
||||
get_entry_tag(GTK_ENTRY(title_entry) , "TITLE");
|
||||
get_entry_tag(GTK_ENTRY(artist_entry) , "ARTIST");
|
||||
get_entry_tag(GTK_ENTRY(album_entry) , "ALBUM");
|
||||
get_entry_tag(GTK_ENTRY(date_entry) , "DATE");
|
||||
get_entry_tag(GTK_ENTRY(tracknum_entry) , "TRACKNUMBER");
|
||||
get_entry_tag(GTK_ENTRY(comment_entry) , "DESCRIPTION");
|
||||
get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "GENRE");
|
||||
|
||||
FLAC_plugin__vorbiscomment_set(current_filename, canonical_tag);
|
||||
gtk_widget_destroy(window);
|
||||
}
|
||||
@ -177,15 +180,13 @@ static void remove_tag(GtkWidget * w, gpointer data)
|
||||
(void)w;
|
||||
(void)data;
|
||||
|
||||
local__safe_free(canonical_tag->title);
|
||||
local__safe_free(canonical_tag->composer);
|
||||
local__safe_free(canonical_tag->album);
|
||||
local__safe_free(canonical_tag->year_recorded);
|
||||
local__safe_free(canonical_tag->track_number);
|
||||
local__safe_free(canonical_tag->comment);
|
||||
local__safe_free(canonical_tag->genre);
|
||||
|
||||
canonical_tag->title = canonical_tag->composer = canonical_tag->album = canonical_tag->year_recorded = canonical_tag->track_number = canonical_tag->comment = canonical_tag->genre = 0;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"TITLE")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"ARTIST")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"ALBUM")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"DATE")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"TRACKNUMBER")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"DESCRIPTION")) ;
|
||||
while (FLAC_plugin__canonical_remove(canonical_tag, L"GENRE")) ;
|
||||
|
||||
FLAC_plugin__vorbiscomment_set(current_filename, canonical_tag);
|
||||
gtk_widget_destroy(window);
|
||||
@ -419,7 +420,7 @@ void FLAC_XMMS__file_info_box(char *filename)
|
||||
else
|
||||
canonical_tag = FLAC_plugin__canonical_tag_new();
|
||||
|
||||
FLAC_plugin__vorbiscomment_get(current_filename, canonical_tag);
|
||||
FLAC_plugin__vorbiscomment_get(current_filename, canonical_tag, /*sep=*/0);
|
||||
|
||||
show_tag();
|
||||
show_file_info();
|
||||
|
@ -167,9 +167,6 @@ void FLAC_XMMS__init()
|
||||
|
||||
xmms_cfg_read_boolean(cfg, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set);
|
||||
|
||||
if(!xmms_cfg_read_string(cfg, "flac", "title.file_char_set", &flac_cfg.title.file_char_set))
|
||||
flac_cfg.title.file_char_set = FLAC_plugin__charset_get_current();
|
||||
|
||||
if(!xmms_cfg_read_string(cfg, "flac", "title.user_char_set", &flac_cfg.title.user_char_set))
|
||||
flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current();
|
||||
|
||||
|
@ -29,8 +29,7 @@
|
||||
#include <xmms/titlestring.h>
|
||||
|
||||
#include "FLAC/metadata.h"
|
||||
#include "plugin_common/id3v1.h"
|
||||
#include "plugin_common/id3v2.h"
|
||||
#include "plugin_common/canonical_tag.h"
|
||||
#include "charset.h"
|
||||
#include "configure.h"
|
||||
|
||||
@ -65,6 +64,29 @@ static int local__getnum(char* str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *local__getfield(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
const wchar_t *ucs2 = FLAC_plugin__canonical_get(tag, name);
|
||||
if (0 != ucs2) {
|
||||
char *utf8 = FLAC_plugin__convert_ucs2_to_utf8(FLAC_plugin__canonical_get(tag, name));
|
||||
if(flac_cfg.title.convert_char_set) {
|
||||
char *user = convert_from_utf8_to_user(utf8);
|
||||
free(utf8);
|
||||
return user;
|
||||
}
|
||||
else
|
||||
return utf8;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void local__safe_free(char *s)
|
||||
{
|
||||
if (0 != s)
|
||||
free(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function flac_format_song_title (tag, filename)
|
||||
*
|
||||
@ -77,35 +99,32 @@ char *flac_format_song_title(char *filename)
|
||||
char *ret = NULL;
|
||||
TitleInput *input = NULL;
|
||||
FLAC_Plugin__CanonicalTag tag;
|
||||
char *title, *artist, *performer, *album, *date, *tracknumber, *genre, *description;
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_get_combined(filename, &tag);
|
||||
FLAC_plugin__canonical_tag_get_combined(filename, &tag, /*sep=*/0);
|
||||
|
||||
if(flac_cfg.title.convert_char_set) {
|
||||
convert_from_file_to_user_in_place(&tag.title);
|
||||
convert_from_file_to_user_in_place(&tag.composer);
|
||||
convert_from_file_to_user_in_place(&tag.performer);
|
||||
convert_from_file_to_user_in_place(&tag.album);
|
||||
convert_from_file_to_user_in_place(&tag.year_recorded);
|
||||
convert_from_file_to_user_in_place(&tag.year_performed);
|
||||
convert_from_file_to_user_in_place(&tag.track_number);
|
||||
convert_from_file_to_user_in_place(&tag.tracks_in_album);
|
||||
convert_from_file_to_user_in_place(&tag.genre);
|
||||
convert_from_file_to_user_in_place(&tag.comment);
|
||||
}
|
||||
title = local__getfield(&tag, L"TITLE");
|
||||
artist = local__getfield(&tag, L"ARTIST");
|
||||
performer = local__getfield(&tag, L"PERFORMER");
|
||||
album = local__getfield(&tag, L"ALBUM");
|
||||
date = local__getfield(&tag, L"DATE");
|
||||
tracknumber = local__getfield(&tag, L"TRACKNUMBER");
|
||||
genre = local__getfield(&tag, L"GENRE");
|
||||
description = local__getfield(&tag, L"DESCRIPTION");
|
||||
|
||||
XMMS_NEW_TITLEINPUT(input);
|
||||
|
||||
input->performer = local__getstr(tag.performer);
|
||||
input->performer = local__getstr(performer);
|
||||
if(!input->performer)
|
||||
input->performer = local__getstr(tag.composer);
|
||||
input->album_name = local__getstr(tag.album);
|
||||
input->track_name = local__getstr(tag.title);
|
||||
input->track_number = local__getnum(tag.track_number);
|
||||
input->year = local__getnum(tag.year_recorded);
|
||||
input->genre = local__getstr(tag.genre);
|
||||
input->comment = local__getstr(tag.comment);
|
||||
input->performer = local__getstr(artist);
|
||||
input->album_name = local__getstr(album);
|
||||
input->track_name = local__getstr(title);
|
||||
input->track_number = local__getnum(tracknumber);
|
||||
input->year = local__getnum(date);
|
||||
input->genre = local__getstr(genre);
|
||||
input->comment = local__getstr(description);
|
||||
|
||||
input->file_name = g_basename(filename);
|
||||
input->file_path = filename;
|
||||
@ -123,5 +142,13 @@ char *flac_format_song_title(char *filename)
|
||||
}
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&tag);
|
||||
local__safe_free(title);
|
||||
local__safe_free(artist);
|
||||
local__safe_free(performer);
|
||||
local__safe_free(album);
|
||||
local__safe_free(date);
|
||||
local__safe_free(tracknumber);
|
||||
local__safe_free(genre);
|
||||
local__safe_free(description);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user