summaryrefslogtreecommitdiff
path: root/apps/metadata/ay.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/metadata/ay.c')
-rw-r--r--apps/metadata/ay.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/apps/metadata/ay.c b/apps/metadata/ay.c
new file mode 100644
index 0000000000..8b737a7eba
--- /dev/null
+++ b/apps/metadata/ay.c
@@ -0,0 +1,148 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13/* Taken from blargg's Game_Music_Emu library */
14
15typedef unsigned char byte;
16
17/* AY file header */
18enum { header_size = 0x14 };
19struct header_t
20{
21 byte tag[8];
22 byte vers;
23 byte player;
24 byte unused[2];
25 byte author[2];
26 byte comment[2];
27 byte max_track;
28 byte first_track;
29 byte track_info[2];
30};
31
32struct file_t {
33 struct header_t const* header;
34 byte const* tracks;
35 byte const* end; /* end of file data */
36};
37
38static int get_be16( const void *a )
39{
40 return get_short_be( (void*) a );
41}
42
43/* Given pointer to 2-byte offset of data, returns pointer to data, or NULL if
44 * offset is 0 or there is less than min_size bytes of data available. */
45static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size )
46{
47 int offset = (int16_t) get_be16( ptr );
48 int pos = ptr - (byte const*) file->header;
49 int size = file->end - (byte const*) file->header;
50 int limit = size - min_size;
51 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit )
52 return NULL;
53 return ptr + offset;
54}
55
56static const char *parse_header( byte const in [], int size, struct file_t* out )
57{
58 if ( size < header_size )
59 return "wrong file type";
60
61 out->header = (struct header_t const*) in;
62 out->end = in + size;
63 struct header_t const* h = (struct header_t const*) in;
64 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) )
65 return "wrong file type";
66
67 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 );
68 if ( !out->tracks )
69 return "missing track data";
70
71 return 0;
72}
73
74static void copy_ay_fields( struct file_t const* file, struct mp3entry* id3, int track )
75{
76 int track_count = file->header->max_track + 1;
77
78 /* calculate track length based on number of subtracks */
79 if (track_count > 1) {
80 id3->length = file->header->max_track * 1000;
81 } else {
82 byte const* track_info = get_data( file, file->tracks + track * 4 + 2, 6 );
83 if (track_info)
84 id3->length = get_be16( track_info + 4 ) * (1000 / 50); /* frames to msec */
85 else id3->length = 120 * 1000;
86 }
87
88 if ( id3->length <= 0 )
89 id3->length = 120 * 1000; /* 2 minutes */
90
91 /* If meta info was found in the m3u skip next step */
92 if (id3->title && id3->title[0]) return;
93
94 /* If file has more than one track will
95 use file name as title */
96 char * tmp;
97 if (track_count <= 1) {
98 tmp = (char *) get_data( file, file->tracks + track * 4, 1 );
99 if ( tmp ) id3->title = tmp;
100 }
101
102 /* Author */
103 tmp = (char *) get_data( file, file->header->author, 1 );
104 if (tmp) id3->artist = tmp;
105
106 /* Comment */
107 tmp = (char *) get_data( file, file->header->comment, 1 );
108 if (tmp) id3->comment = tmp;
109}
110
111bool parse_ay_header(int fd, struct mp3entry *id3)
112{
113 /* Use the trackname part of the id3 structure as a temporary buffer */
114 unsigned char* buf = (unsigned char *)id3->id3v2buf;
115 struct file_t file;
116 int read_bytes;
117
118 lseek(fd, 0, SEEK_SET);
119 if ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) < header_size)
120 return false;
121
122 buf [ID3V2_BUF_SIZE] = '\0';
123 if ( parse_header( buf, read_bytes, &file ) )
124 return false;
125
126 copy_ay_fields( &file, id3, 0 );
127 return true;
128}
129
130bool get_ay_metadata(int fd, struct mp3entry* id3)
131{
132 char ay_type[8];
133 if ((lseek(fd, 0, SEEK_SET) < 0) ||
134 read(fd, ay_type, 8) < 8)
135 return false;
136
137 id3->vbr = false;
138 id3->filesize = filesize(fd);
139
140 id3->bitrate = 706;
141 id3->frequency = 44100;
142
143 /* Make sure this is a ZX Ay file */
144 if (memcmp( ay_type, "ZXAYEMUL", 8 ) != 0)
145 return false;
146
147 return parse_ay_header(fd, id3);
148}