1 //=========================================================================
2 // FILENAME : tagutils-dsf.c
3 // DESCRIPTION : DSF metadata reader
4 //=========================================================================
5 // Copyright (c) 2014 Takeshich NAKAMURA
6 // based on tagutils-mp3.c
7 //=========================================================================
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define GET_DSF_INT64(p) ((((uint64_t)((p)[7])) << 56) | \
25 (((uint64_t)((p)[6])) << 48) | \
26 (((uint64_t)((p)[5])) << 40) | \
27 (((uint64_t)((p)[4])) << 32) | \
28 (((uint64_t)((p)[3])) << 24) | \
29 (((uint64_t)((p)[2])) << 16) | \
30 (((uint64_t)((p)[1])) << 8) | \
31 (((uint64_t)((p)[0]))))
33 #define GET_DSF_INT32(p) ((((uint8_t)((p)[3])) << 24) | \
34 (((uint8_t)((p)[2])) << 16) | \
35 (((uint8_t)((p)[1])) << 8) | \
36 (((uint8_t)((p)[0]))))
39 _get_dsftags(char *file
, struct song_metadata
*psong
)
41 struct id3_tag
*pid3tag
;
42 struct id3_frame
*pid3frame
;
46 unsigned char *utf8_text
;
47 int genre
= WINAMP_GENRE_UNKNOWN
;
50 id3_ucs4_t
const *native_text
;
52 int got_numeric_genre
;
53 id3_byte_t
const *image
;
54 id3_length_t image_size
= 0;
57 struct id3header
*pid3
;
59 unsigned char hdr
[28] = { 0 };
60 uint64_t total_size
= 0;
61 uint64_t pointer_to_metadata_chunk
= 0;
62 uint64_t metadata_chunk_size
= 0;
63 unsigned char *id3tagbuf
= NULL
;
65 //DEBUG DPRINTF(E_DEBUG,L_SCANNER,"Getting DSF file info\n");
67 if ((fp
= fopen(file
, "rb")) == NULL
)
69 DPRINTF(E_WARN
, L_SCANNER
, "Could not create file handle\n");
74 if (!(len
= fread(hdr
, len
, 1, fp
)))
76 DPRINTF(E_WARN
, L_SCANNER
, "Could not read DSD Chunk from %s\n", file
);
81 if (strncmp((char*)hdr
, "DSD ", 4))
83 DPRINTF(E_WARN
, L_SCANNER
, "Invalid DSD Chunk header in %s\n", file
);
88 total_size
= GET_DSF_INT64(hdr
+ 12);
89 pointer_to_metadata_chunk
= GET_DSF_INT64(hdr
+ 20);
91 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", total_size);
92 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", pointer_to_metadata_chunk);
93 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", metadata_chunk_size);
95 //check invalid metadata
99 DPRINTF(E_INFO
, L_SCANNER
, "Invalid TotalDataSize in %s\n", file
);
103 if (pointer_to_metadata_chunk
== 0)
106 DPRINTF(E_INFO
, L_SCANNER
, "Metadata doesn't exist %s\n", file
);
110 if (total_size
> pointer_to_metadata_chunk
)
112 metadata_chunk_size
= total_size
- pointer_to_metadata_chunk
;
117 DPRINTF(E_INFO
, L_SCANNER
, "Invalid PointerToMetadata in %s\n", file
);
121 fseeko(fp
, pointer_to_metadata_chunk
, SEEK_SET
);
123 id3tagbuf
= (unsigned char*)malloc(sizeof(unsigned char) * metadata_chunk_size
);
124 if (id3tagbuf
== NULL
)
127 DPRINTF(E_WARN
, L_SCANNER
, "Out of memory.Big MetadataSize in %s\n", file
);
130 memset(id3tagbuf
, 0, sizeof(unsigned char) * metadata_chunk_size
);
132 if (!(len
= fread(id3tagbuf
, metadata_chunk_size
, 1, fp
)))
136 DPRINTF(E_WARN
, L_SCANNER
, "Could not read Metadata Chunk from %s\n", file
);
140 pid3tag
= id3_tag_parse(id3tagbuf
, metadata_chunk_size
);
148 DPRINTF(E_WARN
, L_SCANNER
, "Cannot get ID3 tag for %s\n", file
);
152 pid3
= (struct id3header
*)id3tagbuf
;
154 if (strncmp((char*)pid3
->id
, "ID3", 3) == 0)
158 /* found an ID3 header... */
159 snprintf(tagversion
, sizeof(tagversion
), "ID3v2.%d.%d",
160 pid3
->version
[0], pid3
->version
[1]);
161 psong
->tagversion
= strdup(tagversion
);
166 while ((pid3frame
= id3_tag_findframe(pid3tag
, "", index
)))
174 if (!strcmp(pid3frame
->id
, "YTCP")) /* for id3v2.2 */
176 psong
->compilation
= 1;
177 DPRINTF(E_DEBUG
, L_SCANNER
, "Compilation: %d [%s]\n", psong
->compilation
, basename(file
));
179 else if (!strcmp(pid3frame
->id
, "APIC") && !image_size
)
181 if ((strcmp((char*)id3_field_getlatin1(&pid3frame
->fields
[1]), "image/jpeg") == 0) ||
182 (strcmp((char*)id3_field_getlatin1(&pid3frame
->fields
[1]), "image/jpg") == 0) ||
183 (strcmp((char*)id3_field_getlatin1(&pid3frame
->fields
[1]), "jpeg") == 0))
185 image
= id3_field_getbinarydata(&pid3frame
->fields
[4], &image_size
);
188 psong
->image
= malloc(image_size
);
189 memcpy(psong
->image
, image
, image_size
);
190 psong
->image_size
= image_size
;
191 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Found thumbnail: %d\n", psong->image_size);
196 if (((pid3frame
->id
[0] == 'T') || (strcmp(pid3frame
->id
, "COMM") == 0)) &&
197 (id3_field_getnstrings(&pid3frame
->fields
[1])))
202 native_text
= id3_field_getstrings(&pid3frame
->fields
[1], 0);
208 utf8_text
= _get_utf8_text(native_text
); // through iconv
210 utf8_text
= (unsigned char*)id3_ucs4_utf8duplicate(native_text
);
212 if (!strcmp(pid3frame
->id
, "TIT2"))
215 psong
->title
= (char*)utf8_text
;
217 else if (!strcmp(pid3frame
->id
, "TPE1"))
220 psong
->contributor
[ROLE_ARTIST
] = (char*)utf8_text
;
222 else if (!strcmp(pid3frame
->id
, "TALB"))
225 psong
->album
= (char*)utf8_text
;
227 else if (!strcmp(pid3frame
->id
, "TCOM"))
230 psong
->contributor
[ROLE_COMPOSER
] = (char*)utf8_text
;
232 else if (!strcmp(pid3frame
->id
, "TIT1"))
235 psong
->grouping
= (char*)utf8_text
;
237 else if (!strcmp(pid3frame
->id
, "TPE2"))
240 psong
->contributor
[ROLE_BAND
] = (char*)utf8_text
;
242 else if (!strcmp(pid3frame
->id
, "TPE3"))
245 psong
->contributor
[ROLE_CONDUCTOR
] = (char*)utf8_text
;
247 else if (!strcmp(pid3frame
->id
, "TCON"))
250 psong
->genre
= (char*)utf8_text
;
251 got_numeric_genre
= 0;
254 if (!strlen(psong
->genre
))
256 genre
= WINAMP_GENRE_UNKNOWN
;
257 got_numeric_genre
= 1;
259 else if (isdigit(psong
->genre
[0]))
261 genre
= atoi(psong
->genre
);
262 got_numeric_genre
= 1;
264 else if ((psong
->genre
[0] == '(') && (isdigit(psong
->genre
[1])))
266 genre
= atoi((char*)&psong
->genre
[1]);
267 got_numeric_genre
= 1;
270 if (got_numeric_genre
)
272 if ((genre
< 0) || (genre
> WINAMP_GENRE_UNKNOWN
))
273 genre
= WINAMP_GENRE_UNKNOWN
;
275 psong
->genre
= strdup(winamp_genre
[genre
]);
279 else if (!strcmp(pid3frame
->id
, "COMM"))
282 psong
->comment
= (char*)utf8_text
;
284 else if (!strcmp(pid3frame
->id
, "TPOS"))
286 tmp
= (char*)utf8_text
;
290 psong
->total_discs
= atoi(tmp
);
292 psong
->disc
= atoi((char*)utf8_text
);
294 else if (!strcmp(pid3frame
->id
, "TRCK"))
296 tmp
= (char*)utf8_text
;
300 psong
->total_tracks
= atoi(tmp
);
302 psong
->track
= atoi((char*)utf8_text
);
304 else if (!strcmp(pid3frame
->id
, "TDRC"))
306 psong
->year
= atoi((char*)utf8_text
);
308 else if (!strcmp(pid3frame
->id
, "TLEN"))
310 psong
->song_length
= atoi((char*)utf8_text
);
312 else if (!strcmp(pid3frame
->id
, "TBPM"))
314 psong
->bpm
= atoi((char*)utf8_text
);
316 else if (!strcmp(pid3frame
->id
, "TCMP"))
318 psong
->compilation
= (char)atoi((char*)utf8_text
);
324 if ((!used
) && (have_utf8
) && (utf8_text
))
328 if ((!strcmp(pid3frame
->id
, "COMM")) && (pid3frame
->nfields
== 4))
330 native_text
= id3_field_getstring(&pid3frame
->fields
[2]);
333 utf8_text
= (unsigned char*)id3_ucs4_utf8duplicate(native_text
);
334 if ((utf8_text
) && (strncasecmp((char*)utf8_text
, "iTun", 4) != 0))
339 native_text
= id3_field_getfullstring(&pid3frame
->fields
[3]);
342 utf8_text
= (unsigned char*)id3_ucs4_utf8duplicate(native_text
);
345 free(psong
->comment
);
346 psong
->comment
= (char*)utf8_text
;
360 id3_tag_delete(pid3tag
);
363 //DPRINTF(E_DEBUG, L_SCANNER, "Got id3tag successfully for file=%s\n", file);
368 _get_dsffileinfo(char *file
, struct song_metadata
*psong
)
372 unsigned char hdr
[len
];
374 uint32_t samplingfrequency
;
375 uint32_t bitpersample
;
376 uint64_t samplecount
;
378 if ((fp
= fopen(file
, "rb")) == NULL
)
380 DPRINTF(E_WARN
, L_SCANNER
, "Could not create file handle\n");
384 if (!(len
= fread(hdr
, len
, 1, fp
)))
386 DPRINTF(E_WARN
, L_SCANNER
, "Could not read chunks from %s\n", file
);
391 if (strncmp((char*)hdr
, "DSD ", 4))
393 DPRINTF(E_WARN
, L_SCANNER
, "Invalid DSD Chunk headerin %s\n", file
);
398 if (strncmp((char*)hdr
+ 28, "fmt ", 4))
400 DPRINTF(E_WARN
, L_SCANNER
, "Invalid fmt Chunk header in %s\n", file
);
405 channelnum
= GET_DSF_INT32(hdr
+ 52);
406 samplingfrequency
= GET_DSF_INT32(hdr
+ 56);
407 bitpersample
= GET_DSF_INT32(hdr
+ 60);
408 samplecount
= GET_DSF_INT64(hdr
+ 64);
410 psong
->bitrate
= channelnum
* samplingfrequency
* bitpersample
;
411 psong
->samplesize
= bitpersample
;
412 psong
->samplerate
= samplingfrequency
;
413 psong
->song_length
= (samplecount
/ samplingfrequency
) * 1000;
414 psong
->channels
= channelnum
;
416 DPRINTF(E_MAXDEBUG
, L_SCANNER
, "Got file info successfully for %s\n", file
);
417 //DEBUG DPRINTF(E_MAXDEBUG, L_SCANNER, "bitrate is %d\n", psong->bitrate);
418 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplesize is %d\n", psong->samplesize);
419 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplerate is %d\n", psong->samplerate);
420 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "song_length is %d\n", psong->song_length);
421 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "channels are %d\n", psong->channels);
422 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplecount are %lld\n", samplecount);
425 xasprintf(&(psong
->dlna_pn
), "DSF");