Index: Makefile.am =================================================================== RCS file: /cvs/gnome/nautilus/components/music/Makefile.am,v retrieving revision 1.31 diff -u -u -r1.31 Makefile.am --- Makefile.am 2001/05/04 03:14:29 1.31 +++ Makefile.am 2001/05/28 21:08:28 @@ -53,14 +53,18 @@ esd-audio.c \ esd-mixer.c \ pixmaps.h \ + song.h \ + song.c \ $(dct64_source) \ $(decode_source) nautilus_music_view_LDADD = \ $(top_builddir)/libnautilus/libnautilus.la \ + -lvorbis -lvorbisfile \ $(top_builddir)/libnautilus-private/libnautilus-private.la \ $(NAUTILUS_PRIVATE_LIBS) \ $(NULL) + oafdir = $(datadir)/oaf Index: Nautilus_View_music.oaf.in =================================================================== RCS file: /cvs/gnome/nautilus/components/music/Nautilus_View_music.oaf.in,v retrieving revision 1.10 diff -u -u -r1.10 Nautilus_View_music.oaf.in --- Nautilus_View_music.oaf.in 2001/02/25 10:01:56 1.10 +++ Nautilus_View_music.oaf.in 2001/05/28 21:08:28 @@ -25,6 +25,7 @@ + Index: nautilus-music-view.c =================================================================== RCS file: /cvs/gnome/nautilus/components/music/nautilus-music-view.c,v retrieving revision 1.136 diff -u -u -r1.136 nautilus-music-view.c --- nautilus-music-view.c 2001/05/11 01:30:28 1.136 +++ nautilus-music-view.c 2001/05/28 21:08:28 @@ -27,9 +27,10 @@ #include "nautilus-music-view.h" #include "esd-audio.h" -#include "mp3head.h" -#include "mpg123.h" +//#include "mp3head.h" +//#include "mpg123.h" #include "pixmaps.h" +#include "song.h" #include #include @@ -48,11 +49,9 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -85,9 +84,9 @@ int current_samprate; int current_duration; - + gboolean slider_dragging; - + GtkVBox *album_container; GtkWidget *scroll_window; GtkWidget *album_title; @@ -119,22 +118,6 @@ }; -/* structure for holding song info */ -typedef struct { - int track_number; - int bitrate; - int track_time; - int stereo; - int samprate; - - char *title; - char *artist; - char *album; - char *year; - char *comment; - char *path_uri; -} SongInfo; - enum { TARGET_URI_LIST, TARGET_COLOR, @@ -766,103 +749,6 @@ } } -/* here are some utility routines for reading ID3 tags from mp3 files */ - -/* initialize a songinfo structure */ -static void -initialize_song_info (SongInfo *info) -{ - /* Only called after g_new0. */ - info->track_number = -1; -} - -/* deallocate a songinfo structure */ - -static void -release_song_info (SongInfo *info) -{ - g_free (info->title); - g_free (info->artist); - g_free (info->album); - g_free (info->year); - g_free (info->comment); - g_free (info->path_uri); - g_free (info); -} - -/* determine if a file is an mp3 file by looking at the mime type */ -static gboolean -is_mp3_file (GnomeVFSFileInfo *file_info) -{ - return eel_istr_has_prefix (file_info->mime_type, "audio/") - && eel_istr_has_suffix (file_info->mime_type, "mp3"); -} - -/* read the id3 tag of the file if present */ -static gboolean -read_id_tag (const char *song_uri, SongInfo *song_info) -{ - char *path; - id3_t *id3; - struct id3v1tag_t id3v1tag; - struct id3tag_t tag; - FILE *file; - - path = gnome_vfs_get_local_path_from_uri (song_uri); - if (path == NULL) { - return FALSE; - } - - file = fopen (path, "rb"); - g_free (path); - - if (file == NULL) { - return FALSE; - } - - /* Try ID3v2 tag first */ - fseek (file, 0, SEEK_SET); - id3 = id3_open_fp (file, O_RDONLY); - if (id3 != NULL) { - mpg123_get_id3v2 (id3, &tag); - id3_close (id3); - } else if ((fseek (file, -1 * sizeof (id3v1tag), SEEK_END) == 0) && - (fread (&id3v1tag, 1, sizeof (id3v1tag), file) == sizeof (id3v1tag)) && - (strncmp (id3v1tag.tag, "TAG", 3) == 0)) { - /* Try reading ID3v1 tag. */ - mpg123_id3v1_to_id3v2 (&id3v1tag, &tag); - } else { - /* Failed to read any sort of tag */ - fclose (file); - return FALSE; - } - - /* Copy data from tag into our info struct */ - song_info->title = g_strdup (tag.title); - song_info->artist = g_strdup (tag.artist); - song_info->album = g_strdup (tag.album); - song_info->year = g_strdup (tag.year); - song_info->comment = g_strdup (tag.comment); - song_info->track_number = atoi (tag.track); - - /* Clean up */ - fclose (file); - return TRUE; -} - - -/* fetch_play_time takes the pathname to a file and returns the play time in seconds */ -static int -fetch_play_time (GnomeVFSFileInfo *file_info, int bitrate) -{ - if ((file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) { - return 0; - } - - /* Avoid divide by zero. */ - return bitrate == 0 ? 0 : file_info->size / (125 * bitrate); -} - /* format_play_time takes the pathname to a file and returns the play time formated as mm:ss */ static char * format_play_time (int track_time) @@ -875,109 +761,6 @@ return g_strdup_printf ("%d:%02d ", minutes, remain_seconds); } -/* extract a track number from the file name - return -1 if there wasn't any */ -static int -extract_number(const char *name_str) -{ - const char *temp_str; - gboolean found_digit; - int accumulator; - - found_digit = FALSE; - accumulator = 0; - if (isdigit (*name_str)) { - temp_str = name_str; - } else if (strchr(name_str, '(') != NULL) { - temp_str = strchr(name_str, '(') + 1; - } else { - return -1; - } - - while (isdigit (*temp_str)) { - found_digit = TRUE; - accumulator = (10 * accumulator) + *temp_str - 48; - temp_str += 1; - } - - if (found_digit) { - return accumulator; - } - - return -1; -} - -/* allocate a return a song info record, from an mp3 tag if present, or from intrinsic info */ -static SongInfo * -fetch_song_info (const char *song_uri, GnomeVFSFileInfo *file_info, int file_order) -{ - gboolean has_info = FALSE; - SongInfo *info; - guchar buffer[8192]; - GnomeVFSHandle *mp3_file; - GnomeVFSResult result; - GnomeVFSFileSize length_read; - ID3V2Header v2header; - long header_size; - - if (!is_mp3_file (file_info)) { - return NULL; - } - - info = g_new0 (SongInfo, 1); - initialize_song_info (info); - - has_info = read_id_tag (song_uri, info); - - /* if we couldn't get a track number, see if we can pull one from - the file name */ - if (info->track_number <= 0) { - info->track_number = extract_number(file_info->name); - } - - /* there was no id3 tag, so set up the info heuristically from the file name and file order */ - if (!has_info) { - info->title = g_strdup (file_info->name); - } - - result = gnome_vfs_open (&mp3_file, song_uri, GNOME_VFS_OPEN_READ); - if (result == GNOME_VFS_OK) { - result = gnome_vfs_read (mp3_file, buffer, sizeof (buffer), &length_read); - if ((result == GNOME_VFS_OK) && (length_read > 512)) { - /* Make sure ID3v2 tag is not at start of file */ - if ( buffer[0] == 'I' && buffer[1] == 'D' && buffer[2] == '3' ) { - /* Read in header and determine size */ - gnome_vfs_seek (mp3_file, GNOME_VFS_SEEK_START, 0); - result = gnome_vfs_read (mp3_file, &v2header, sizeof (ID3V2Header), &length_read); - if (result != GNOME_VFS_OK) { - return info; - } - - header_size = ((long) v2header.size[3] | - ((long) v2header.size[2] << (8 - 1)) | - ((long) v2header.size[1] << (16 - 2)) | - ((long) v2header.size[0] << (24 - 3))) - + sizeof (ID3V2Header); - - /* Seek past the tag to the mp3 data */ - gnome_vfs_seek (mp3_file, GNOME_VFS_SEEK_START, header_size); - result = gnome_vfs_read (mp3_file, buffer, sizeof (buffer), &length_read); - if (result != GNOME_VFS_OK) { - return info; - } - } - - info->bitrate = get_bitrate (buffer, length_read); - info->samprate = get_samprate (buffer, length_read); - info->stereo = get_stereo (buffer, length_read); - info->track_time = fetch_play_time (file_info, info->bitrate); - } - gnome_vfs_close (mp3_file); - } - - return info; -} - /* utility routine to determine most common attribute in song list. The passed in boolean selects album or artist. Return NULL if they are heterogenous */ static char * @@ -1209,9 +992,11 @@ if (song_info == NULL) { return; } - song_filename = gnome_vfs_get_local_path_from_uri (song_info->path_uri); + + song_filename = gnome_vfs_get_local_path_from_uri (song_info->path_uri); /* for now, we can only play local files, so apologize to the user and give up */ + /* NOTE: In theory the ogg stuff can be played over other transports. */ if (song_filename == NULL) { eel_show_error_dialog ( _("Sorry, but the music view can't play non-local files yet."), @@ -1673,7 +1458,6 @@ char *image_path_uri; char *path, *message; - int file_index; int track_index; int image_count; @@ -1681,7 +1465,6 @@ song_list = NULL; image_path_uri = NULL; - file_index = 1; track_index = 0; image_count = 0; @@ -1716,10 +1499,9 @@ g_free (escaped_name); /* fetch info and queue it if it's an mp3 file */ - info = fetch_song_info (path_uri, current_file_info, file_index); + info = song_info_new (path_uri, current_file_info); if (info) { info->path_uri = path_uri; - file_index += 1; song_list = g_list_prepend (song_list, info); } else { /* it's not an mp3 file, so see if it's an image */ @@ -1773,7 +1555,7 @@ gtk_clist_append(GTK_CLIST(music_view->details->song_list), clist_entry); gtk_clist_set_row_data_full (GTK_CLIST(music_view->details->song_list), - track_index, info, (GtkDestroyNotify)release_song_info); + track_index, info, (GtkDestroyNotify)song_info_free); for (i = 0; i < 10; i ++) { g_free (clist_entry[i]); @@ -1940,7 +1722,7 @@ start_playing_file (NautilusMusicView *music_view, const char *file_name) { set_player_state (music_view, PLAYER_PLAYING); - mpg123_play_file (file_name); + song_play_file (file_name); } static void Index: song.c =================================================================== RCS file: song.c diff -N song.c --- /dev/null Tue May 5 16:32:27 1998 +++ song.c Mon May 28 17:08:28 2001 @@ -0,0 +1,479 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +#include "song.h" + +#include "esd-audio.h" +#include "mp3head.h" +#include "mpg123.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static size_t ogg_fread (void *ptr, + size_t size, + size_t nmemb, + void *stream); +static int ogg_fseek (void *stream, + gint64 offset, + int whence); +static int ogg_fclose (void *stream); +static long ogg_ftell (void *stream); + + + + +/* Generic Functionality + */ + +/* extract a track number from the file name + return -1 if there wasn't any */ +static int +extract_number(const char *name_str) +{ + const char *temp_str; + gboolean found_digit; + int accumulator; + + found_digit = FALSE; + accumulator = 0; + if (isdigit (*name_str)) { + temp_str = name_str; + } else if (strchr(name_str, '(') != NULL) { + temp_str = strchr(name_str, '(') + 1; + } else { + return -1; + } + + while (isdigit (*temp_str)) { + found_digit = TRUE; + accumulator = (10 * accumulator) + *temp_str - 48; + temp_str += 1; + } + + if (found_digit) { + return accumulator; + } + + return -1; +} + +/* MP3 Functionality + */ +static int +mp3_fetch_play_time (GnomeVFSFileInfo *file_info, int bitrate) +{ + if ((file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) { + return 0; + } + + /* Avoid divide by zero. */ + return bitrate == 0 ? 0 : file_info->size / (125 * bitrate); +} + +static gboolean +mp3_read_id_tag (const char *song_uri, SongInfo *song_info) +{ + char *path; + id3_t *id3; + struct id3v1tag_t id3v1tag; + struct id3tag_t tag; + FILE *file; + + path = gnome_vfs_get_local_path_from_uri (song_uri); + if (path == NULL) { + return FALSE; + } + + file = fopen (path, "rb"); + g_free (path); + + if (file == NULL) { + return FALSE; + } + + /* Try ID3v2 tag first */ + fseek (file, 0, SEEK_SET); + id3 = id3_open_fp (file, O_RDONLY); + if (id3 != NULL) { + mpg123_get_id3v2 (id3, &tag); + id3_close (id3); + } else if ((fseek (file, -1 * sizeof (id3v1tag), SEEK_END) == 0) && + (fread (&id3v1tag, 1, sizeof (id3v1tag), file) == sizeof (id3v1tag)) && + (strncmp (id3v1tag.tag, "TAG", 3) == 0)) { + /* Try reading ID3v1 tag. */ + mpg123_id3v1_to_id3v2 (&id3v1tag, &tag); + } else { + /* Failed to read any sort of tag */ + fclose (file); + return FALSE; + } + + /* Copy data from tag into our info struct */ + song_info->title = g_strdup (tag.title); + song_info->artist = g_strdup (tag.artist); + song_info->album = g_strdup (tag.album); + song_info->year = g_strdup (tag.year); + song_info->comment = g_strdup (tag.comment); + song_info->track_number = atoi (tag.track); + + /* Clean up */ + fclose (file); + return TRUE; +} + +static gboolean +song_info_initialize_mp3 (SongInfo *song_info, + const char *song_uri, + GnomeVFSFileInfo *file_info) +{ + gboolean has_info = FALSE; + guchar buffer[8192]; + GnomeVFSHandle *mp3_file; + GnomeVFSResult result; + GnomeVFSFileSize length_read; + ID3V2Header v2header; + long header_size; + + song_info->type = SONG_TYPE_MP3; + has_info = mp3_read_id_tag (song_uri, song_info); + + /* if we couldn't get a track number, see if we can pull one from + * the file name. + */ + if (song_info->track_number <= 0) { + song_info->track_number = extract_number(file_info->name); + } + + /* there was no id3 tag, so set up the info heuristically from the file name and file order */ + if (!has_info) { + song_info->title = g_strdup (file_info->name); + } + + result = gnome_vfs_open (&mp3_file, song_uri, GNOME_VFS_OPEN_READ); + if (result == GNOME_VFS_OK) { + result = gnome_vfs_read (mp3_file, buffer, sizeof (buffer), &length_read); + if ((result == GNOME_VFS_OK) && (length_read > 512)) { + /* Make sure ID3v2 tag is not at start of file */ + if ( buffer[0] == 'I' && buffer[1] == 'D' && buffer[2] == '3' ) { + /* Read in header and determine size */ + gnome_vfs_seek (mp3_file, GNOME_VFS_SEEK_START, 0); + result = gnome_vfs_read (mp3_file, &v2header, sizeof (ID3V2Header), &length_read); + if (result != GNOME_VFS_OK) { + return FALSE; + } + + header_size = ((long) v2header.size[3] | + ((long) v2header.size[2] << (8 - 1)) | + ((long) v2header.size[1] << (16 - 2)) | + ((long) v2header.size[0] << (24 - 3))) + + sizeof (ID3V2Header); + + /* Seek past the tag to the mp3 data */ + gnome_vfs_seek (mp3_file, GNOME_VFS_SEEK_START, header_size); + result = gnome_vfs_read (mp3_file, buffer, sizeof (buffer), &length_read); + if (result != GNOME_VFS_OK) { + return TRUE; + } + } + + song_info->bitrate = get_bitrate (buffer, length_read); + song_info->samprate = get_samprate (buffer, length_read); + song_info->stereo = get_stereo (buffer, length_read); + song_info->track_time = mp3_fetch_play_time (file_info, song_info->bitrate); + } + gnome_vfs_close (mp3_file); + } + + return TRUE; +} + +static gboolean +is_mp3_file (GnomeVFSFileInfo *file_info) +{ + return eel_istr_has_prefix (file_info->mime_type, "audio/") + && eel_istr_has_suffix (file_info->mime_type, "mp3"); +} + + +/* Ogg Functionality + */ + +static size_t +ogg_fread (void *ptr, + size_t size, + size_t nmemb, + void *stream) +{ + GnomeVFSResult result; + GnomeVFSFileSize bytes_read; + result = gnome_vfs_read ((GnomeVFSHandle *) stream, + ptr, + size * nmemb, + &bytes_read); + if (result != GNOME_VFS_OK) + return 0; + return bytes_read; +} + +static int +ogg_fseek (void *stream, + gint64 offset, + int whence) +{ + GnomeVFSResult result; + result = gnome_vfs_seek ((GnomeVFSHandle *) stream, + whence, offset); + + if (result == GNOME_VFS_OK) + return 0; + else + return -1; +} + +static int +ogg_fclose (void *stream) +{ + GnomeVFSResult result; + result = gnome_vfs_close ((GnomeVFSHandle *) stream); + + if (result == GNOME_VFS_OK) + return 0; + else + return -1; +} + +static long +ogg_ftell (void *stream) +{ + GnomeVFSResult result; + GnomeVFSFileSize offset_return; + result = gnome_vfs_tell ((GnomeVFSHandle *) stream, + &offset_return); + + if (result == GNOME_VFS_OK) + return offset_return; + else + return -1; +} +struct { + char *key; /* includes the '=' for programming convenience */ + char *formatstr; /* formatted output */ +} ogg_comment_keys[] = { + {"COMMENT=", "Comment: %s\n"}, + {"VERSION=", "Version: %s\n"}, + {"TRACKNUMBER=", "Track number: %s\n"}, + {"ORGANIZATION=", "Organization: %s\n"}, + {"GENRE=", "Genre: %s\n"}, + {"DESCRIPTION=", "Description: %s\n"}, + {"LOCATION=", "Location: %s\n"}, + {"COPYRIGHT=", "Copyright %s\n"}, + { NULL, NULL } +}; + +static gboolean +song_info_initialize_ogg (SongInfo *song_info, + const char *song_uri, + GnomeVFSFileInfo *file_info) +{ + GnomeVFSHandle *ogg_file; + GnomeVFSResult result; + OggVorbis_File vf; + vorbis_comment *vc; + vorbis_info *vi; + GString *comment; + gint i, j; + ov_callbacks callbacks = { + (size_t (*)(void *, size_t, size_t, void *)) ogg_fread, + (int (*)(void *, ogg_int64_t, int)) ogg_fseek, + (int (*)(void *)) ogg_fclose, + (long (*)(void *)) ogg_ftell + }; + + song_info->type = SONG_TYPE_OGG; + song_info->track_number = -1; + result = gnome_vfs_open (&ogg_file, song_uri, GNOME_VFS_OPEN_READ); + + if (result != GNOME_VFS_OK) + return FALSE; + + if (ov_open_callbacks (ogg_file, &vf, NULL, 0, callbacks) != 0) { + gnome_vfs_close (ogg_file); + return FALSE; + } + + vc = ov_comment(&vf, -1); + vi = ov_info(&vf, -1); + + /* First, parse all comments */ + comment = g_string_new (NULL); + + for (i = 0 ; i < vc->comments; i++) { + if (! song_info->artist && + ! strncasecmp ("ARTIST=", + vc->user_comments[i], + strlen ("ARTIST="))) + song_info->artist = g_strdup (vc->user_comments[i] + + strlen ("ARTIST=")); + else if (! song_info->title && + ! strncasecmp ("TITLE=", + vc->user_comments[i], + strlen ("TITLE="))) + song_info->title = g_strdup (vc->user_comments[i] + + strlen ("TITLE=")); + else if (! song_info->album && + ! strncasecmp ("ALBUM=", + vc->user_comments[i], + strlen ("ALBUM="))) + song_info->album = g_strdup (vc->user_comments[i] + + strlen ("ALBUM=")); + else if (! song_info->year && + ! strncasecmp ("DATE=", + vc->user_comments[i], + strlen ("DATE="))) + song_info->year = g_strdup (vc->user_comments[i] + + strlen ("DATE=")); + else if (! song_info->year && + ! strncasecmp ("TIMESTAMP=", + vc->user_comments[i], + strlen ("TIMESTAMP="))) + song_info->track_number = atoi (vc->user_comments[i] + + strlen ("TIMESTAMP=")); + else { + for (j = 0; ogg_comment_keys[j].key != NULL; j++) { + if (!strncasecmp (ogg_comment_keys[j].key, + vc->user_comments[i], + strlen(ogg_comment_keys[i].key))) { + gchar *str = g_strdup_printf (ogg_comment_keys[j].formatstr, + vc->user_comments[i] + + strlen(ogg_comment_keys[i].key)); + g_string_append (comment, str); + break; + } + } + } + } + + song_info->comment = comment->str; + g_string_free (comment, FALSE); + + if (song_info->track_number <= 0) { + song_info->track_number = extract_number (file_info->name); + } + song_info->bitrate = vi->bitrate_nominal; + song_info->track_time = ov_time_total (&vf, -1); + song_info->stereo = (vi->channels > 1); + song_info->samprate = vi->rate; + + ov_clear (&vf); + + return TRUE; +} + +static gboolean +is_ogg_file (GnomeVFSFileInfo *file_info) +{ + return eel_istr_has_prefix (file_info->mime_type, "application/") + && eel_istr_has_suffix (file_info->mime_type, "x-ogg"); +} + +/* Song info + */ +SongInfo * +song_info_new (const char *song_uri, + GnomeVFSFileInfo *file_info) +{ + SongInfo *song_info; + + song_info = g_new0 (SongInfo, 1); + song_info->track_number = -1; + + if (is_mp3_file (file_info)) { + if (song_info_initialize_mp3 (song_info, song_uri, file_info)) + return song_info; + } + if (is_ogg_file (file_info)) { + if (song_info_initialize_ogg (song_info, song_uri, file_info)) + return song_info; + } + g_free (song_info); + song_info = NULL; + + + return NULL; +} + +void +song_info_free (SongInfo *info) +{ + g_free (info->title); + g_free (info->artist); + g_free (info->album); + g_free (info->year); + g_free (info->comment); + g_free (info->path_uri); + g_free (info); +} + + +static gint cur_song_type = -1; + +void +song_play_file (const gchar *file_info) +{ + cur_song_type = SONG_TYPE_MP3; + switch (cur_song_type) { + case SONG_TYPE_MP3: + mpg123_play_file (file_info); + break; + case SONG_TYPE_OGG: + break; + default: + g_assert_not_reached (); + } +} + +void +song_pause (gboolean pause) +{ + switch (cur_song_type) { + case SONG_TYPE_MP3: + mpg123_pause (pause); + break; + case SONG_TYPE_OGG: + break; + default: + g_assert_not_reached (); + } +} + +void +song_stop () +{ + switch (cur_song_type) { + case SONG_TYPE_MP3: + mpg123_stop (); + break; + case SONG_TYPE_OGG: + break; + default: + g_assert_not_reached (); + } +} + +void +song_seek (gint offset) +{ + switch (cur_song_type) { + case SONG_TYPE_MP3: + mpg123_seek (offset); + break; + case SONG_TYPE_OGG: + break; + default: + g_assert_not_reached (); + } +} Index: song.h =================================================================== RCS file: song.h diff -N song.h --- /dev/null Tue May 5 16:32:27 1998 +++ song.h Mon May 28 17:08:28 2001 @@ -0,0 +1,66 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * Copyright (C) 2000 Eazel, Inc, Jonathan Blandford + * + * 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. + * + * Author: Andy Hertzfeld, Jonathan Blandford + */ + +/* header file for song abstraction */ + +#ifndef SONG_H +#define SONG_H + +#include +#include + + + +typedef enum { + SONG_TYPE_MP3, + SONG_TYPE_OGG +} SongType; + +typedef struct { + SongType type; + int track_number; + int bitrate; + int track_time; + int stereo; + int samprate; + + char *title; + char *artist; + char *album; + char *year; + char *comment; + char *path_uri; +} SongInfo; + + + + +SongInfo *song_info_new (const char *song_uri, + GnomeVFSFileInfo *file_info); +void song_info_free (SongInfo *song); +void song_play_file (const gchar *file_info); +void song_pause (gboolean pause); +void song_stop (void); +void song_seek (gint offset); + + +#endif /* NAUTILUS_MUSIC_VIEW_H */