catori 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -0
- data/bin/catori +9 -0
- data/changelog.txt +3 -0
- data/construir +3 -0
- data/crear_vista.sql +8 -0
- data/ext/audiofile/MANIFEST +8 -0
- data/ext/audiofile/README +11 -0
- data/ext/audiofile/audiofile.c +833 -0
- data/ext/audiofile/audiofile.rd +265 -0
- data/ext/audiofile/depend +0 -0
- data/ext/audiofile/extconf.rb +8 -0
- data/ext/audiofile/fail.rb +22 -0
- data/ext/audiofile/mkmf.log +34 -0
- data/ext/audiofile/test.rb +229 -0
- data/ext/flac/extconf.rb +5 -0
- data/ext/flac/flac.c +75 -0
- data/ext/flac/mkmf.log +12 -0
- data/ext/flac/test.rb +3 -0
- data/ext/mahoro-0.1/INSTALL +9 -0
- data/ext/mahoro-0.1/extconf.rb +7 -0
- data/ext/mahoro-0.1/mahoro.c +187 -0
- data/ext/mahoro-0.1/mkmf.log +24 -0
- data/ext/mahoro-0.1/test.rb +41 -0
- data/ext/mpc/extconf.rb +5 -0
- data/ext/mpc/id3tag.c +245 -0
- data/ext/mpc/id3tag.h +5 -0
- data/ext/mpc/mkmf.log +12 -0
- data/ext/mpc/mpc.c +56 -0
- data/ext/mpc/mpp.h +194 -0
- data/ext/mpc/mppdec.h +1171 -0
- data/ext/mpc/test.rb +3 -0
- data/ext/rmac/extconf.rb +7 -0
- data/ext/rmac/mkmf.log +22 -0
- data/ext/rmac/rmac.cpp +162 -0
- data/ext/vorbisfile/ChangeLog +11 -0
- data/ext/vorbisfile/README +33 -0
- data/ext/vorbisfile/configure +2 -0
- data/ext/vorbisfile/extconf.rb +9 -0
- data/ext/vorbisfile/mkmf.log +68 -0
- data/ext/vorbisfile/test.rb +78 -0
- data/ext/vorbisfile/vorbisfile.c +482 -0
- data/instalar.txt +19 -0
- data/install.rb +11 -0
- data/lib/audioinfo.rb +321 -0
- data/lib/catori.rb +131 -0
- data/lib/catori/Catalogador.rb +71 -0
- data/lib/catori/Db.rb +81 -0
- data/lib/catori/Gui.rb +52 -0
- data/lib/catori/Installer.rb +16 -0
- data/lib/catori/Query.rb +82 -0
- data/lib/catori/XML.rb +42 -0
- data/lib/catori/catori_gui.glade +340 -0
- data/lib/catori/catori_gui.glade.bak +340 -0
- data/lib/catori/catori_gui.gladep +8 -0
- data/lib/catori/catori_gui.gladep.bak +8 -0
- data/lib/catori/taglib.rb +227 -0
- data/lib/pixmaps/album.png +0 -0
- data/lib/pixmaps/artist.png +0 -0
- data/lib/pixmaps/cdr.png +0 -0
- data/lib/pixmaps/song.png +0 -0
- data/lib/taglib.rb +230 -0
- data/sql/catori_mysql.sql +68 -0
- data/sql/catori_pg.sql +65 -0
- data/tests/saw.ape +0 -0
- data/tests/saw.flac +0 -0
- data/tests/saw.mp3 +0 -0
- data/tests/saw.mpc +0 -0
- data/tests/saw.ogg +0 -0
- data/tests/saw.wav +0 -0
- data/tests/test_audioinfo.rb +43 -0
- metadata +217 -0
data/ext/flac/extconf.rb
ADDED
data/ext/flac/flac.c
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#include "FLAC/metadata.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
#include <ctype.h>
|
4
|
+
#include <string.h>
|
5
|
+
static VALUE mFlac;
|
6
|
+
static VALUE cInfo;
|
7
|
+
// static VALUE rb_cinfo_new(VALUE self);
|
8
|
+
static VALUE rb_flac_info(VALUE module, VALUE filename);
|
9
|
+
static void set_tag(FLAC__StreamMetadata_VorbisComment_Entry * tag,
|
10
|
+
VALUE info);
|
11
|
+
void
|
12
|
+
Init_flac()
|
13
|
+
{
|
14
|
+
mFlac = rb_define_module("Flac");
|
15
|
+
cInfo = rb_define_class_under(mFlac, "Info", rb_cObject);
|
16
|
+
int i = 0;
|
17
|
+
#define NA 5
|
18
|
+
const char *attr2[NA] =
|
19
|
+
{ "time", "sample_rate", "channels", "bits_per_sample", "comments"
|
20
|
+
};
|
21
|
+
for (i = 0; i < NA; i++) {
|
22
|
+
rb_define_attr(cInfo, attr2[i], 1, 0);
|
23
|
+
}
|
24
|
+
|
25
|
+
rb_define_module_function(mFlac, "info", rb_flac_info, 1);
|
26
|
+
}
|
27
|
+
|
28
|
+
VALUE
|
29
|
+
rb_flac_info(VALUE self, VALUE filename)
|
30
|
+
{
|
31
|
+
FLAC__StreamMetadata si;
|
32
|
+
FLAC__StreamMetadata *tags;
|
33
|
+
// char *tag;
|
34
|
+
char *cfilename = STR2CSTR(filename);
|
35
|
+
FLAC__metadata_get_streaminfo(cfilename, &si);
|
36
|
+
int i = 0;
|
37
|
+
VALUE info = rb_class_new_instance(0, NULL, cInfo);
|
38
|
+
VALUE comments = rb_hash_new();
|
39
|
+
double time =
|
40
|
+
(double) si.data.stream_info.total_samples /
|
41
|
+
(double) si.data.stream_info.sample_rate;
|
42
|
+
rb_iv_set(info, "@sample_rate",
|
43
|
+
INT2FIX(si.data.stream_info.sample_rate));
|
44
|
+
rb_iv_set(info, "@channels", INT2FIX(si.data.stream_info.channels));
|
45
|
+
rb_iv_set(info, "@bits_per_sample",
|
46
|
+
INT2FIX(si.data.stream_info.bits_per_sample));
|
47
|
+
rb_iv_set(info, "@time", rb_float_new(time));
|
48
|
+
FLAC__metadata_get_tags(cfilename, &tags);
|
49
|
+
for (i = 0; i < tags->data.vorbis_comment.num_comments; i++) {
|
50
|
+
set_tag(&(tags->data.vorbis_comment.comments[i]), comments);
|
51
|
+
}
|
52
|
+
rb_iv_set(info, "@comments", comments);
|
53
|
+
FLAC__metadata_object_delete(tags);
|
54
|
+
return info;
|
55
|
+
}
|
56
|
+
|
57
|
+
static void
|
58
|
+
set_tag(FLAC__StreamMetadata_VorbisComment_Entry * tag, VALUE comments)
|
59
|
+
{
|
60
|
+
// printf("%s\n",tag->entry);
|
61
|
+
char *s = tag->entry;
|
62
|
+
char *equals_pos = strchr(s, '=');
|
63
|
+
VALUE key,
|
64
|
+
value;
|
65
|
+
if (0 != equals_pos) {
|
66
|
+
int i = 0;
|
67
|
+
|
68
|
+
for (; i < equals_pos - s; i++) {
|
69
|
+
s[i] = tolower(s[i]);
|
70
|
+
}
|
71
|
+
key = rb_str_new(s, equals_pos - s);
|
72
|
+
value = rb_str_new(equals_pos + 1, strlen(equals_pos + 1));
|
73
|
+
rb_hash_aset(comments, key, value);
|
74
|
+
}
|
75
|
+
}
|
data/ext/flac/mkmf.log
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
have_library: checking for main() in -lFLAC... -------------------- yes
|
2
|
+
|
3
|
+
"i686-pc-linux-gnu-gcc -o conftest -I. -I/usr/lib/ruby/1.8/i686-linux -I. -O2 -march=athlon-xp -m3dnow -msse -mfpmath=sse -mmmx -pipe -fno-strict-aliasing -fPIC -Wall conftest.c -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L. -rdynamic -Wl,-export-dynamic -lruby18-static -lFLAC -ldl -lcrypt -lm -lc"
|
4
|
+
checked program was:
|
5
|
+
/* begin */
|
6
|
+
1: /*top*/
|
7
|
+
2: int main() { return 0; }
|
8
|
+
3: int t() { void ((*volatile p)()); p = (void ((*)()))main; return 0; }
|
9
|
+
/* end */
|
10
|
+
|
11
|
+
--------------------
|
12
|
+
|
data/ext/flac/test.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
/*
|
2
|
+
* This file is Public Domain.
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <ruby.h>
|
6
|
+
#include <magic.h>
|
7
|
+
|
8
|
+
struct MagicCookie
|
9
|
+
{
|
10
|
+
magic_t cookie;
|
11
|
+
};
|
12
|
+
|
13
|
+
static VALUE cMahoro;
|
14
|
+
static VALUE eMahoroError;
|
15
|
+
|
16
|
+
static void
|
17
|
+
mahoro_free(ptr)
|
18
|
+
struct MagicCookie *ptr;
|
19
|
+
{
|
20
|
+
magic_close(ptr->cookie);
|
21
|
+
free(ptr);
|
22
|
+
}
|
23
|
+
|
24
|
+
static VALUE
|
25
|
+
mahoro_allocate(klass)
|
26
|
+
VALUE klass;
|
27
|
+
{
|
28
|
+
return Data_Wrap_Struct(klass, 0, mahoro_free, 0);
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE
|
32
|
+
mahoro_initialize(argc, argv, self)
|
33
|
+
int argc;
|
34
|
+
VALUE *argv, self;
|
35
|
+
{
|
36
|
+
int flags = MAGIC_NONE;
|
37
|
+
char *path = 0;
|
38
|
+
struct MagicCookie *ptr;
|
39
|
+
magic_t cookie;
|
40
|
+
VALUE vpath, vflags;
|
41
|
+
|
42
|
+
switch(rb_scan_args(argc, argv, "02", &vflags, &vpath)) {
|
43
|
+
case 2:
|
44
|
+
if(!NIL_P(vpath)) {
|
45
|
+
path = StringValuePtr(vpath);
|
46
|
+
}
|
47
|
+
/* fallthrough */
|
48
|
+
case 1:
|
49
|
+
flags = FIX2INT(vflags);
|
50
|
+
break;
|
51
|
+
}
|
52
|
+
|
53
|
+
if(!(cookie = magic_open(flags))) {
|
54
|
+
rb_raise(eMahoroError, "failed to initialize magic cookie");
|
55
|
+
}
|
56
|
+
|
57
|
+
if(magic_load(cookie, path)) {
|
58
|
+
rb_raise(eMahoroError, "failed to load database: %s",
|
59
|
+
magic_error(cookie));
|
60
|
+
}
|
61
|
+
|
62
|
+
ptr = ALLOC(struct MagicCookie);
|
63
|
+
ptr->cookie = cookie;
|
64
|
+
DATA_PTR(self) = ptr;
|
65
|
+
|
66
|
+
return self;
|
67
|
+
}
|
68
|
+
|
69
|
+
static VALUE
|
70
|
+
mahoro_file(self, path)
|
71
|
+
VALUE self, path;
|
72
|
+
{
|
73
|
+
const char *msg;
|
74
|
+
magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
|
75
|
+
|
76
|
+
if(!(msg = magic_file(cookie, StringValuePtr(path)))) {
|
77
|
+
rb_raise(eMahoroError, "failed lookup: %s", magic_error(cookie));
|
78
|
+
}
|
79
|
+
|
80
|
+
return rb_str_new2(msg);
|
81
|
+
}
|
82
|
+
|
83
|
+
static VALUE
|
84
|
+
mahoro_buffer(self, input)
|
85
|
+
VALUE self, input;
|
86
|
+
{
|
87
|
+
const char *msg;
|
88
|
+
magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
|
89
|
+
|
90
|
+
if(!(msg = magic_buffer(cookie, StringValuePtr(input),
|
91
|
+
RSTRING(StringValue(input))->len))) {
|
92
|
+
rb_raise(eMahoroError, "failed lookup: %s", magic_error(cookie));
|
93
|
+
}
|
94
|
+
|
95
|
+
return rb_str_new2(msg);
|
96
|
+
}
|
97
|
+
|
98
|
+
static VALUE
|
99
|
+
mahoro_set_flags(self, flags)
|
100
|
+
VALUE self, flags;
|
101
|
+
{
|
102
|
+
magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
|
103
|
+
|
104
|
+
return INT2FIX(magic_setflags(cookie, FIX2INT(flags)));
|
105
|
+
}
|
106
|
+
|
107
|
+
static VALUE
|
108
|
+
mahoro_check(argc, argv, self)
|
109
|
+
int argc;
|
110
|
+
VALUE *argv, self;
|
111
|
+
{
|
112
|
+
char *path = 0;
|
113
|
+
VALUE vpath;
|
114
|
+
magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
|
115
|
+
|
116
|
+
switch(rb_scan_args(argc, argv, "01", &vpath)) {
|
117
|
+
case 1:
|
118
|
+
if(!NIL_P(vpath)) {
|
119
|
+
path = StringValuePtr(vpath);
|
120
|
+
}
|
121
|
+
break;
|
122
|
+
}
|
123
|
+
|
124
|
+
if(!magic_check(cookie, path)) {
|
125
|
+
return Qtrue;
|
126
|
+
} else {
|
127
|
+
return Qfalse;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
static VALUE
|
132
|
+
mahoro_compile(klass, path)
|
133
|
+
VALUE klass, path;
|
134
|
+
{
|
135
|
+
magic_t cookie = magic_open(MAGIC_NONE);
|
136
|
+
|
137
|
+
if(magic_compile(cookie, StringValuePtr(path))) {
|
138
|
+
rb_raise(eMahoroError, "failed compile: %s", magic_error(cookie));
|
139
|
+
}
|
140
|
+
|
141
|
+
magic_close(cookie);
|
142
|
+
|
143
|
+
return Qtrue;
|
144
|
+
}
|
145
|
+
|
146
|
+
static VALUE
|
147
|
+
mahoro_load(self, path)
|
148
|
+
VALUE self, path;
|
149
|
+
{
|
150
|
+
magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
|
151
|
+
|
152
|
+
if(magic_load(cookie, StringValuePtr(path))) {
|
153
|
+
rb_raise(eMahoroError, "failed load: %s", magic_error(cookie));
|
154
|
+
}
|
155
|
+
|
156
|
+
return self;
|
157
|
+
}
|
158
|
+
|
159
|
+
void Init_mahoro(void)
|
160
|
+
{
|
161
|
+
cMahoro = rb_define_class("Mahoro", rb_cObject);
|
162
|
+
eMahoroError = rb_define_class_under(cMahoro, "Error", rb_eStandardError);
|
163
|
+
|
164
|
+
rb_const_set(cMahoro, rb_intern("NONE"), INT2FIX(MAGIC_NONE));
|
165
|
+
rb_const_set(cMahoro, rb_intern("DEBUG"), INT2FIX(MAGIC_DEBUG));
|
166
|
+
rb_const_set(cMahoro, rb_intern("SYMLINK"), INT2FIX(MAGIC_SYMLINK));
|
167
|
+
rb_const_set(cMahoro, rb_intern("COMPRESS"), INT2FIX(MAGIC_COMPRESS));
|
168
|
+
rb_const_set(cMahoro, rb_intern("DEVICES"), INT2FIX(MAGIC_DEVICES));
|
169
|
+
rb_const_set(cMahoro, rb_intern("MIME"), INT2FIX(MAGIC_MIME));
|
170
|
+
rb_const_set(cMahoro, rb_intern("CONTINUE"), INT2FIX(MAGIC_CONTINUE));
|
171
|
+
rb_const_set(cMahoro, rb_intern("CHECK"), INT2FIX(MAGIC_CHECK));
|
172
|
+
rb_const_set(cMahoro, rb_intern("PRESERVE_ATIME"),
|
173
|
+
INT2FIX(MAGIC_PRESERVE_ATIME));
|
174
|
+
rb_const_set(cMahoro, rb_intern("RAW"), INT2FIX(MAGIC_RAW));
|
175
|
+
rb_const_set(cMahoro, rb_intern("ERROR"), INT2FIX(MAGIC_ERROR));
|
176
|
+
|
177
|
+
rb_define_alloc_func(cMahoro, mahoro_allocate);
|
178
|
+
rb_define_method(cMahoro, "initialize", mahoro_initialize, -1);
|
179
|
+
rb_define_method(cMahoro, "file", mahoro_file, 1);
|
180
|
+
rb_define_method(cMahoro, "buffer", mahoro_buffer, 1);
|
181
|
+
rb_define_method(cMahoro, "flags=", mahoro_set_flags, 1);
|
182
|
+
rb_define_method(cMahoro, "valid?", mahoro_check, -1);
|
183
|
+
rb_define_singleton_method(cMahoro, "compile", mahoro_compile, 1);
|
184
|
+
rb_define_method(cMahoro, "load", mahoro_load, 1);
|
185
|
+
}
|
186
|
+
|
187
|
+
/* arch-tag: mahoro */
|
@@ -0,0 +1,24 @@
|
|
1
|
+
have_library: checking for magic_open() in -lmagic... -------------------- yes
|
2
|
+
|
3
|
+
"i686-pc-linux-gnu-gcc -o conftest -I. -I/usr/lib/ruby/1.8/i686-linux -I. -O2 -march=athlon-xp -m3dnow -msse -mfpmath=sse -mmmx -pipe -fno-strict-aliasing -fPIC conftest.c -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L. -rdynamic -Wl,-export-dynamic -lruby18-static -lmagic -ldl -lcrypt -lm -lc"
|
4
|
+
conftest.c: En la función ‘t’:
|
5
|
+
conftest.c:3: error: ‘magic_open’ no se declaró aquí (primer uso en esta función)
|
6
|
+
conftest.c:3: error: (Cada identificador no declarado solamente se reporta una vez
|
7
|
+
conftest.c:3: error: ara cada funcion en la que aparece.)
|
8
|
+
checked program was:
|
9
|
+
/* begin */
|
10
|
+
1: /*top*/
|
11
|
+
2: int main() { return 0; }
|
12
|
+
3: int t() { void ((*volatile p)()); p = (void ((*)()))magic_open; return 0; }
|
13
|
+
/* end */
|
14
|
+
|
15
|
+
"i686-pc-linux-gnu-gcc -o conftest -I. -I/usr/lib/ruby/1.8/i686-linux -I. -O2 -march=athlon-xp -m3dnow -msse -mfpmath=sse -mmmx -pipe -fno-strict-aliasing -fPIC conftest.c -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L. -rdynamic -Wl,-export-dynamic -lruby18-static -lmagic -ldl -lcrypt -lm -lc"
|
16
|
+
checked program was:
|
17
|
+
/* begin */
|
18
|
+
1: /*top*/
|
19
|
+
2: int main() { return 0; }
|
20
|
+
3: int t() { magic_open(); return 0; }
|
21
|
+
/* end */
|
22
|
+
|
23
|
+
--------------------
|
24
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'mahoro'
|
5
|
+
|
6
|
+
class MahoroTestCase < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
@m = Mahoro.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_file
|
14
|
+
@m.flags = Mahoro::NONE
|
15
|
+
assert_equal('ASCII C program text', @m.file('mahoro.c'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_mime_file
|
19
|
+
@m.flags = Mahoro::MIME
|
20
|
+
assert_equal('text/x-c; charset=us-ascii', @m.file('mahoro.c'))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_buffer
|
24
|
+
@m.flags = Mahoro::NONE
|
25
|
+
assert_equal('ASCII C program text',
|
26
|
+
@m.buffer(File.read('mahoro.c')))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_mime_buffer
|
30
|
+
@m.flags = Mahoro::MIME
|
31
|
+
assert_equal('text/x-c; charset=us-ascii',
|
32
|
+
@m.buffer(File.read('mahoro.c')))
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_valid
|
36
|
+
assert(@m.valid?, 'Default database was not valid.')
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# arch-tag: test
|
data/ext/mpc/extconf.rb
ADDED
data/ext/mpc/id3tag.c
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
/*
|
2
|
+
* Musepack audio compression
|
3
|
+
* Copyright (C) 1999-2004 Buschmann/Klemm/Piecha/Wolf
|
4
|
+
*
|
5
|
+
* This library is free software; you can redistribute it and/or
|
6
|
+
* modify it under the terms of the GNU Lesser General Public
|
7
|
+
* License as published by the Free Software Foundation; either
|
8
|
+
* version 2.1 of the License, or (at your option) any later version.
|
9
|
+
*
|
10
|
+
* This library is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
* Lesser General Public License for more details.
|
14
|
+
*
|
15
|
+
* You should have received a copy of the GNU Lesser General Public
|
16
|
+
* License along with this library; if not, write to the Free Software
|
17
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
*/
|
19
|
+
|
20
|
+
#include <string.h>
|
21
|
+
#include "mppdec.h"
|
22
|
+
|
23
|
+
|
24
|
+
/*
|
25
|
+
* List of known Genres. 256 genres are possible with version 1/1.1 tags,
|
26
|
+
* but not yet used.
|
27
|
+
*/
|
28
|
+
|
29
|
+
static const char* GenreList [] = {
|
30
|
+
"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
|
31
|
+
"Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
|
32
|
+
"Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
|
33
|
+
"Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient",
|
34
|
+
"Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical",
|
35
|
+
"Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
|
36
|
+
"AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
|
37
|
+
"Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
|
38
|
+
"Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
|
39
|
+
"Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap",
|
40
|
+
"Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave",
|
41
|
+
"Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal",
|
42
|
+
"Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll",
|
43
|
+
"Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion",
|
44
|
+
"Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
|
45
|
+
"Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock",
|
46
|
+
"Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour",
|
47
|
+
"Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony",
|
48
|
+
"Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club",
|
49
|
+
"Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
|
50
|
+
"Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
|
51
|
+
"Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
|
52
|
+
"Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta",
|
53
|
+
"Heavy Metal", "Black Metal", "Crossover", "Contemporary C",
|
54
|
+
"Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
|
55
|
+
"SynthPop"
|
56
|
+
};
|
57
|
+
|
58
|
+
|
59
|
+
/*
|
60
|
+
* Copies src to dst. Copying is stopped at `\0' char is detected or if
|
61
|
+
* len chars are copied.
|
62
|
+
* Trailing blanks are removed and the string is `\0` terminated.
|
63
|
+
*/
|
64
|
+
|
65
|
+
static void
|
66
|
+
memcpy_crop ( char* dst, const char* src, size_t len )
|
67
|
+
{
|
68
|
+
size_t i;
|
69
|
+
|
70
|
+
for ( i = 0; i < len; i++ )
|
71
|
+
if ( src[i] != '\0' )
|
72
|
+
dst[i] = src[i];
|
73
|
+
else
|
74
|
+
break;
|
75
|
+
|
76
|
+
// dst[i] points behind the string contents
|
77
|
+
|
78
|
+
while ( i > 0 && dst [i-1] == ' ' )
|
79
|
+
i--;
|
80
|
+
dst [i] = '\0';
|
81
|
+
}
|
82
|
+
|
83
|
+
|
84
|
+
/*
|
85
|
+
* Evaluate ID version 1/1.1 tags of a file given by 'fp' and fills out Tag
|
86
|
+
* information in 'tip'. Tag information also contains the effective file
|
87
|
+
* length (without the tags if tags are present). Return 1 if there is
|
88
|
+
* usable information inside the file. Note there's also the case possible
|
89
|
+
* that the file contains empty tags, the the file size is truncated by the
|
90
|
+
* 128 bytes but the function returns 0.
|
91
|
+
*
|
92
|
+
* If there're no tags, all strings containing '\0', the Genre pointer is
|
93
|
+
* NULL and GenreNo and TrackNo are -1.
|
94
|
+
*/
|
95
|
+
|
96
|
+
Int
|
97
|
+
Read_ID3V1_Tags ( FILE_T fp, TagInfo_t* tip )
|
98
|
+
{
|
99
|
+
Uint8_t tmp [128];
|
100
|
+
OFF_T file_pos;
|
101
|
+
|
102
|
+
memset ( tip, 0, sizeof(*tip) );
|
103
|
+
tip->GenreNo = -1;
|
104
|
+
tip->TrackNo = -1;
|
105
|
+
|
106
|
+
if ( -1 == (file_pos = FILEPOS (fp)) )
|
107
|
+
return 0;
|
108
|
+
if ( -1 == SEEK ( fp, -128L, SEEK_END ) )
|
109
|
+
return 0;
|
110
|
+
|
111
|
+
tip->FileSize = FILEPOS (fp);
|
112
|
+
if ( 128 != READ ( fp, tmp, 128 ) )
|
113
|
+
return 0;
|
114
|
+
SEEK ( fp, file_pos, SEEK_SET );
|
115
|
+
|
116
|
+
if ( 0 != memcmp ( tmp, "TAG", 3 ) ) {
|
117
|
+
tip->FileSize += 128;
|
118
|
+
return 0;
|
119
|
+
}
|
120
|
+
|
121
|
+
if ( !tmp[3] && !tmp[33] && !tmp[63] && !tmp[93] && !tmp[97] )
|
122
|
+
return 0;
|
123
|
+
|
124
|
+
memcpy_crop ( tip->Title , tmp + 3, 30 );
|
125
|
+
memcpy_crop ( tip->Artist , tmp + 33, 30 );
|
126
|
+
memcpy_crop ( tip->Album , tmp + 63, 30 );
|
127
|
+
memcpy_crop ( tip->Year , tmp + 93, 4 );
|
128
|
+
memcpy_crop ( tip->Comment, tmp + 97, 30 );
|
129
|
+
|
130
|
+
strcpy ( tip->Genre, tmp[127] < sizeof(GenreList)/sizeof(*GenreList) ?
|
131
|
+
GenreList [tip->GenreNo = tmp[127]] : "???" );
|
132
|
+
|
133
|
+
// Index 0 may be true if file is very short
|
134
|
+
if ( tmp[125] == 0 && (tmp[126] != 0 || tip->FileSize < 66000 ) )
|
135
|
+
sprintf ( tip->Track, "[%02d]", tip->TrackNo = tmp[126] );
|
136
|
+
else
|
137
|
+
strcpy ( tip->Track, " " );
|
138
|
+
|
139
|
+
return 1;
|
140
|
+
}
|
141
|
+
|
142
|
+
|
143
|
+
struct APETagFooterStruct {
|
144
|
+
Uint8_t ID [8]; // should equal 'APETAGEX'
|
145
|
+
Uint8_t Version [4]; // currently 1000 (version 1.000)
|
146
|
+
Uint8_t Length [4]; // the complete size of the tag, including this footer
|
147
|
+
Uint8_t TagCount [4]; // the number of fields in the tag
|
148
|
+
Uint8_t Flags [4]; // the tag flags (none currently defined)
|
149
|
+
Uint8_t Reserved [8]; // reserved for later use
|
150
|
+
};
|
151
|
+
|
152
|
+
|
153
|
+
static Uint32_t
|
154
|
+
Read_LE_Uint32 ( const Uint8_t* p )
|
155
|
+
{
|
156
|
+
return ((Uint32_t)p[0] << 0) |
|
157
|
+
((Uint32_t)p[1] << 8) |
|
158
|
+
((Uint32_t)p[2] << 16) |
|
159
|
+
((Uint32_t)p[3] << 24);
|
160
|
+
}
|
161
|
+
|
162
|
+
|
163
|
+
#define TAG_ANALYZE(item,elem) \
|
164
|
+
if ( 0 == memcmp (p, #item, sizeof #item ) ) { \
|
165
|
+
p += sizeof #item; \
|
166
|
+
memcpy ( tip->elem, p, len ); \
|
167
|
+
p += len; \
|
168
|
+
} else
|
169
|
+
|
170
|
+
|
171
|
+
Int
|
172
|
+
Read_APE_Tags ( FILE_T fp, TagInfo_t* tip )
|
173
|
+
{
|
174
|
+
OFF_T file_pos;
|
175
|
+
Uint32_t len;
|
176
|
+
Uint32_t flags;
|
177
|
+
unsigned char buff [8192];
|
178
|
+
unsigned char* p;
|
179
|
+
unsigned char* end;
|
180
|
+
struct APETagFooterStruct T;
|
181
|
+
Uint32_t TagLen;
|
182
|
+
Uint32_t TagCount;
|
183
|
+
Uint32_t tmp;
|
184
|
+
|
185
|
+
memset ( tip, 0, sizeof(*tip) );
|
186
|
+
tip->GenreNo = -1;
|
187
|
+
tip->TrackNo = -1;
|
188
|
+
|
189
|
+
if ( -1 == (file_pos = FILEPOS (fp)) )
|
190
|
+
goto notag;
|
191
|
+
if ( -1 == SEEK ( fp, 0L, SEEK_END ) )
|
192
|
+
goto notag;
|
193
|
+
tip->FileSize = FILEPOS (fp);
|
194
|
+
if ( -1 == SEEK ( fp, -(long)sizeof T, SEEK_END ) )
|
195
|
+
goto notag;
|
196
|
+
if ( sizeof(T) != READ ( fp, &T, sizeof T ) )
|
197
|
+
goto notag;
|
198
|
+
if ( memcmp ( T.ID, "APETAGEX", sizeof(T.ID) ) != 0 )
|
199
|
+
goto notag;
|
200
|
+
tmp = Read_LE_Uint32 (T.Version);
|
201
|
+
if ( tmp != 1000 && tmp != 2000 )
|
202
|
+
goto notag;
|
203
|
+
TagLen = Read_LE_Uint32 (T.Length);
|
204
|
+
if ( TagLen <= sizeof T )
|
205
|
+
goto notag;
|
206
|
+
if ( -1 == SEEK ( fp, -(long)TagLen, SEEK_END ) )
|
207
|
+
goto notag;
|
208
|
+
tip->FileSize = FILEPOS (fp);
|
209
|
+
memset ( buff, 0, sizeof(buff) );
|
210
|
+
if ( TagLen - sizeof T != READ ( fp, buff, TagLen - sizeof T ) )
|
211
|
+
goto notag;
|
212
|
+
SEEK ( fp, file_pos, SEEK_SET );
|
213
|
+
|
214
|
+
TagCount = Read_LE_Uint32 (T.TagCount);
|
215
|
+
end = buff + TagLen - sizeof T;
|
216
|
+
for ( p = buff; p < end && TagCount--; ) {
|
217
|
+
len = Read_LE_Uint32 ( p ); p += 4;
|
218
|
+
flags = Read_LE_Uint32 ( p ); p += 4;
|
219
|
+
TAG_ANALYZE ( Title , Title )
|
220
|
+
TAG_ANALYZE ( Album , Album )
|
221
|
+
TAG_ANALYZE ( Artist , Artist )
|
222
|
+
TAG_ANALYZE ( Album , Album )
|
223
|
+
TAG_ANALYZE ( Comment, Comment )
|
224
|
+
TAG_ANALYZE ( Track , Track )
|
225
|
+
TAG_ANALYZE ( Year , Year )
|
226
|
+
TAG_ANALYZE ( Genre , Genre )
|
227
|
+
{
|
228
|
+
p += strlen(p) + 1 + len;
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
if ( tip->Track[0] != '\0' )
|
233
|
+
sprintf ( tip->Track, "[%02d]", tip->TrackNo = atoi (tip->Track) );
|
234
|
+
else
|
235
|
+
strcpy ( tip->Track, " " );
|
236
|
+
|
237
|
+
/* genre is not yet entirely decoded */
|
238
|
+
return 1;
|
239
|
+
|
240
|
+
notag:
|
241
|
+
SEEK ( fp, file_pos, SEEK_SET );
|
242
|
+
return 0;
|
243
|
+
}
|
244
|
+
|
245
|
+
/* end of id3tag.c */
|