Support FLAC 1.1.3
[cmus.git] / mad.c
blob62ecbabbb298b0f2aee95dab5ee4566f6d0ebd5c
1 /*
2 * Copyright 2004 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include "ip.h"
21 #include "nomad.h"
22 #include "id3.h"
23 #include "xmalloc.h"
24 #include "read_wrapper.h"
25 #include "debug.h"
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
34 /* ------------------------------------------------------------------------- */
36 static ssize_t read_func(void *datasource, void *buffer, size_t count)
38 struct input_plugin_data *ip_data = datasource;
40 return read_wrapper(ip_data, buffer, count);
43 static off_t lseek_func(void *datasource, off_t offset, int whence)
45 struct input_plugin_data *ip_data = datasource;
47 return lseek(ip_data->fd, offset, whence);
50 static int close_func(void *datasource)
52 struct input_plugin_data *ip_data = datasource;
54 return close(ip_data->fd);
57 static struct nomad_callbacks callbacks = {
58 .read = read_func,
59 .lseek = lseek_func,
60 .close = close_func
63 /* ------------------------------------------------------------------------- */
65 static int mad_open(struct input_plugin_data *ip_data)
67 struct nomad *nomad;
68 struct nomad_info info;
69 int rc, fast;
71 fast = 1;
72 rc = nomad_open_callbacks(&nomad, ip_data, fast, &callbacks);
73 switch (rc) {
74 case -NOMAD_ERROR_ERRNO:
75 return -1;
76 case -NOMAD_ERROR_FILE_FORMAT:
77 return -IP_ERROR_FILE_FORMAT;
79 ip_data->private = nomad;
81 nomad_info(nomad, &info);
83 /* always 16-bit signed little-endian */
84 ip_data->sf = sf_rate(info.sample_rate) | sf_channels(info.channels) |
85 sf_bits(16) | sf_signed(1);
86 return 0;
89 static int mad_close(struct input_plugin_data *ip_data)
91 struct nomad *nomad;
93 nomad = ip_data->private;
94 nomad_close(nomad);
95 ip_data->fd = -1;
96 ip_data->private = NULL;
97 return 0;
100 static int mad_read(struct input_plugin_data *ip_data, char *buffer, int count)
102 struct nomad *nomad;
104 nomad = ip_data->private;
105 return nomad_read(nomad, buffer, count);
108 static int mad_seek(struct input_plugin_data *ip_data, double offset)
110 struct nomad *nomad;
112 nomad = ip_data->private;
113 return nomad_time_seek(nomad, offset);
116 static void get_comment(struct keyval *c, int *iptr, ID3 *id3, enum id3_key key, const char *key_name)
118 int i = *iptr;
120 c[i].val = id3_get_comment(id3, key);
121 if (c[i].val == NULL)
122 return;
123 c[i].key = xstrdup(key_name);
124 *iptr = i + 1;
127 static int mad_read_comments(struct input_plugin_data *ip_data,
128 struct keyval **comments)
130 ID3 *id3;
131 struct keyval *c;
132 int fd, rc, save, i;
134 fd = open(ip_data->filename, O_RDONLY);
135 if (fd == -1) {
136 return -1;
138 d_print("filename: %s\n", ip_data->filename);
140 id3 = id3_new();
141 rc = id3_read_tags(id3, fd, ID3_V1 | ID3_V2);
142 save = errno;
143 close(fd);
144 errno = save;
145 if (rc) {
146 if (rc == -1) {
147 d_print("error: %s\n", strerror(errno));
148 return -1;
150 d_print("corrupted tag?\n");
151 *comments = xnew0(struct keyval, 1);
152 return 0;
155 c = xnew0(struct keyval, NUM_ID3_KEYS + 1);
156 i = 0;
157 get_comment(c, &i, id3, ID3_ARTIST, "artist");
158 get_comment(c, &i, id3, ID3_ALBUM, "album");
159 get_comment(c, &i, id3, ID3_TITLE, "title");
160 get_comment(c, &i, id3, ID3_DATE, "date");
161 get_comment(c, &i, id3, ID3_GENRE, "genre");
162 get_comment(c, &i, id3, ID3_DISC, "discnumber");
163 get_comment(c, &i, id3, ID3_TRACK, "tracknumber");
164 get_comment(c, &i, id3, ID3_ALBUMARTIST, "albumartist");
165 *comments = c;
166 id3_free(id3);
167 return 0;
170 static int mad_duration(struct input_plugin_data *ip_data)
172 struct nomad *nomad;
174 nomad = ip_data->private;
175 return nomad_time_total(nomad);
178 const struct input_plugin_ops ip_ops = {
179 .open = mad_open,
180 .close = mad_close,
181 .read = mad_read,
182 .seek = mad_seek,
183 .read_comments = mad_read_comments,
184 .duration = mad_duration
187 const char * const ip_extensions[] = { "mp3", "mp2", NULL };
188 const char * const ip_mime_types[] = {
189 "audio/mpeg", "audio/x-mp3", "audio/x-mpeg", "audio/x-mpegurl", NULL