1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
| #include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
// Define names for better readable code
#define MP3_STEREO 0x0
#define MP3_JOINT_STEREO 0x1
#define MP3_DUAL_CHANNEL 0x2
#define MP3_SINGLE_CHANNEL 0x3
#define MPEG_V1 0x3
#define MPEG_V2 0x2
#define MPEG_V25 0x0
#define MPEG_LAYER1 0x3
#define MPEG_LAYER2 0x2
#define MPEG_LAYER3 0x1
// Bitrate index
int bitrateIndex[5][16] = {{0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448,-1},
{0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384,-1},
{0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,-1},
{0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256,-1},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,-1}};
// Samplerate index
int samplerateIndex[4][4] = {{11025,12000,8000},{0,0,0},{22500,24000,16000},{44100,48000, 32000}};
// Genre index. Including WinAMP genres
char *genreIndex[] = {"Blues","Classic Rock","Country","Dance","Disco","Funk","Grunge","Hip-Hop","Jazz","Metal","New Age","Oldies","Other","Pop","R&B","Rap",
"Reggae","Rock","Techno","Industrial","Alternative","Ska","Death Metal","Pranks","Soundtrack","Euro-Techno","Ambient","Trip-Hop","Vocal",
"Jazz+Funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound Clip","Gospel","Noise","AlternRock","Bass","Soul",
"Punk","Space","Meditative","Instrumental Pop","Instrumental Rock","Ethnic","Gothic","Darkwave","Techno-Industrial","Electronic","Pop-Folk",
"Eurodance","Dream","Southern Rock","Comedy","Cult","Gangsta","Top 40","Christian Rap","Pop/Funk","Jungle","Native American","Cabaret",
"New Wave","Psychadelic","Rave","Showtunes","Trailer","Lo-Fi","Tribal","Acid Punk","Acid Jazz","Polka","Retro","Musical","Rock & Roll","Hard Rock",
"Folk","Folk-Rock","National Folk","Swing","Fast Fusion","Bebob","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic Rock","Progressive Rock",
"Psychedelic Rock","Symphonic Rock","Slow Rock","Big Band","Chorus","Easy Listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber Music",
"Sonata","Symphony","Booty Brass","Primus","Porn Groove","Satire","Slow Jam","Club","Tango","Samba","Folklore","Ballad","Poweer Ballad","Rhytmic Soul",
"Freestyle","Duet","Punk","Drum Solo","A Capela","Euro-House","Dance Hall"};
// Channels
char *mpeg_channels[] = {"Stereo", "Joint Stereo", "Dual Audio", "Mono"};
// Versions
char *mpeg_versions[] = {"v2.5", "Reserved", "v2", "v1"};
// MPEG Layers
char *mpeg_layers[] = {"Reserved", "MPEG Layer3", "MPEG Layer2", "MPEG Layer1"};
// MP3 header info struct
struct mp3 {
int versionid;
int layer;
// int crc;
int bitrate;
int frequency;
int channels;
int filesize;
int length;
int frames;
};
// MP3 tag struct
struct id3v1tag {
char title[31];
char artist[31];
char album[31];
char year[5];
char comment[31];
int genre;
};
// Listing-struct. For "contents" of a directory
struct content {
char *filename;
struct id3v1tag *v1tag;
int directory;
struct mp3 *info;
};
// Homedir to start checking. TODO: change to dynamic vars etc
char *homedir = "/home/mp3/";
// Listing of the content
struct content **listing;
// Number of entries in the listing
int ARRAYSIZE;
// Declares
struct mp3 *getMp3HeaderInfo(char *);
struct id3v1tag *getMp3ID3v1Tag(char *);
int ftype(char *);
int fsize(char *);
int main( int argc, char *argv[] ){
DIR *dirlist;
struct dirent *dp;
char *fullname;
int aantal=0;
int i;
struct content **templisting;
// Inital array size
ARRAYSIZE=8;
// Reserve some memory for the listing, and for a temporary string
listing = (struct content **)malloc(ARRAYSIZE*sizeof(struct content *));
fullname = (char *)malloc(1);
// Open the directory
dirlist = opendir(homedir);
// Loop throught the entire directory
while (dp!=NULL) {
// Read next entry in listing
dp = readdir(dirlist);
if (dp==NULL) {
// No entry found, so close the directory
closedir(dirlist);
} else {
// Entry found
// Get full path
fullname = (char *)realloc(fullname,strlen(homedir)+strlen(dp->d_name)+1);
strcpy(fullname, homedir);
strcat(fullname, dp->d_name);
if (ftype(fullname)==S_IFDIR){
// Print the directory
printf("d- %s\n",dp->d_name);
// Allocate memory for the mp3file/directory
listing[aantal] = (struct content *)malloc(sizeof(struct content));
listing[aantal]->filename = (char *)malloc(strlen(fullname)+1);
strcpy(listing[aantal]->filename,fullname);
listing[aantal]->directory = 1;
// Increase number of mp3files/directories
aantal++;
} else {
// Print the file
printf(" - %s\n",dp->d_name);
// Check for .mp3 extension ...
if (strcmp(fullname + strlen(fullname) - 4,".mp3")==0){
// ... if so ...
// Allocate memory for the mp3file/directory
listing[aantal] = (struct content *)malloc(sizeof(struct content));
listing[aantal]->filename = (char *)malloc(strlen(fullname)+1);
strcpy(listing[aantal]->filename,fullname);
listing[aantal]->directory = 0;
// get MP3 header info, and ID3 tag
listing[aantal]->info = getMp3HeaderInfo(listing[aantal]->filename);
listing[aantal]->v1tag = getMp3ID3v1Tag(listing[aantal]->filename);
printf(" > %s, %dkbps @ %dhz in %s sound. Duration: %ds\n",
mpeg_layers[listing[aantal]->info->layer],
listing[aantal]->info->bitrate,
listing[aantal]->info->frequency,
mpeg_channels[listing[aantal]->info->channels],
listing[aantal]->info->length);
printf(" > Title: %s\n > Artist: %s\n > Album: %s\n > Year: %s\n > Comment: %s\n > Genre: %s\n",
listing[aantal]->v1tag->title,
listing[aantal]->v1tag->artist,
listing[aantal]->v1tag->album,
listing[aantal]->v1tag->year,
listing[aantal]->v1tag->comment,
genreIndex[listing[aantal]->v1tag->genre]);
// Increase number of mp3files/directories
aantal++;
}
}
// If the array got too small, resize it
if (aantal>=ARRAYSIZE){
// Make the arraysize twice as big and reallocate memory for the listing
// printf("Resizing %d to %d\n",ARRAYSIZE,ARRAYSIZE<<1);
ARRAYSIZE = ARRAYSIZE << 1;
listing = (struct content **)realloc(listing, ARRAYSIZE*sizeof(struct content *));
}
}
}
// Print directory listing
for (i=0; i < aantal; i++){
printf("%d - %s\n",i,listing[i]->filename);
}
// Free memory
free(fullname);
}
// ftype: return the file type
int ftype(char *filename){
struct stat stbuf;
if (stat(filename, &stbuf) == -1) {
return -1;
}
return (stbuf.st_mode & S_IFMT);
}
// fsize: return the filesize
int fsize(char *filename){
FILE *mp3file;
int fsize;
mp3file = fopen(filename, "r");
fseek(mp3file, 0, SEEK_END);
fsize = ftell(mp3file);
fclose(mp3file);
return fsize;
}
// Returns a pointer to an id3 v1 tag
struct id3v1tag *getMp3ID3v1Tag(char *filename){
FILE *mp3file;
char tag[128];
struct id3v1tag *tmpID3Tag;
int hasRead;
// Allocate space for ID3 tag
tmpID3Tag = (struct id3v1tag *)malloc(sizeof(struct id3v1tag));
// Open file for reading
mp3file = fopen(filename, "r");
// Seek to the end of the file minus 128 bytes. This is where the id3tag v1 has to be
fseek(mp3file, -128, SEEK_END);
// Read 128 bytes
hasRead = fread(tag,128,1, mp3file);
// If read is successful AND the 128 bytes start with "TAG" ...
if (hasRead==1 && strncmp(&tag[0],"TAG",3)==0){
// ... Get all fields
// Title field, 30 chars
strncpy(&tmpID3Tag->title[0],&tag[3],30);
// Artist field, 30 chars
strncpy(&tmpID3Tag->artist[0],&tag[33],30);
// Album field, 30 chars
strncpy(&tmpID3Tag->album[0],&tag[63],30);
// Year field, 4 chars
strncpy(&tmpID3Tag->year[0],&tag[93],4);
// Comment field, 30 chars
strncpy(&tmpID3Tag->comment[0],&tag[97],30);
// Genre field, 1 char (index)
tmpID3Tag->genre=(int)tag[127];
}
fclose(mp3file);
return tmpID3Tag;
}
// Returns pointer to MP3 header info
struct mp3 *getMp3HeaderInfo(char *filename){
int headerFound = 0;
int hasRead = 1;
FILE *mp3file;
struct mp3 *tempMP3;
int whichone;
char syncHeader[1];
char header[3];
// Allocate memory for MP3-info block
tempMP3 = (struct mp3 *)malloc(sizeof(struct mp3));
// Open MP3 file for reading
mp3file = fopen(filename, "r");
// Search for a header as long as it isn't found, AND as long as no EOF
while(headerFound==0 && hasRead >= 1){
hasRead = fread(syncHeader,1,1, mp3file);
// Need a 0xFF byte (all 1's)
if (syncHeader[0]=='\xFF'){
fread(syncHeader,1,1, mp3file);
// And the first 3 bits (111ddddd) = 0x0E of the next byte need to be 1 also
if ((syncHeader[0] & 0xE0) == 0xE0){
headerFound = 1;
// Read header bytes
hasRead = fread(header+1,2,1, mp3file);
header[0] = syncHeader[0];
}
}
}
// If the header was found, parse it
if (headerFound==1){
// Grab version ID
tempMP3->versionid = (header[0] & 0x18)>>3;
// Get MPEG Layer
tempMP3->layer = (header[0] & 0x06)>>1;
switch(tempMP3->layer){
case MPEG_LAYER1:
if (tempMP3->versionid == MPEG_V1){
whichone = 0;
} else {
whichone = 3;
}
break;
case MPEG_LAYER2:
if (tempMP3->versionid == MPEG_V1){
whichone = 1;
} else {
whichone = 4;
}
break;
case MPEG_LAYER3:
if (tempMP3->versionid == MPEG_V1){
whichone = 2;
} else {
whichone = 4;
}
break;
default:
whichone = 0;
break;
}
// Derive the bitrate
tempMP3->bitrate = bitrateIndex[whichone][(header[1] & 0xF0)>>4];
// Get frequency according to versionid
tempMP3->frequency = samplerateIndex[tempMP3->versionid][(header[1] & 0x0C)>>2];
// Get channels
tempMP3->channels = (header[2] & 0xC0)>>6;
}
// Get the filesize
tempMP3->filesize = fsize(filename);
// Calculate MP3 length. Only correct for constant bitrate MP3s
// With MP3, 1 kbit = 1000 bit. So bitrate*1000 divided by 8 gives *125
tempMP3->length = tempMP3->filesize / (tempMP3->bitrate*125);
// TODO: Get number of frames. 0 for now...
tempMP3->frames = 0;
// Close file
fclose(mp3file);
// Return pointer to mp3info
return tempMP3;
} |