~ubuntu-branches/ubuntu/saucy/mpd/saucy

« back to all changes in this revision

Viewing changes to src/decoder/gme_decoder_plugin.c

  • Committer: Bazaar Package Importer
  • Author(s): Angel Abad
  • Date: 2011-02-02 12:26:30 UTC
  • mfrom: (1.5.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110202122630-bdyx8w4k94doz4fs
Tags: 0.16.1-1ubuntu1
* Merge from debian unstable. Remaining changes:
  - debian/control:
    + Don't build-depend on libmikmod2-dev (Debian bug #510675).
    + Move avahi-daemon from Suggests field to Recommends field.
  - debian/mpd.init.d:
    + Read mpd user from mpd.conf.
  - debian/control, debian/rules:
    + Add libmp3lame-dev to the build dependencies and enable lame.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "config.h"
 
2
#include "../decoder_api.h"
 
3
#include "audio_check.h"
 
4
#include "uri.h"
 
5
 
 
6
#include <glib.h>
 
7
#include <assert.h>
 
8
#include <errno.h>
 
9
#include <stdlib.h>
 
10
#include <string.h>
 
11
 
 
12
#include <gme/gme.h>
 
13
 
 
14
#undef G_LOG_DOMAIN
 
15
#define G_LOG_DOMAIN "gme"
 
16
 
 
17
#define SUBTUNE_PREFIX "tune_"
 
18
 
 
19
enum {
 
20
        GME_SAMPLE_RATE = 44100,
 
21
        GME_CHANNELS = 2,
 
22
        GME_BUFFER_FRAMES = 2048,
 
23
        GME_BUFFER_SAMPLES = GME_BUFFER_FRAMES * GME_CHANNELS,
 
24
};
 
25
 
 
26
/**
 
27
 * returns the file path stripped of any /tune_xxx.* subtune
 
28
 * suffix
 
29
 */
 
30
static char *
 
31
get_container_name(const char *path_fs)
 
32
{
 
33
        const char *subtune_suffix = uri_get_suffix(path_fs);
 
34
        char *path_container = g_strdup(path_fs);
 
35
        char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", subtune_suffix, NULL);
 
36
        GPatternSpec *path_with_subtune = g_pattern_spec_new(pat);
 
37
        g_free(pat);
 
38
        if (!g_pattern_match(path_with_subtune,
 
39
                             strlen(path_container), path_container, NULL)) {
 
40
                g_pattern_spec_free(path_with_subtune);
 
41
                return path_container;
 
42
        }
 
43
 
 
44
        char *ptr = g_strrstr(path_container, "/" SUBTUNE_PREFIX);
 
45
        if (ptr != NULL)
 
46
                *ptr='\0';
 
47
 
 
48
        g_pattern_spec_free(path_with_subtune);
 
49
        return path_container;
 
50
}
 
51
 
 
52
/**
 
53
 * returns tune number from file.nsf/tune_xxx.* style path or 0 if no subtune
 
54
 * is appended.
 
55
 */
 
56
static int
 
57
get_song_num(const char *path_fs)
 
58
{
 
59
        const char *subtune_suffix = uri_get_suffix(path_fs);
 
60
        char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", subtune_suffix, NULL);
 
61
        GPatternSpec *path_with_subtune = g_pattern_spec_new(pat);
 
62
        g_free(pat);
 
63
 
 
64
        if (g_pattern_match(path_with_subtune,
 
65
                            strlen(path_fs), path_fs, NULL)) {
 
66
                char *sub = g_strrstr(path_fs, "/" SUBTUNE_PREFIX);
 
67
                g_pattern_spec_free(path_with_subtune);
 
68
                if(!sub)
 
69
                        return 0;
 
70
 
 
71
                sub += strlen("/" SUBTUNE_PREFIX);
 
72
                int song_num = strtol(sub, NULL, 10);
 
73
 
 
74
                return song_num - 1;
 
75
        } else {
 
76
                g_pattern_spec_free(path_with_subtune);
 
77
                return 0;
 
78
        }
 
79
}
 
80
 
 
81
static char *
 
82
gme_container_scan(const char *path_fs, const unsigned int tnum)
 
83
{
 
84
        Music_Emu *emu;
 
85
        const char* gme_err;
 
86
        unsigned int num_songs;
 
87
 
 
88
        gme_err = gme_open_file(path_fs, &emu, GME_SAMPLE_RATE);
 
89
        if (gme_err != NULL) {
 
90
                g_warning("%s", gme_err);
 
91
                return NULL;
 
92
        }
 
93
 
 
94
        num_songs = gme_track_count(emu);
 
95
        /* if it only contains a single tune, don't treat as container */
 
96
        if (num_songs < 2)
 
97
                return NULL;
 
98
 
 
99
        const char *subtune_suffix = uri_get_suffix(path_fs);
 
100
        if (tnum <= num_songs){
 
101
                char *subtune = g_strdup_printf(
 
102
                        SUBTUNE_PREFIX "%03u.%s", tnum, subtune_suffix);
 
103
                return subtune;
 
104
        } else
 
105
                return NULL;
 
106
}
 
107
 
 
108
static void
 
109
gme_file_decode(struct decoder *decoder, const char *path_fs)
 
110
{
 
111
        float song_len;
 
112
        Music_Emu *emu;
 
113
        gme_info_t *ti;
 
114
        struct audio_format audio_format;
 
115
        enum decoder_command cmd;
 
116
        short buf[GME_BUFFER_SAMPLES];
 
117
        const char* gme_err;
 
118
        char *path_container = get_container_name(path_fs);
 
119
        int song_num = get_song_num(path_fs);
 
120
 
 
121
        gme_err = gme_open_file(path_container, &emu, GME_SAMPLE_RATE);
 
122
        g_free(path_container);
 
123
        if (gme_err != NULL) {
 
124
                g_warning("%s", gme_err);
 
125
                return;
 
126
        }
 
127
 
 
128
        if((gme_err = gme_track_info(emu, &ti, song_num)) != NULL){
 
129
                g_warning("%s", gme_err);
 
130
                gme_delete(emu);
 
131
                return;
 
132
        }
 
133
 
 
134
        if(ti->length > 0)
 
135
                song_len = ti->length / 1000.0;
 
136
        else song_len = -1;
 
137
 
 
138
        /* initialize the MPD decoder */
 
139
 
 
140
        GError *error = NULL;
 
141
        if (!audio_format_init_checked(&audio_format, GME_SAMPLE_RATE,
 
142
                                       SAMPLE_FORMAT_S16, GME_CHANNELS,
 
143
                                       &error)) {
 
144
                g_warning("%s", error->message);
 
145
                g_error_free(error);
 
146
                gme_free_info(ti);
 
147
                gme_delete(emu);
 
148
                return;
 
149
        }
 
150
 
 
151
        decoder_initialized(decoder, &audio_format, true, song_len);
 
152
 
 
153
        if((gme_err = gme_start_track(emu, song_num)) != NULL)
 
154
                g_warning("%s", gme_err);
 
155
 
 
156
        /* play */
 
157
        do {
 
158
                gme_err = gme_play(emu, GME_BUFFER_SAMPLES, buf);
 
159
                if (gme_err != NULL) {
 
160
                        g_warning("%s", gme_err);
 
161
                        return;
 
162
                }
 
163
                cmd = decoder_data(decoder, NULL, buf, sizeof(buf), 0);
 
164
 
 
165
                if(cmd == DECODE_COMMAND_SEEK) {
 
166
                        float where = decoder_seek_where(decoder);
 
167
                        if((gme_err = gme_seek(emu, (int)where*1000)) != NULL)
 
168
                                g_warning("%s", gme_err);
 
169
                        decoder_command_finished(decoder);
 
170
                }
 
171
 
 
172
                if(gme_track_ended(emu))
 
173
                        break;
 
174
        } while(cmd != DECODE_COMMAND_STOP);
 
175
 
 
176
        gme_free_info(ti);
 
177
        gme_delete(emu);
 
178
}
 
179
 
 
180
static struct tag *
 
181
gme_tag_dup(const char *path_fs)
 
182
{
 
183
        Music_Emu *emu;
 
184
        gme_info_t *ti;
 
185
        const char* gme_err;
 
186
        char *path_container=get_container_name(path_fs);
 
187
        int song_num;
 
188
        song_num=get_song_num(path_fs);
 
189
 
 
190
        gme_err = gme_open_file(path_container, &emu, GME_SAMPLE_RATE);
 
191
        g_free(path_container);
 
192
        if (gme_err != NULL) {
 
193
                g_warning("%s", gme_err);
 
194
                return NULL;
 
195
        }
 
196
        if((gme_err = gme_track_info(emu, &ti, song_num)) != NULL){
 
197
                g_warning("%s", gme_err);
 
198
                gme_delete(emu);
 
199
                return NULL;
 
200
        }
 
201
 
 
202
        struct tag *tag = tag_new();
 
203
        if(ti != NULL){
 
204
                if(ti->length > 0)
 
205
                        tag->time = ti->length / 1000;
 
206
                if(ti->song != NULL){
 
207
                        if(gme_track_count(emu) > 1){
 
208
                                /* start numbering subtunes from 1 */
 
209
                                char *tag_title=g_strdup_printf("%s (%d/%d)",
 
210
                                        ti->song, song_num+1, gme_track_count(emu));
 
211
                                tag_add_item(tag, TAG_TITLE, tag_title);
 
212
                                g_free(tag_title);
 
213
                        }else
 
214
                                tag_add_item(tag, TAG_TITLE, ti->song);
 
215
                }
 
216
                if(ti->author != NULL)
 
217
                        tag_add_item(tag, TAG_ARTIST, ti->author);
 
218
                if(ti->game != NULL)
 
219
                        tag_add_item(tag, TAG_ALBUM, ti->game);
 
220
                if(ti->comment != NULL)
 
221
                        tag_add_item(tag, TAG_COMMENT, ti->comment);
 
222
                if(ti->copyright != NULL)
 
223
                        tag_add_item(tag, TAG_DATE, ti->copyright);
 
224
        }
 
225
 
 
226
        gme_free_info(ti);
 
227
        gme_delete(emu);
 
228
        return tag;
 
229
}
 
230
 
 
231
static const char *const gme_suffixes[] = {
 
232
        "ay", "gbs", "gym", "hes", "kss", "nsf",
 
233
        "nsfe", "sap", "spc", "vgm", "vgz",
 
234
        NULL
 
235
};
 
236
 
 
237
extern const struct decoder_plugin gme_decoder_plugin;
 
238
const struct decoder_plugin gme_decoder_plugin = {
 
239
        .name = "gme",
 
240
        .file_decode = gme_file_decode,
 
241
        .tag_dup = gme_tag_dup,
 
242
        .suffixes = gme_suffixes,
 
243
        .container_scan = gme_container_scan,
 
244
};