# HG changeset patch # User nenolod # Date 1161741833 25200 # Node ID 38ce41606f1080d49c3b5e45c004c59d2ab6fcb3 # Parent 0eb1e99b77489f56ea87a8c1b330411985367665 [svn] - wavpack input plugin -- under construction diff -r 0eb1e99b7748 -r 38ce41606f10 ChangeLog --- a/ChangeLog Tue Oct 24 18:15:53 2006 -0700 +++ b/ChangeLog Tue Oct 24 19:03:53 2006 -0700 @@ -1,3 +1,13 @@ +2006-10-25 01:15:53 +0000 William Pitcock + revision [216] + - move prefswin_page_destroy(cfgdlg) to before the plugin logs out of last.fm; + otherwise the prefswin_page handle isn't always removed. + Reported on IRC by Tim Yamin + + trunk/src/scrobbler/xmms_scrobbler.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + + 2006-10-24 08:44:06 +0000 William Pitcock revision [214] - 1.2.2 release diff -r 0eb1e99b7748 -r 38ce41606f10 src/wavpack/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wavpack/Makefile Tue Oct 24 19:03:53 2006 -0700 @@ -0,0 +1,16 @@ +include ../../mk/rules.mk +include ../../mk/init.mk + +OBJECTIVE_LIBS = libwavpack$(SHARED_SUFFIX) + +LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR) + +SOURCES = tags.cxx ui.cxx libwavpack.cxx + +LIBADD = -L/usr/local/lib + +CXXFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../intl -I../.. + +OBJECTS = ${SOURCES:.cxx=.o} + +include ../../mk/objective.mk diff -r 0eb1e99b7748 -r 38ce41606f10 src/wavpack/libwavpack.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wavpack/libwavpack.cxx Tue Oct 24 19:03:53 2006 -0700 @@ -0,0 +1,411 @@ +#include +#include +#include +#include +#include +#include +extern "C" { +#include +#include +#include +#include +} +#include +#include +#include +#include +#include "equalizer.h" +#include "tags.h" +#ifndef M_LN10 +#define M_LN10 2.3025850929940456840179914546843642 +#endif + +#define DBG(format, args...) fprintf(stderr, format, ## args) +#define BUFFER_SIZE 256 // read buffer size, in samples + +extern "C" InputPlugin * get_iplugin_info(void); +static void wv_load_config(); +static int wv_is_our_file(char *); +static void wv_play(char *); +static void wv_stop(void); +static void wv_pause(short); +static void wv_seek(int); +static int wv_get_time(void); +static void wv_get_song_info(char *, char **, int *); +static char *generate_title(const char *, WavpackContext *ctx); +static double isSeek; +static short paused; +static bool killDecodeThread; +static bool AudioError; +static GThread *thread_handle; +static gboolean EQ_on; + +// in ui.cpp +void wv_configure(); +void wv_about_box(void); +void wv_file_info_box(char *); +extern gboolean clipPreventionEnabled; +extern gboolean dynBitrateEnabled; +extern gboolean replaygainEnabled; +extern gboolean albumReplaygainEnabled; +extern gboolean openedAudio; + +InputPlugin mod = { + NULL, //handle + NULL, //filename + NULL, + wv_load_config, + wv_about_box, + wv_configure, + wv_is_our_file, + NULL, //no use + wv_play, + wv_stop, + wv_pause, + wv_seek, + NULL, //set eq + wv_get_time, + NULL, //get volume + NULL, //set volume + NULL, //cleanup + NULL, //obsolete + NULL, //add_vis + NULL, + NULL, + wv_get_song_info, + wv_file_info_box, //info box + NULL, //output +}; + +class WavpackDecoder +{ +public: + InputPlugin *mod; + int32_t *input; + int16_t *output; + int sample_rate; + int num_channels; + WavpackContext *ctx; + char error_buff[4096]; // TODO: fixme! + + WavpackDecoder(InputPlugin *mod) : mod(mod) + { + ctx = NULL; + input = NULL; + output = NULL; + } + + ~WavpackDecoder() + { + if (input != NULL) { + free(input); + input = NULL; + } + if (output != NULL) { + free(output); + output = NULL; + } + if (ctx != NULL) { + WavpackCloseFile(ctx); + ctx = NULL; + } + } + + bool attach(const char *filename) + { + ctx = WavpackOpenFileInput(filename, error_buff, OPEN_TAGS | OPEN_WVC, 0); + + if (ctx == NULL) { + return false; + } + + sample_rate = WavpackGetSampleRate(ctx); + num_channels = WavpackGetNumChannels(ctx); + input = (int32_t *)calloc(BUFFER_SIZE, num_channels * sizeof(int32_t)); + output = (int16_t *)calloc(BUFFER_SIZE, num_channels * sizeof(int16_t)); + mod->set_info(generate_title(filename, ctx), + (int) (WavpackGetNumSamples(ctx) / sample_rate) * 1000, + (int) WavpackGetAverageBitrate(ctx, num_channels), + (int) sample_rate, num_channels); + return true; + } + + bool open_audio() + { + return mod->output->open_audio(FMT_S16_LE, sample_rate, num_channels); + } + + void process_buffer(size_t num_samples) + { + for (int i = 0; i < num_samples * num_channels; i++) { + output[i] = input[i]; + } + produce_audio(mod->output->get_output_time(), FMT_S16_LE, + sample_rate, num_channels, output, + num_samples * num_channels * sizeof(int16_t)); + } +}; + +extern "C" InputPlugin * +get_iplugin_info(void) +{ + mod.description = + g_strdup_printf(("Wavpack Decoder Plugin %s"), VERSION); + return &mod; +} + +static int +wv_is_our_file(char *filename) +{ + char *ext; + + ext = strrchr(filename, '.'); + if (ext) { + if (!strcasecmp(ext, ".wv")) { + return TRUE; + } + } + return FALSE; +} + +void +load_tag(ape_tag *tag, WavpackContext *ctx) +{ + memset(tag, 0, sizeof(ape_tag)); + WavpackGetTagItem(ctx, "Album", tag->album, sizeof(tag->album)); + WavpackGetTagItem(ctx, "Artist", tag->artist, sizeof(tag->artist)); + WavpackGetTagItem(ctx, "Comment", tag->comment, sizeof(tag->comment)); + WavpackGetTagItem(ctx, "Genre", tag->genre, sizeof(tag->genre)); + WavpackGetTagItem(ctx, "Title", tag->title, sizeof(tag->title)); + WavpackGetTagItem(ctx, "Track", tag->track, sizeof(tag->track)); + WavpackGetTagItem(ctx, "Year", tag->year, sizeof(tag->year)); +} + +static char * +convertUTF8toLocale(char *utf8) +{ + // note - opens a new iconv descriptor for each call + // will have to find a way to reuse the descriptor if this turns + // out to be too slow + iconv_t idesc = iconv_open("", "UTF-8"); + if (idesc == (iconv_t) -1) { + perror("iconv_open failed"); + return g_strdup(utf8); + } + + size_t in_left = strlen(utf8); + size_t out_left = 2 * in_left + 1; + char *buf = (char *)g_malloc(out_left); + char *in = utf8; + char *out = buf; + + memset(buf, 0, out_left); + size_t err = iconv(idesc, &in, &in_left, &out, &out_left); + iconv_close(idesc); + return buf; +} + +static void * +end_thread() +{ + return 0; +} + +static void * +DecodeThread(void *a) +{ + ape_tag tag; + char *filename = (char *) a; + int bps_updateCounter = 0; + int bps; + int i; + WavpackDecoder d(&mod); + + if (!d.attach(filename)) { + printf("wavpack: Error opening file: \"%s\"\n", filename); + killDecodeThread = true; + return end_thread(); + } + bps = WavpackGetBytesPerSample(d.ctx) * d.num_channels; + DBG("reading %s at %d rate with %d channels\n", filename, d.sample_rate, d.num_channels); + + if (!d.open_audio()) { + DBG("error opening xmms audio channel\n"); + killDecodeThread = true; + AudioError = true; + openedAudio = false; + } + else { + DBG("opened xmms audio channel\n"); + openedAudio = true; + } + unsigned status; + char *display = generate_title(filename, d.ctx); + int length = (int) (1000 * WavpackGetNumSamples(d.ctx)); + + while (!killDecodeThread) { + if (isSeek != -1) { + DBG("seeking to position %d\n", isSeek); + WavpackSeekSample(d.ctx, isSeek * d.sample_rate); + isSeek = -1; + } + if (paused == 0 + && (mod.output->buffer_free() >= + (1152 * 2 * + (16 / 8)) << (mod.output->buffer_playing()? 1 : 0))) { + status = + WavpackUnpackSamples(d.ctx, d.input, BUFFER_SIZE); + if (status == (unsigned) (-1)) { + printf("wavpack: Error decoding file.\n"); + break; + } + else if (status == 0) { + killDecodeThread = true; + break; + } + else { + d.process_buffer(status); + } + } + else { + xmms_usleep(10000); + } + } + return end_thread(); +} + +static void +wv_play(char *filename) +{ + paused = 0; + isSeek = -1; + killDecodeThread = false; + AudioError = false; + thread_handle = g_thread_create(DecodeThread, (void *) filename, TRUE, NULL); + return; +} + +static char * +generate_title(const char *fn, WavpackContext *ctx) +{ + static char *displaytitle = NULL; + ape_tag tag; + TitleInput *ti; + + ti = (TitleInput *) g_malloc0(sizeof(TitleInput)); + ti->__size = XMMS_TITLEINPUT_SIZE; + ti->__version = XMMS_TITLEINPUT_VERSION; + + ti->file_name = g_strdup(g_basename(fn)); + ti->file_ext = "wv"; + + load_tag(&tag, ctx); + + // xmms doesn't support unicode... + ti->track_name = convertUTF8toLocale(tag.title); + ti->performer = convertUTF8toLocale(tag.artist); + ti->album_name = convertUTF8toLocale(tag.album); + ti->date = convertUTF8toLocale(tag.year); + ti->track_number = atoi(tag.track); + if (ti->track_number < 0) + ti->track_number = 0; + ti->year = atoi(tag.year); + if (ti->year < 0) + ti->year = 0; + ti->genre = convertUTF8toLocale(tag.genre); + ti->comment = convertUTF8toLocale(tag.comment); + + displaytitle = xmms_get_titlestring(xmms_get_gentitle_format(), ti); + if (!displaytitle || *displaytitle == '\0' + || (strlen(tag.title) == 0 && strlen(tag.artist) == 0)) + displaytitle = ti->file_name; + g_free(ti->track_name); + g_free(ti->performer); + g_free(ti->album_name); + g_free(ti->genre); + g_free(ti->comment); + g_free(ti); + + return displaytitle; +} + +static void +wv_get_song_info(char *filename, char **title, int *length) +{ + assert(filename != NULL); + char error_buff[4096]; // TODO: fixme! + WavpackContext *ctx = WavpackOpenFileInput(filename, error_buff, OPEN_TAGS | OPEN_WVC, 0); + if (ctx == NULL) { + printf("wavpack: Error opening file: \"%s: %s\"\n", filename, error_buff); + return; + } + int sample_rate = WavpackGetSampleRate(ctx); + int num_channels = WavpackGetNumChannels(ctx); + DBG("reading %s at %d rate with %d channels\n", filename, sample_rate, num_channels); + + *length = (int)(WavpackGetNumSamples(ctx) / sample_rate) * 1000, + *title = generate_title(filename, ctx); + DBG("title for %s = %s\n", filename, *title); + WavpackCloseFile(ctx); +} + +static int +wv_get_time(void) +{ + if (!mod.output) + return -1; + if (AudioError) + return -2; + if (killDecodeThread && !mod.output->buffer_playing()) + return -1; + return mod.output->output_time(); +} + + +static void +wv_seek(int sec) +{ + isSeek = sec; + mod.output->flush((int) (1000 * isSeek)); +} + +static void +wv_pause(short pause) +{ + mod.output->pause(paused = pause); +} + +static void +wv_stop(void) +{ + killDecodeThread = true; + if (thread_handle != 0) { + g_thread_join(thread_handle); + if (openedAudio) { + mod.output->buffer_free(); + mod.output->close_audio(); + } + openedAudio = false; + if (AudioError) + printf("Could not open Audio\n"); + } + +} + +static void +wv_load_config() +{ + ConfigDb *cfg; + + cfg = bmp_cfg_db_open(); + + bmp_cfg_db_get_bool(cfg, "wavpack", "clip_prevention", + &clipPreventionEnabled); + bmp_cfg_db_get_bool(cfg, "wavpack", "album_replaygain", + &albumReplaygainEnabled); + bmp_cfg_db_get_bool(cfg, "wavpack", "dyn_bitrate", &dynBitrateEnabled); + bmp_cfg_db_get_bool(cfg, "wavpack", "replaygain", &replaygainEnabled); + bmp_cfg_db_close(cfg); + + openedAudio = false; +} diff -r 0eb1e99b7748 -r 38ce41606f10 src/wavpack/tags.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wavpack/tags.cxx Tue Oct 24 19:03:53 2006 -0700 @@ -0,0 +1,537 @@ +#include +#include +#include +#include +#include +#include +#include +#include "tags.h" + +struct APETagFooterStruct { + unsigned char ID[8]; + unsigned char Version[4]; + unsigned char Length[4]; + unsigned char TagCount[4]; + unsigned char Flags[4]; + unsigned char Reserved[8]; +}; + +typedef struct { + char *key; + size_t keylen; + unsigned char *value; + size_t valuelen; + unsigned int flags; +} TagItem; + +unsigned long +Read_LE_Uint32(const unsigned char *p) +{ + return ((unsigned long) p[0] << 0) | + ((unsigned long) p[1] << 8) | + ((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24); +} + +// Convert UTF-8 coded string to UNICODE +// Return number of characters converted +int +utf8ToUnicode(const char *lpMultiByteStr, wchar_t * lpWideCharStr, + int cmbChars) +{ + const unsigned char *pmb = (unsigned char *) lpMultiByteStr; + unsigned short *pwc = (unsigned short *) lpWideCharStr; + const unsigned char *pmbe; + size_t cwChars = 0; + + if (cmbChars >= 0) { + pmbe = pmb + cmbChars; + } + else { + pmbe = NULL; + } + + while ((pmbe == NULL) || (pmb < pmbe)) { + char mb = *pmb++; + unsigned int cc = 0; + unsigned int wc; + + while ((cc < 7) && (mb & (1 << (7 - cc)))) { + cc++; + } + + if (cc == 1 || cc > 6) // illegal character combination for UTF-8 + continue; + + if (cc == 0) { + wc = mb; + } + else { + wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6); + while (--cc > 0) { + if (pmb == pmbe) // reached end of the buffer + return cwChars; + mb = *pmb++; + if (((mb >> 6) & 0x03) != 2) // not part of multibyte character + return cwChars; + wc |= (mb & 0x3F) << ((cc - 1) * 6); + } + } + + if (wc & 0xFFFF0000) + wc = L'?'; + *pwc++ = wc; + cwChars++; + if (wc == L'\0') + return cwChars; + } + + return cwChars; +} + +void +tag_insert(char *buffer, const char *value, long unsigned int len, + long unsigned int maxlen, bool decode_utf8) +{ + char *p; + wchar_t wValue[MAX_LEN]; + char temp[MAX_LEN]; + long unsigned int c; + const wchar_t *src = wValue; + + if (len >= maxlen) + len = maxlen - 1; + if (decode_utf8) { + if ((c = utf8ToUnicode(value, wValue, len)) <= 0) + return; + if (wValue[c] != L'\0') + wValue[c++] = L'\0'; + if ((c = wcsrtombs(temp, &src, MAX_LEN, NULL)) == 0) + return; + } + else { + c = len; + strncpy(temp, value, len); + while (temp[len - 1] == 0x20 || len < 1) { + len--; + } + temp[len] = '\0'; + } + + //if ( *buffer == '\0' ) { // new value + p = buffer; + //} else { // append to existing value + // p = strchr (buffer, '\0' ); + // p += sprintf ( p, ", " ); + //} + + if ((p - buffer) + c >= maxlen) + c = maxlen - (p - buffer) - 1; + strncpy(p, temp, c); + p[c] = '\0'; +} + +// Returns the Type of Tag (Ape or ID3) +int +GetTageType(FILE * fp) +{ + struct APETagFooterStruct T; + unsigned char tagheader[3]; + int size; + + if (fp == NULL) { + return TAG_NONE; + } + + if (fseek(fp, 0, SEEK_END) != 0) + return TAG_NONE; + size = ftell(fp); + if (fseek(fp, size - sizeof T, SEEK_SET) != 0) + return TAG_NONE; + if (fread(&T, 1, sizeof T, fp) != sizeof T) + return TAG_NONE; + if (memcmp(T.ID, "APETAGEX", sizeof T.ID) == 0) + return TAG_APE; + if (fseek(fp, -128L, SEEK_END) != 0) + return TAG_NONE; + if (fread(tagheader, 1, 3, fp) != 3) + return TAG_NONE; + if (0 == memcmp(tagheader, "TAG", 3)) + return TAG_ID3; + return TAG_NONE; +} + + +int +ReadID3Tag(FILE * fp, ape_tag * Tag) +{ + char *tag; + char *buff; + unsigned int genre; + + buff = (char *) malloc(128); + + *(Tag->title) = '\0'; + *(Tag->artist) = '\0'; + *(Tag->album) = '\0'; + *(Tag->comment) = '\0'; + *(Tag->genre) = '\0'; + *(Tag->track) = '\0'; + *(Tag->year) = '\0'; + + if (fseek(fp, -128L, SEEK_END) != 0) + return 0; + if (fread(buff, 1, 128, fp) != 128) + return 0; + tag = buff; + tag_insert(Tag->title, (tag + 3), 30, 32, false); + tag_insert(Tag->artist, (tag + 33), 30, 32, false); + tag_insert(Tag->album, (tag + 63), 30, 32, false); + tag_insert(Tag->year, (tag + 93), 4, 32, false); + tag_insert(Tag->comment, (tag + 97), 30, 32, false); + genre = (unsigned char) tag[127]; + if (genre >= sizeof(GenreList) / sizeof(int)) + genre = 12; + tag_insert(Tag->genre, GenreList[genre], 30, 32, false); + sprintf(tag, "%u", tag[126]); + tag_insert(Tag->track, tag, 30, 32, false); + free(buff); + return 1; +} + +// Reads APE v2.0 tag +int +ReadAPE2Tag(FILE * fp, ape_tag * Tag) +{ + unsigned long vsize; + unsigned long isize; + unsigned long flags; + unsigned char *buff; + unsigned char *p; + unsigned char *end; + struct APETagFooterStruct T; + unsigned long TagLen; + unsigned long TagCount; + long size; + + *(Tag->title) = '\0'; + *(Tag->artist) = '\0'; + *(Tag->album) = '\0'; + *(Tag->comment) = '\0'; + *(Tag->genre) = '\0'; + *(Tag->track) = '\0'; + *(Tag->year) = '\0'; + + if (fseek(fp, 0, SEEK_END) != 0) + return 0; + size = ftell(fp); + if (fseek(fp, size - sizeof T, SEEK_SET) != 0) + return 0; + if (fread(&T, 1, sizeof T, fp) != sizeof T) + return 0; + if (memcmp(T.ID, "APETAGEX", sizeof T.ID) != 0) + return 0; + if (Read_LE_Uint32(T.Version) != 2000) + return 0; + TagLen = Read_LE_Uint32(T.Length); + if (TagLen < sizeof T) + return 0; + if (fseek(fp, size - TagLen, SEEK_SET) != 0) + return 0; + if ((buff = (unsigned char *) malloc(TagLen)) == NULL) + return 0; + if (fread(buff, 1, TagLen - sizeof T, fp) != TagLen - sizeof T) { + free(buff); + return 0; + } + + TagCount = Read_LE_Uint32(T.TagCount); + end = buff + TagLen - sizeof(T); + for (p = buff; p < end && TagCount--;) { + vsize = Read_LE_Uint32(p); + p += 4; + flags = Read_LE_Uint32(p); + p += 4; + isize = strlen((char *) p); + + if (isize > 0 && vsize > 0) { + if (!(flags & 1 << 1)) { // insert UTF-8 string (skip binary values) + if (!strcasecmp((char *) p, "Title")) { + tag_insert(Tag->title, (char *) (p + isize + 1), vsize, + MAX_LEN, false); + } + else if (!strcasecmp((char *) p, "Artist")) { + tag_insert(Tag->artist, (char *) (p + isize + 1), vsize, + MAX_LEN, false); + } + else if (!strcasecmp((char *) p, "Album")) { + tag_insert(Tag->album, (char *) (p + isize + 1), vsize, + MAX_LEN, false); + } + else if (!strcasecmp((char *) p, "Comment")) { + tag_insert(Tag->comment, (char *) (p + isize + 1), vsize, + MAX_LEN, false); + } + else if (!strcasecmp((char *) p, "Genre")) { + tag_insert(Tag->genre, (char *) (p + isize + 1), vsize, + MAX_LEN, false); + } + else if (!strcasecmp((char *) p, "Track")) { + tag_insert(Tag->track, (char *) (p + isize + 1), vsize, + 128, false); + } + else if (!strcasecmp((char *) p, "Year")) { + tag_insert(Tag->year, (char *) (p + isize + 1), vsize, + 128, false); + } + } + } + p += isize + 1 + vsize; + } + free(buff); + return 1; +} + +int +DeleteTag(char *filename) +{ + + FILE *fp = fopen(filename, "rb+"); + int tagtype; + int fd; + long filelength = 0; + long dellength = -1; + char *tagheader; + unsigned long *apelength; + int res = -1; + + if (fp == NULL) { + char text[256]; + + sprintf(text, "File \"%s\" not found or is read protected!\n", + filename); + xmms_show_message("File-Error", (gchar *) text, "Ok", FALSE, NULL, + NULL); + return -1; + } + tagtype = GetTageType(fp); + + // get Length of File + fseek(fp, 0L, SEEK_END); + filelength = ftell(fp); + + apelength = (unsigned long *) malloc(4); + tagheader = (char *) malloc(9); + + if (tagtype == TAG_ID3) { + dellength = 128L; + } + else if (tagtype == TAG_APE) { + fseek(fp, -32L, SEEK_END); + fread(tagheader, 8, 1, fp); + if (0 == memcmp(tagheader, "APETAGEX", 8)) { + fseek(fp, -20L, SEEK_END); + fread(apelength, 4, 1, fp); + dellength = *apelength + 32; + } + } + + + if (dellength > -1) //if TAG was found, delete it + { + fd = open(filename, O_RDWR); + res = ftruncate(fd, (off_t) (filelength - dellength)); + close(fd); + } + + free(tagheader); + free(apelength); + + //returns 0 if everything is ok + return res; +} + +// Returns bytes used in APE-Tag for this value +int +addValue(TagItem * item, char *key, char *value) +{ + item->keylen = strlen(key); + item->valuelen = strlen(value); + item->key = (char *) malloc(item->keylen + 1); + item->value = (unsigned char *) malloc(item->valuelen + 1); + strcpy((char *) item->value, value); + strcpy(item->key, key); + item->flags = 0; + return (9 + item->keylen + item->valuelen); +} + +int +WriteAPE2Tag(char *filename, ape_tag * Tag) +{ + FILE *fp; + unsigned char H[32] = "APETAGEX"; + unsigned long Version = 2000; + unsigned char dw[8]; + unsigned long estimatedbytes = 32; // 32 byte footer + all items, these are the 32 bytes footer, the items are added later + long writtenbytes = -32; // actually writtenbytes-32, which should be equal to estimatedbytes (= footer + all items) + unsigned int TagCount = 0; + TagItem T[7]; + + + // Delete Tag if there is one + fp = fopen(filename, "rb+"); + if (fp == NULL) { + char text[256]; + + sprintf(text, "File \"%s\" not found or is read protected!\n", + filename); + xmms_show_message("File-Error", (gchar *) text, "Ok", FALSE, NULL, + NULL); + return -1; + } + + int tagtype = GetTageType(fp); + + if (tagtype != TAG_NONE) + if (DeleteTag(filename) != 0) + return 0; + + // Produce TagItem-Array + if (strlen(Tag->title) > 0) { + char *value = (char *) malloc(strlen(Tag->title) + 1); + + strcpy(value, Tag->title); + int res = addValue(&T[TagCount], "Title", value); + + estimatedbytes += res; + if (res > 0) + TagCount++; + free(value); + } + + if (strlen(Tag->artist) > 0) { + char *value = (char *) malloc(strlen(Tag->artist) + 1); + + strcpy(value, Tag->artist); + int res = addValue(&T[TagCount], "Artist", value); + + estimatedbytes += res; + if (res > 0) + TagCount++; + free(value); + } + + if (strlen(Tag->album) > 0) { + char *value = (char *) malloc(strlen(Tag->album) + 1); + + strcpy(value, Tag->album); + int res = addValue(&T[TagCount], "Album", value); + + estimatedbytes += res; + if (res > 0) + TagCount++; + free(value); + } + + if (strlen(Tag->comment) > 0) { + char *value = (char *) malloc(strlen(Tag->comment) + 1); + + strcpy(value, Tag->comment); + int res = addValue(&T[TagCount], "Comment", value); + + estimatedbytes += res; + if (res > 0) + TagCount++; + free(value); + } + + if (strlen(Tag->genre) > 0) { + char *value = (char *) malloc(strlen(Tag->genre) + 1); + + strcpy(value, Tag->genre); + int res = addValue(&T[TagCount], "Genre", value); + + estimatedbytes += res; + if (res > 0) + TagCount++; + free(value); + } + + if (strlen(Tag->track) > 0) { + char *value = (char *) malloc(strlen(Tag->track) + 1); + + strcpy(value, Tag->track); + int res = addValue(&T[TagCount], "Track", value); + + estimatedbytes += res; + if (res > 0) + TagCount++; + free(value); + } + + if (strlen(Tag->year) > 0) { + char *value = (char *) malloc(strlen(Tag->year) + 1); + + strcpy(value, Tag->year); + int res = addValue(&T[TagCount], "Year", value); + + estimatedbytes += res; + if (res > 0) + TagCount++; + free(value); + } + // Start writing the new Ape2 Tag + fseek(fp, 0L, SEEK_END); + + if (TagCount == 0) { + printf("no tag to write"); + return 0; + } + + if (estimatedbytes >= 8192 + 103) { + printf + ("\nTag is %.1f Kbyte long. This is longer than the maximum recommended 8 KByte.\n\a", + estimatedbytes / 1024.); + return 0; + } + + H[8] = Version >> 0; + H[9] = Version >> 8; + H[10] = Version >> 16; + H[11] = Version >> 24; + H[12] = estimatedbytes >> 0; + H[13] = estimatedbytes >> 8; + H[14] = estimatedbytes >> 16; + H[15] = estimatedbytes >> 24; + H[16] = TagCount >> 0; + H[17] = TagCount >> 8; + H[18] = TagCount >> 16; + H[19] = TagCount >> 24; + + H[23] = 0x80 | 0x20; + writtenbytes += fwrite(H, 1, 32, fp); + + for (unsigned int i = 0; i < TagCount; i++) { + dw[0] = T[i].valuelen >> 0; + dw[1] = T[i].valuelen >> 8; + dw[2] = T[i].valuelen >> 16; + dw[3] = T[i].valuelen >> 24; + dw[4] = T[i].flags >> 0; + dw[5] = T[i].flags >> 8; + dw[6] = T[i].flags >> 16; + dw[7] = T[i].flags >> 24; + writtenbytes += fwrite(dw, 1, 8, fp); + writtenbytes += fwrite(T[i].key, 1, T[i].keylen, fp); + writtenbytes += fwrite("", 1, 1, fp); + if (T[i].valuelen > 0) + writtenbytes += fwrite(T[i].value, 1, T[i].valuelen, fp); + } + + H[23] = 0x80; + writtenbytes += fwrite(H, 1, 32, fp); + + if (estimatedbytes != (unsigned long) writtenbytes) + printf("\nError writing APE tag.\n"); + fclose(fp); + TagCount = 0; + return 0; +} diff -r 0eb1e99b7748 -r 38ce41606f10 src/wavpack/tags.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wavpack/tags.h Tue Oct 24 19:03:53 2006 -0700 @@ -0,0 +1,63 @@ +#ifndef _tags_h +#define _tags_h + +#include + +const int MAX_LEN = 2048; +const int TAG_NONE = 0; +const int TAG_ID3 = 1; +const int TAG_APE = 2; + +typedef struct { + char title [MAX_LEN]; + char artist [MAX_LEN]; + char album [MAX_LEN]; + char comment [MAX_LEN]; + char genre [MAX_LEN]; + char track [128]; + char year [128]; + int _genre; +} ape_tag; + +static const char* GenreList [] = { + "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", + "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", + "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", + "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", + "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", + "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", + "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", + "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", + "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", + "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", + "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", + "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", + "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", + "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", + "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", + "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", + "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", + "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", + "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", + "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", + "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", + "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", + "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", + "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", + "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", + "SynthPop" +}; + +int utf8ToUnicode ( const char* lpMultiByteStr, wchar_t* lpWideCharStr, int cmbChars ); + +int GetTageType ( FILE *fp ); + +int DeleteTag ( char* filename); + +int WriteAPE2Tag ( char* fp, ape_tag *Tag ); + +int ReadAPE2Tag ( FILE *fp, ape_tag *Tag ); + +int ReadID3Tag ( FILE *fp, ape_tag *Tag ); + +#endif diff -r 0eb1e99b7748 -r 38ce41606f10 src/wavpack/ui.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wavpack/ui.cxx Tue Oct 24 19:03:53 2006 -0700 @@ -0,0 +1,568 @@ +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +#include +#include +#include +} +#include +#include +#include +#include +#include "tags.h" +#ifndef M_LN10 +#define M_LN10 2.3025850929940456840179914546843642 +#endif + +#define DBG(format, args...) fprintf(stderr, format, ## args) + +void load_tag(ape_tag *tag, WavpackContext *ctx); +gboolean clipPreventionEnabled; +gboolean dynBitrateEnabled; +gboolean replaygainEnabled; +gboolean albumReplaygainEnabled; +gboolean openedAudio; +static GtkWidget *window = NULL; +static GtkWidget *title_entry; +static GtkWidget *album_entry; +static GtkWidget *performer_entry; +static GtkWidget *tracknumber_entry; +static GtkWidget *date_entry; +static GtkWidget *genre_entry; +static GtkWidget *user_comment_entry; +static char *filename; + +void +wv_about_box() +{ + static GtkWidget *about_window; + + if (about_window) + gdk_window_raise(about_window->window); + + about_window = + xmms_show_message(g_strdup_printf + ("Wavpack Decoder Plugin %s", VERSION), + ("Plugin code by \n" "Miles Egan\n" + "Adapted from xmms-musepack plugin by Lefungus\n" + "Visit the Wavpack site at http://www.wavpack.com/\n"), + ("Ok"), FALSE, NULL, NULL); + gtk_signal_connect(GTK_OBJECT(about_window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), &about_window); +} + +static void +label_set_text(GtkWidget * label, char *str, ...) +{ + va_list args; + gchar *tempstr; + + va_start(args, str); + tempstr = g_strdup_vprintf(str, args); + va_end(args); + + gtk_label_set_text(GTK_LABEL(label), tempstr); + g_free(tempstr); +} + +static void +remove_cb(GtkWidget * w, gpointer data) +{ + DeleteTag(filename); + g_free(filename); + gtk_widget_destroy(window); +} + +static void +save_cb(GtkWidget * w, gpointer data) +{ + ape_tag Tag; + + strcpy(Tag.title, gtk_entry_get_text(GTK_ENTRY(title_entry))); + strcpy(Tag.artist, gtk_entry_get_text(GTK_ENTRY(performer_entry))); + strcpy(Tag.album, gtk_entry_get_text(GTK_ENTRY(album_entry))); + strcpy(Tag.comment, gtk_entry_get_text(GTK_ENTRY(user_comment_entry))); + strcpy(Tag.track, gtk_entry_get_text(GTK_ENTRY(tracknumber_entry))); + strcpy(Tag.year, gtk_entry_get_text(GTK_ENTRY(date_entry))); + strcpy(Tag.genre, gtk_entry_get_text(GTK_ENTRY(genre_entry))); + WriteAPE2Tag(filename, &Tag); + g_free(filename); + gtk_widget_destroy(window); +} + +static void +close_window(GtkWidget * w, gpointer data) +{ + g_free(filename); + gtk_widget_destroy(window); +} + +void +wv_file_info_box(char *fn) +{ + gchar *tmp; + gint time, minutes, seconds; + ape_tag tag; + + assert(fn != NULL); + char error_buff[4096]; // TODO: fixme! + WavpackContext *ctx = WavpackOpenFileInput(fn, error_buff, OPEN_TAGS | OPEN_WVC, 0); + if (ctx == NULL) { + printf("wavpack: Error opening file: \"%s: %s\"\n", fn, error_buff); + return; + } + int sample_rate = WavpackGetSampleRate(ctx); + int num_channels = WavpackGetNumChannels(ctx); + load_tag(&tag, ctx); + DBG("opened %s at %d rate with %d channels\n", fn, sample_rate, num_channels); + + filename = g_strdup(fn); + static GtkWidget *info_frame, *info_box, *bitrate_label, *rate_label; + static GtkWidget *version_label, *bits_per_sample_label; + static GtkWidget *channel_label, *length_label, *filesize_label; + static GtkWidget *peakTitle_label, *peakAlbum_label, *gainTitle_label; + static GtkWidget *gainAlbum_label, *filename_entry, *tag_frame; + + if (!window) { + GtkWidget *hbox, *label, *filename_hbox, *vbox, *left_vbox; + GtkWidget *table, *bbox, *cancel_button; + GtkWidget *save_button, *remove_button; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window); + gtk_container_set_border_width(GTK_CONTAINER(window), 10); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(window), vbox); + + filename_hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0); + + label = gtk_label_new("Filename:"); + gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0); + filename_entry = gtk_entry_new(); + gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE); + gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, + TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + + left_vbox = gtk_vbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0); + + tag_frame = gtk_frame_new("Ape2 Tag"); + gtk_box_pack_start(GTK_BOX(left_vbox), tag_frame, FALSE, FALSE, 0); + + table = gtk_table_new(5, 5, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_container_add(GTK_CONTAINER(tag_frame), table); + + label = gtk_label_new("Title:"); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + GTK_FILL, GTK_FILL, 5, 5); + + title_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), 0, 5); + + label = gtk_label_new("Artist:"); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, + GTK_FILL, GTK_FILL, 5, 5); + + performer_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), performer_entry, 1, 4, 1, 2, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), 0, 5); + + label = gtk_label_new("Album:"); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, + GTK_FILL, GTK_FILL, 5, 5); + + album_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), 0, 5); + + label = gtk_label_new("Comment:"); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, + GTK_FILL, GTK_FILL, 5, 5); + + user_comment_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), user_comment_entry, 1, 4, 3, + 4, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), 0, 5); + + label = gtk_label_new("Year:"); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, + GTK_FILL, GTK_FILL, 5, 5); + + date_entry = gtk_entry_new(); + gtk_widget_set_usize(date_entry, 60, -1); + gtk_table_attach(GTK_TABLE(table), date_entry, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), 0, 5); + + label = gtk_label_new("Track n°:"); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, + GTK_FILL, GTK_FILL, 5, 5); + + tracknumber_entry = gtk_entry_new_with_max_length(4); + gtk_widget_set_usize(tracknumber_entry, 20, -1); + gtk_table_attach(GTK_TABLE(table), tracknumber_entry, 3, 4, 4, + 5, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), 0, 5); + + label = gtk_label_new("Genre:"); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, + GTK_FILL, GTK_FILL, 5, 5); + + genre_entry = gtk_entry_new(); + gtk_widget_set_usize(genre_entry, 20, -1); + gtk_table_attach(GTK_TABLE(table), genre_entry, 1, 4, 5, + 6, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | + GTK_SHRINK), 0, 5); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0); + + save_button = gtk_button_new_with_label("Save"); + gtk_signal_connect(GTK_OBJECT(save_button), "clicked", + GTK_SIGNAL_FUNC(save_cb), NULL); + GTK_WIDGET_SET_FLAGS(save_button, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), save_button, TRUE, TRUE, 0); + + remove_button = gtk_button_new_with_label("Remove Tag"); + gtk_signal_connect_object(GTK_OBJECT(remove_button), + "clicked", + GTK_SIGNAL_FUNC(remove_cb), NULL); + GTK_WIDGET_SET_FLAGS(remove_button, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), remove_button, TRUE, TRUE, 0); + + cancel_button = gtk_button_new_with_label("Cancel"); + gtk_signal_connect_object(GTK_OBJECT(cancel_button), + "clicked", + GTK_SIGNAL_FUNC(close_window), NULL); + GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0); + gtk_widget_grab_default(cancel_button); + + info_frame = gtk_frame_new("Wavpack Info:"); + gtk_box_pack_start(GTK_BOX(hbox), info_frame, FALSE, FALSE, 0); + + info_box = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(info_frame), info_box); + gtk_container_set_border_width(GTK_CONTAINER(info_box), 10); + gtk_box_set_spacing(GTK_BOX(info_box), 0); + + version_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(version_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(version_label), + GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), version_label, FALSE, + FALSE, 0); + + bits_per_sample_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(bits_per_sample_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(bits_per_sample_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), bits_per_sample_label, FALSE, FALSE, 0); + + bitrate_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(bitrate_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(bitrate_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), bitrate_label, FALSE, FALSE, 0); + + rate_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(rate_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(rate_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), rate_label, FALSE, FALSE, 0); + + channel_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(channel_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(channel_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), channel_label, FALSE, FALSE, 0); + + length_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(length_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(length_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), length_label, FALSE, FALSE, 0); + + filesize_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(filesize_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(filesize_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), filesize_label, FALSE, + FALSE, 0); + + peakTitle_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(peakTitle_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(peakTitle_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), peakTitle_label, FALSE, + FALSE, 0); + + peakAlbum_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(peakAlbum_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(peakAlbum_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), peakAlbum_label, FALSE, + FALSE, 0); + + gainTitle_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(gainTitle_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(gainTitle_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), gainTitle_label, FALSE, + FALSE, 0); + + gainAlbum_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(gainAlbum_label), 0, 0); + gtk_label_set_justify(GTK_LABEL(gainAlbum_label), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(info_box), gainAlbum_label, FALSE, + FALSE, 0); + + gtk_widget_show_all(window); + } + else + gdk_window_raise(window->window); + + gtk_widget_set_sensitive(tag_frame, TRUE); + + gtk_label_set_text(GTK_LABEL(version_label), ""); + gtk_label_set_text(GTK_LABEL(bits_per_sample_label), ""); + gtk_label_set_text(GTK_LABEL(bitrate_label), ""); + gtk_label_set_text(GTK_LABEL(rate_label), ""); + gtk_label_set_text(GTK_LABEL(channel_label), ""); + gtk_label_set_text(GTK_LABEL(length_label), ""); + gtk_label_set_text(GTK_LABEL(filesize_label), ""); + gtk_label_set_text(GTK_LABEL(peakTitle_label), ""); + gtk_label_set_text(GTK_LABEL(peakAlbum_label), ""); + gtk_label_set_text(GTK_LABEL(gainTitle_label), ""); + gtk_label_set_text(GTK_LABEL(gainAlbum_label), ""); + + time = WavpackGetNumSamples(ctx) / WavpackGetSampleRate(ctx); + minutes = time / 60; + seconds = time % 60; + + label_set_text(version_label, "version %d", WavpackGetVersion(ctx)); + label_set_text(bitrate_label, "average bitrate: %6.1f kbps", WavpackGetAverageBitrate(ctx, 0) / 1000); + label_set_text(rate_label, "samplerate: %d Hz", WavpackGetSampleRate(ctx)); + label_set_text(bits_per_sample_label, "bits per sample: %d", WavpackGetBitsPerSample(ctx)); + label_set_text(channel_label, "channels: %d", WavpackGetNumChannels(ctx)); + label_set_text(length_label, "length: %d:%.2d", minutes, seconds); + label_set_text(filesize_label, "file size: %d Bytes", WavpackGetFileSize(ctx)); + /* + label_set_text(peakTitle_label, "Title Peak: %5u", 100); + label_set_text(peakAlbum_label, "Album Peak: %5u", 100); + label_set_text(gainTitle_label, "Title Gain: %-+5.2f dB", 100.0); + label_set_text(gainAlbum_label, "Album Gain: %-+5.2f dB", 100.0); + */ + label_set_text(peakTitle_label, "Title Peak: ?"); + label_set_text(peakAlbum_label, "Album Peak: ?"); + label_set_text(gainTitle_label, "Title Gain: ?"); + label_set_text(gainAlbum_label, "Album Gain: ?"); + + gtk_entry_set_text(GTK_ENTRY(title_entry), tag.title); + gtk_entry_set_text(GTK_ENTRY(performer_entry), tag.artist); + gtk_entry_set_text(GTK_ENTRY(album_entry), tag.album); + gtk_entry_set_text(GTK_ENTRY(user_comment_entry), tag.comment); + gtk_entry_set_text(GTK_ENTRY(genre_entry), tag.genre); + gtk_entry_set_text(GTK_ENTRY(tracknumber_entry), tag.track); + gtk_entry_set_text(GTK_ENTRY(date_entry), tag.year); + gtk_entry_set_text(GTK_ENTRY(filename_entry), fn); + gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1); + + tmp = g_strdup_printf("File Info - %s", g_basename(fn)); + gtk_window_set_title(GTK_WINDOW(window), tmp); + g_free(tmp); +} + +static GtkWidget *wv_configurewin = NULL; +static GtkWidget *vbox, *notebook; +static GtkWidget *rg_switch, *rg_clip_switch, *rg_track_gain, *rg_dyn_bitrate; + +static void +wv_configurewin_ok(GtkWidget * widget, gpointer data) +{ + ConfigDb *cfg; + GtkToggleButton *tb; + + tb = GTK_TOGGLE_BUTTON(rg_switch); + replaygainEnabled = gtk_toggle_button_get_active(tb); + tb = GTK_TOGGLE_BUTTON(rg_clip_switch); + clipPreventionEnabled = gtk_toggle_button_get_active(tb); + tb = GTK_TOGGLE_BUTTON(rg_dyn_bitrate); + dynBitrateEnabled = gtk_toggle_button_get_active(tb); + tb = GTK_TOGGLE_BUTTON(rg_track_gain); + albumReplaygainEnabled = !gtk_toggle_button_get_active(tb); + + cfg = bmp_cfg_db_open(); + + bmp_cfg_db_set_bool(cfg, "wavpack", "clip_prevention", + clipPreventionEnabled); + bmp_cfg_db_set_bool(cfg, "wavpack", "album_replaygain", + albumReplaygainEnabled); + bmp_cfg_db_set_bool(cfg, "wavpack", "dyn_bitrate", dynBitrateEnabled); + bmp_cfg_db_set_bool(cfg, "wavpack", "replaygain", replaygainEnabled); + bmp_cfg_db_close(cfg); + gtk_widget_destroy(wv_configurewin); +} + +static void +rg_switch_cb(GtkWidget * w, gpointer data) +{ + gtk_widget_set_sensitive(GTK_WIDGET(data), + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON + (w))); +} + +void +wv_configure(void) +{ + + GtkWidget *rg_frame, *rg_vbox; + GtkWidget *bbox, *ok, *cancel; + GtkWidget *rg_type_frame, *rg_type_vbox, *rg_album_gain; + + if (wv_configurewin != NULL) { + gdk_window_raise(wv_configurewin->window); + return; + } + + wv_configurewin = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_signal_connect(GTK_OBJECT(wv_configurewin), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &wv_configurewin); + gtk_window_set_title(GTK_WINDOW(wv_configurewin), + "Musepack Configuration"); + gtk_window_set_policy(GTK_WINDOW(wv_configurewin), FALSE, FALSE, FALSE); + gtk_container_border_width(GTK_CONTAINER(wv_configurewin), 10); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(wv_configurewin), vbox); + + notebook = gtk_notebook_new(); + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + + /* Plugin Settings */ + + rg_frame = gtk_frame_new("General Plugin Settings:"); + gtk_container_border_width(GTK_CONTAINER(rg_frame), 5); + + rg_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(rg_vbox), 5); + gtk_container_add(GTK_CONTAINER(rg_frame), rg_vbox); + + rg_dyn_bitrate = + gtk_check_button_new_with_label("Enable Dynamic Bitrate Display"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rg_dyn_bitrate), + dynBitrateEnabled); + gtk_box_pack_start(GTK_BOX(rg_vbox), rg_dyn_bitrate, FALSE, FALSE, 0); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), rg_frame, + gtk_label_new("Plugin")); + + /* Replay Gain.. */ + + rg_frame = gtk_frame_new("ReplayGain Settings:"); + gtk_container_border_width(GTK_CONTAINER(rg_frame), 5); + + rg_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(rg_vbox), 5); + gtk_container_add(GTK_CONTAINER(rg_frame), rg_vbox); + + rg_clip_switch = + gtk_check_button_new_with_label("Enable Clipping Prevention"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rg_clip_switch), + clipPreventionEnabled); + gtk_box_pack_start(GTK_BOX(rg_vbox), rg_clip_switch, FALSE, FALSE, 0); + + rg_switch = gtk_check_button_new_with_label("Enable ReplayGain"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rg_switch), + replaygainEnabled); + gtk_box_pack_start(GTK_BOX(rg_vbox), rg_switch, FALSE, FALSE, 0); + + rg_type_frame = gtk_frame_new("ReplayGain Type:"); + gtk_box_pack_start(GTK_BOX(rg_vbox), rg_type_frame, FALSE, FALSE, 0); + + gtk_signal_connect(GTK_OBJECT(rg_switch), "toggled", + GTK_SIGNAL_FUNC(rg_switch_cb), rg_type_frame); + + rg_type_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(rg_type_vbox), 5); + gtk_container_add(GTK_CONTAINER(rg_type_frame), rg_type_vbox); + + rg_track_gain = + gtk_radio_button_new_with_label(NULL, "use Track Gain/Peak"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rg_track_gain), + !albumReplaygainEnabled); + gtk_box_pack_start(GTK_BOX(rg_type_vbox), rg_track_gain, FALSE, FALSE, 0); + + rg_album_gain = + gtk_radio_button_new_with_label(gtk_radio_button_group + (GTK_RADIO_BUTTON(rg_track_gain)), + "use Album Gain/Peak"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rg_album_gain), + albumReplaygainEnabled); + gtk_box_pack_start(GTK_BOX(rg_type_vbox), rg_album_gain, FALSE, FALSE, 0); + + gtk_widget_set_sensitive(rg_type_frame, replaygainEnabled); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), rg_frame, + gtk_label_new("ReplayGain")); + + /* Buttons */ + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(ok), "clicked", + GTK_SIGNAL_FUNC(wv_configurewin_ok), NULL); + GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); + gtk_widget_grab_default(ok); + + cancel = gtk_button_new_with_label("Cancel"); + gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(wv_configurewin)); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); + + gtk_widget_show_all(wv_configurewin); +}