Mercurial > audlegacy-plugins
diff src/tta/libtta.c @ 1012:d0d99b22e393 trunk
[svn] import major update by Aleksander Djuric (the original author).
- major code cleanups
- fix for badly playlist names
- remove unnecessary functions
- remove no-longer-needed files
author | yaz |
---|---|
date | Fri, 11 May 2007 01:15:39 -0700 |
parents | src/tta/aud-tta.c@5bd17596c7e9 |
children | 08979ba252ff |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tta/libtta.c Fri May 11 01:15:39 2007 -0700 @@ -0,0 +1,861 @@ +/* + * libtta.c + * + * Description: TTA input plug-in for Audacious + * Developed by: Alexander Djourik <ald@true-audio.com> + * Audacious port: Yoshiki Yazawa <yaz@cc.rim.or.jp> + * + * Copyright (c) 2007 Alexander Djourik. All rights reserved. + * + */ + +/* + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Please see the file COPYING in this directory for full copyright + * information. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <glib.h> +#include <pthread.h> +#include <string.h> + +#include <audacious/util.h> +#include <audacious/plugin.h> +#include <audacious/titlestring.h> +#include <audacious/vfs.h> +#include <audacious/output.h> +#include <audacious/strings.h> +#include <audacious/i18n.h> + +#include <audacious/id3tag.h> + +#define PLUGIN_VERSION "1.4" +#define PROJECT_URL "<http://www.true-audio.com>" + +#include "ttalib.h" + +#define OUTPUT_ERROR (MEMORY_ERROR+1) +#define MAX_BSIZE (MAX_BPS>>3) +#define BYTES(x) ((x) * sizeof(id3_ucs4_t)) + +static void init (); +static void cleanup (); +static int is_our_file (char *filename); +static void play_file (InputPlayback *playback); +static void tta_pause (InputPlayback *playback, short paused); +static void stop (InputPlayback *playback); +static void seek (InputPlayback *playback, int time); +static int get_time (InputPlayback *playback); +static void get_song_info (char *filename, char **title, int *length); +static void file_info (char *filename); +static void about (); +static TitleInput *get_song_tuple(char *filename); +static gchar *extname(const char *filename); + +static pthread_t decode_thread; +static char sample_buffer[PCM_BUFFER_LENGTH * MAX_BSIZE * MAX_NCH]; +static tta_info info; // currently playing file info +static int seek_position = -1; +static int playing = FALSE; +static int read_samples = -1; + +gchar *tta_fmts[] = { "tta", NULL }; + +InputPlugin tta_ip = +{ + NULL, + NULL, + NULL, + init, + about, + NULL, + is_our_file, + NULL, + play_file, + stop, + tta_pause, + seek, + NULL, + get_time, + NULL, + NULL, + cleanup, + NULL, + NULL, + NULL, + NULL, + get_song_info, + file_info, + NULL, + get_song_tuple, // get_song_tuple + NULL, // set_song_tuple + NULL, // buffer + NULL, // vfs + tta_fmts, +}; + +InputPlugin * +get_iplugin_info (void) +{ + tta_ip.description = g_strdup_printf ("True Audio Plugin %s", PLUGIN_VERSION); + return &tta_ip; +} + +size_t +file_size (char *filename) +{ + VFSFile *f; + size_t size = -1; + + if ((f = vfs_fopen (filename, "r"))) + { + vfs_fseek (f, 0, SEEK_END); + size = vfs_ftell (f); + vfs_fclose (f); + } + return size; +} + +static void +tta_error (int error) +{ + char *message; + static GtkWidget *errorbox; + if (errorbox != NULL) return; + + switch (error) + { + case OPEN_ERROR: + message = "Can't open file\n"; + break; + case FORMAT_ERROR: + message = "Not supported file format\n"; + break; + case FILE_ERROR: + message = "File is corrupted\n"; + break; + case READ_ERROR: + message = "Can't read from file\n"; + break; + case MEMORY_ERROR: + message = "Insufficient memory available\n"; + break; + case OUTPUT_ERROR: + message = "Output plugin error\n"; + break; + default: + message = "Unknown error\n"; + break; + } + + xmms_show_message ("TTA Decoder Error", message, + "Ok", FALSE, NULL, NULL); + + gtk_signal_connect(GTK_OBJECT(errorbox), "destroy", + G_CALLBACK(gtk_widget_destroyed), &errorbox); +} + +static gchar * +get_song_title(TitleInput *tuple) +{ + return xmms_get_titlestring(xmms_get_gentitle_format(), tuple); +} + +static void +get_song_info (char *filename, char **title, int *length) +{ + TitleInput *tuple; + + *length = -1; + *title = NULL; + + if ((tuple = get_song_tuple(filename)) != NULL) { + *length = tuple->length; + *title = get_song_title(tuple); + } + + bmp_title_input_free(tuple); +} + +static void * +play_loop (void *arg) +{ + InputPlayback *playback = arg; + int bufsize = PCM_BUFFER_LENGTH * info.BSIZE * info.NCH; + + //////////////////////////////////////// + // decode PCM_BUFFER_LENGTH samples + // into the current PCM buffer position + + while (playing) + { + while ((read_samples = get_samples (sample_buffer)) > 0) + { + + while ((playback->output->buffer_free () < bufsize) + && seek_position == -1) + { + if (!playing) + goto DONE; + xmms_usleep (10000); + } + + if (seek_position == -1) + { + produce_audio(playback->output->written_time(), + ((info.BPS == 8) ? FMT_U8 : FMT_S16_LE), + info.NCH, + read_samples * info.NCH * info.BSIZE, + sample_buffer, + NULL); + } + else + { + set_position (seek_position); + playback->output->flush (seek_position * SEEK_STEP); + seek_position = -1; + } + } + + playback->output->buffer_free (); + playback->output->buffer_free (); + xmms_usleep(10000); + } + +DONE: + //////////////////////// + // destroy memory pools + player_stop (); + + /////////////////////////////// + // close currently playing file + close_tta_file (&info); + + pthread_exit (NULL); +} + +static void +init () +{ + memset (&info, 0, sizeof (tta_info)); +} + +static void +cleanup () +{ +} + +static void +about () +{ + static GtkWidget *aboutbox; + if (aboutbox != NULL) return; + + aboutbox = xmms_show_message( + "About True Audio Plugin", + "TTA input plugin" PLUGIN_VERSION "for BMP\n" + "Copyright (c) 2004 True Audio Software\n" + PROJECT_URL, "Ok", FALSE, NULL, NULL); + + gtk_signal_connect(GTK_OBJECT(aboutbox), "destroy", + G_CALLBACK(gtk_widget_destroyed), &aboutbox); +} + +static GtkWidget *window = NULL; +static GtkWidget *filename_entry, *title_entry, + *artist_entry, *album_entry, + *year_entry, *tracknum_entry, + *comment_entry, *genre_entry, + *info_frame; + +static void +file_info (char *filename) +{ + tta_info ttainfo; + char *title; + gchar *utf_filename = NULL; + + if (!window) { + GtkWidget *vbox, *hbox, *left_vbox, *table; + GtkWidget *label, *filename_hbox, *button_ok; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + G_CALLBACK(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_with_max_length(1024); + 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); + + info_frame = gtk_frame_new("ID3 Tag:"); + gtk_box_pack_start(GTK_BOX(left_vbox), info_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(info_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_with_max_length(1024); + gtk_editable_set_editable(GTK_EDITABLE(title_entry), FALSE); + gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + 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); + + artist_entry = gtk_entry_new_with_max_length(1024); + gtk_editable_set_editable(GTK_EDITABLE(artist_entry), FALSE); + gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + 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_with_max_length(1024); + gtk_editable_set_editable(GTK_EDITABLE(album_entry), FALSE); + gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + 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); + + comment_entry = gtk_entry_new_with_max_length(1024); + gtk_editable_set_editable(GTK_EDITABLE(comment_entry), FALSE); + gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + 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); + + year_entry = gtk_entry_new_with_max_length(4); + gtk_editable_set_editable(GTK_EDITABLE(year_entry), FALSE); + gtk_widget_set_usize(year_entry, 40, -1); + gtk_table_attach(GTK_TABLE(table), year_entry, 1, 2, 4, 5, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new("Track number:"); + 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); + + tracknum_entry = gtk_entry_new_with_max_length(3); + gtk_editable_set_editable(GTK_EDITABLE(tracknum_entry), FALSE); + gtk_widget_set_usize(tracknum_entry, 40, -1); + gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + 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_with_max_length(1024); + gtk_editable_set_editable(GTK_EDITABLE(genre_entry), FALSE); + gtk_widget_set_usize(genre_entry, 40, -1); + gtk_table_attach(GTK_TABLE(table), genre_entry, 1, 4, 5, 6, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + button_ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect_object(GTK_OBJECT(button_ok), "clicked", + G_CALLBACK(gtk_widget_destroy), G_OBJECT(window)); + GTK_WIDGET_SET_FLAGS(button_ok, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(vbox), button_ok, TRUE, TRUE, 0); + + gtk_widget_show_all (window); + } + + utf_filename = str_to_utf8(filename); + title = g_strdup_printf(_("File Info - %s"), g_basename(utf_filename)); + gtk_window_set_title(GTK_WINDOW(window), title); + g_free(title); + + gtk_entry_set_text(GTK_ENTRY(filename_entry), utf_filename); + gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1); + + title = g_strdup(g_basename(utf_filename)); + gtk_entry_set_text(GTK_ENTRY(title_entry), title); + + g_free(title); + g_free(utf_filename); + + if (open_tta_file (filename, &ttainfo, 0) >= 0) + { + gtk_entry_set_text(GTK_ENTRY(title_entry), ttainfo.ID3.title); + gtk_entry_set_text(GTK_ENTRY(artist_entry), ttainfo.ID3.artist); + gtk_entry_set_text(GTK_ENTRY(album_entry), ttainfo.ID3.album); + gtk_entry_set_text(GTK_ENTRY(year_entry), ttainfo.ID3.year); + gtk_entry_set_text(GTK_ENTRY(tracknum_entry), ttainfo.ID3.track); + gtk_entry_set_text(GTK_ENTRY(comment_entry), ttainfo.ID3.comment); + gtk_entry_set_text(GTK_ENTRY(genre_entry), ttainfo.ID3.genre); + } + close_tta_file (&ttainfo); + + gtk_widget_set_sensitive(info_frame, TRUE); +} + +static int +is_our_file (char *filename) +{ + gchar *ext = strrchr(filename, '.'); + + if (!strncasecmp(ext, ".tta", 4)) + return TRUE; + + return FALSE; +} + +static void +play_file (InputPlayback *playback) +{ + char *filename = playback->filename; + char *title; + int datasize, origsize, bitrate; + TitleInput *tuple = NULL; + + playing = FALSE; + + //////////////////////////////////////// + // open TTA file + if (open_tta_file (filename, &info, 0) < 0) + { + tta_error (info.STATE); + close_tta_file (&info); + return; + } + + //////////////////////////////////////// + // initialize TTA player + if (player_init (&info) < 0) + { + tta_error (info.STATE); + close_tta_file (&info); + return; + } + + if (playback->output->open_audio ((info.BPS == 8) ? FMT_U8 : FMT_S16_LE, + info.SAMPLERATE, info.NCH) == 0) + { + tta_error (OUTPUT_ERROR); + close_tta_file (&info); + return; + } + + tuple = get_song_tuple(filename); + title = get_song_title(tuple); + bmp_title_input_free(tuple); + + datasize = file_size(filename) - info.DATAPOS; + origsize = info.DATALENGTH * info.BSIZE * info.NCH; + + bitrate = (int) ((float) datasize / origsize * + (info.SAMPLERATE * info.NCH * info.BPS)); + + tta_ip.set_info (title, 1000 * info.LENGTH, bitrate, info.SAMPLERATE, info.NCH); + + if (title) + g_free (title); + + playing = TRUE; + seek_position = -1; + read_samples = -1; + + pthread_create (&decode_thread, NULL, play_loop, playback); +} + +static void +tta_pause (InputPlayback *playback, short paused) +{ + playback->output->pause (paused); +} + +static void +stop (InputPlayback *playback) +{ + if (playing) + { + playing = FALSE; + pthread_join (decode_thread, NULL); + playback->output->close_audio (); + close_tta_file (&info); + read_samples = 0; + } +} + +static void +seek (InputPlayback *data, int time) +{ + if (playing) + { + seek_position = 1000 * time / SEEK_STEP; + + while (seek_position != -1) + xmms_usleep (10000); + } +} + +static int +get_time (InputPlayback *playback) +{ + if (playing && (read_samples || playback->output->buffer_playing())) + return playback->output->output_time(); + + return -1; +} + +static TitleInput * +get_song_tuple(char *filename) +{ + TitleInput *tuple = NULL; + tta_info *ttainfo; + VFSFile *file; + + ttainfo = g_malloc0(sizeof(tta_info)); + + if((file = vfs_fopen(filename, "rb")) != NULL) { + if(open_tta_file(filename, ttainfo, 0) >= 0) { + tuple = bmp_title_input_new(); + + tuple->file_name = g_path_get_basename(filename); + tuple->file_path = g_path_get_dirname(filename); + tuple->file_ext = extname(filename); + tuple->length = ttainfo->LENGTH * 1000; + + if (ttainfo->ID3.id3has) { + if(ttainfo->ID3.artist) tuple->performer = g_strdup(ttainfo->ID3.artist); + if(ttainfo->ID3.album) tuple->album_name = g_strdup(ttainfo->ID3.album); + if(ttainfo->ID3.title) tuple->track_name = g_strdup(ttainfo->ID3.title); + if(ttainfo->ID3.year) tuple->year = atoi(ttainfo->ID3.year); + if(ttainfo->ID3.track) tuple->track_number = atoi(ttainfo->ID3.track); + if(ttainfo->ID3.genre) tuple->genre = g_strdup(ttainfo->ID3.genre); + if(ttainfo->ID3.comment) tuple->comment = g_strdup(ttainfo->ID3.comment); + } + close_tta_file (ttainfo); + } + vfs_fclose(file); + } + return tuple; +} + +static gchar * +extname(const char *filename) +{ + gchar *ext = strrchr(filename, '.'); + + if (ext != NULL) + ++ext; + + return ext; +} + +/* return length in letters */ +size_t tta_ucs4len(id3_ucs4_t *ucs) +{ + id3_ucs4_t *ptr = ucs; + size_t len = 0; + + while(*ptr++ != 0) + len++; + + return len; +} + +/* duplicate id3_ucs4_t string. new string will be terminated with 0. */ +id3_ucs4_t *tta_ucs4dup(id3_ucs4_t *org) +{ + id3_ucs4_t *new = NULL; + size_t len = tta_ucs4len(org); + + new = g_malloc0((len + 1) * sizeof(id3_ucs4_t)); + memcpy(new, org, len * sizeof(id3_ucs4_t)); + *(new + len) = 0; //terminate + + return new; +} + +id3_ucs4_t *tta_parse_genre(const id3_ucs4_t *string) +{ + id3_ucs4_t *ret = NULL; + id3_ucs4_t *tmp = NULL; + id3_ucs4_t *genre = NULL; + id3_ucs4_t *ptr, *end, *tail, *tp; + size_t ret_len = 0; //num of ucs4 char! + size_t tmp_len = 0; + gboolean is_num = TRUE; + + tail = (id3_ucs4_t *)string + tta_ucs4len((id3_ucs4_t *)string); + + ret = g_malloc0(1024); + + for(ptr = (id3_ucs4_t *)string; *ptr != 0 && ptr <= tail; ptr++) { + if(*ptr == '(') { + if(*(++ptr) == '(') { // escaped text like: ((something) + for(end = ptr; *end != ')' && *end != 0;) { // copy "(something)" + end++; + } + end++; //include trailing ')' + memcpy(ret, ptr, BYTES(end - ptr)); + ret_len += (end - ptr); + *(ret + ret_len) = 0; //terminate + ptr = end + 1; + } + else { + // reference to an id3v1 genre code + for(end = ptr; *end != ')' && *end != 0;) { + end++; + } + + tmp = g_malloc0(BYTES(end - ptr + 1)); + memcpy(tmp, ptr, BYTES(end - ptr)); + *(tmp + (end - ptr)) = 0; //terminate + ptr += end - ptr; + + genre = (id3_ucs4_t *)id3_genre_name((const id3_ucs4_t *)tmp); + + g_free(tmp); + tmp = NULL; + + tmp_len = tta_ucs4len(genre); + + memcpy(ret + BYTES(ret_len), genre, BYTES(tmp_len)); + + ret_len += tmp_len; + *(ret + ret_len) = 0; //terminate + } + } + else { + for(end = ptr; *end != '(' && *end != 0; ) { + end++; + } + // scan string to determine whether a genre code number or not + tp = ptr; + is_num = TRUE; + while(tp < end) { + if(*tp < '0' || *tp > '9') { // anything else than number appears. + is_num = FALSE; + break; + } + tp++; + } + if(is_num) { +#ifdef DEBUG + printf("is_num!\n"); +#endif + tmp = g_malloc0(BYTES(end - ptr + 1)); + memcpy(tmp, ptr, BYTES(end - ptr)); + *(tmp + (end - ptr)) = 0; //terminate + ptr += end - ptr; + + genre = (id3_ucs4_t *)id3_genre_name((const id3_ucs4_t *)tmp); +#ifdef DEBUG + printf("genre length = %d\n", tta_ucs4len(genre)); +#endif + g_free(tmp); + tmp = NULL; + + tmp_len = tta_ucs4len(genre); + + memcpy(ret + BYTES(ret_len), genre, BYTES(tmp_len)); + + ret_len += tmp_len; + *(ret + ret_len) = 0; //terminate + } + else { // plain text +#ifdef DEBUG + printf("plain!\n"); + printf("ret_len = %d\n", ret_len); +#endif + memcpy(ret + BYTES(ret_len), ptr, BYTES(end - ptr)); + ret_len = ret_len + (end - ptr); + *(ret + ret_len) = 0; //terminate + ptr += (end - ptr); + } + } + } + + return ret; +} + +gchar *tta_input_id3_get_string(struct id3_tag * tag, char *frame_name) +{ + gchar *rtn; + gchar *rtn2; + const id3_ucs4_t *string_const; + id3_ucs4_t *string; + id3_ucs4_t *ucsptr; + struct id3_frame *frame; + union id3_field *field; + gboolean flagutf = FALSE; + + frame = id3_tag_findframe(tag, frame_name, 0); + if (!frame) + return NULL; + + if (frame_name == ID3_FRAME_COMMENT) + field = id3_frame_field(frame, 3); + else + field = id3_frame_field(frame, 1); + + if (!field) + return NULL; + + if (frame_name == ID3_FRAME_COMMENT) + string_const = id3_field_getfullstring(field); + else + string_const = id3_field_getstrings(field, 0); + + if (!string_const) + return NULL; + + string = tta_ucs4dup((id3_ucs4_t *)string_const); + + if (frame_name == ID3_FRAME_GENRE) { + id3_ucs4_t *string2 = NULL; + string2 = tta_parse_genre(string); + g_free((void *)string); + string = string2; + } + + ucsptr = (id3_ucs4_t *)string; + while (*ucsptr) { + if (*ucsptr > 0x000000ffL) { + flagutf = TRUE; + break; + } + ucsptr++; + } + + if (flagutf) { +#ifdef DEBUG + g_message("aud-tta: flagutf!\n"); +#endif + rtn = id3_ucs4_utf8duplicate(string); + } + else { + rtn = id3_ucs4_latin1duplicate(string); + rtn2 = str_to_utf8(rtn); + free(rtn); + rtn = rtn2; + } + g_free(string); + string = NULL; +#ifdef DEBUG + g_print("string = %s\n", rtn); +#endif + + return rtn; +} + +int get_id3_tags (const char *filename, tta_info *ttainfo) { + int id3v2_size = 0; + gchar *str = NULL; + + struct id3_file *id3file = NULL; + struct id3_tag *tag = NULL; + + id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY); + + if (id3file) { + tag = id3_file_tag (id3file); + + if (tag) { + ttainfo->ID3.id3has = 1; + id3v2_size = tag->paddedsize; + + str = tta_input_id3_get_string (tag, ID3_FRAME_ARTIST); + if(str) strncpy(ttainfo->ID3.artist, str, MAX_LINE); + free(str); + str = NULL; + + str = tta_input_id3_get_string (tag, ID3_FRAME_ALBUM); + if(str) strncpy(ttainfo->ID3.album, str, MAX_LINE); + free(str); + str = NULL; + + str = tta_input_id3_get_string (tag, ID3_FRAME_TITLE); + if(str) strncpy(ttainfo->ID3.title, str, MAX_LINE); + free(str); + str = NULL; + + str = tta_input_id3_get_string (tag, ID3_FRAME_YEAR); + if(!str) str = tta_input_id3_get_string (tag, "TYER"); + if(str) strncpy(ttainfo->ID3.year, str, MAX_YEAR); + free(str); + str = NULL; + + str = tta_input_id3_get_string (tag, ID3_FRAME_TRACK); + if(str) strncpy(ttainfo->ID3.track, str, MAX_TRACK); + free(str); + str = NULL; + + str = tta_input_id3_get_string (tag, ID3_FRAME_GENRE); + if(str) strncpy(ttainfo->ID3.genre, str, MAX_GENRE); + free(str); + str = NULL; + + str = tta_input_id3_get_string (tag, ID3_FRAME_COMMENT); + if(str) strncpy(ttainfo->ID3.comment, str, MAX_LINE); + free(str); + str = NULL; + } + + id3_file_close(id3file); + } + + return id3v2_size; // not used +}