A modern, network-enabled music player platform built on Rockbox technology. rockboxd.tsiry-sandratraina.com
rust deno navidrome airplay libadwaita zig mpris snapcast mpd rockbox audio subsonic
2

Configure Feed

Select the types of activity you want to include in your feed.

rockboxd / lib / rbcodec / metadata / ay.c
4.0 kB 148 lines
1#include <stdio.h> 2#include <string.h> 3#include <stdlib.h> 4#include <ctype.h> 5#include <inttypes.h> 6#include "platform.h" 7 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 111static bool 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->FS_PREFIX(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}