catori 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 */
|