1 module mp3decoderex; 2 3 public import mp3decoder; 4 5 struct mp3dec_file_info_t { 6 mp3d_sample_t* buffer; 7 size_t samples; /* channels included, byte size = samples*sizeof(short) */ 8 int channels, hz, layer, avg_bitrate_kbps; 9 } 10 11 alias MP3D_PROGRESS_CB = int function(void* user_data, size_t file_size, size_t offset, ref mp3dec_frame_info_t info); 12 13 alias MP3D_ITERATE_CB = int function(void* user_data, ref const(ubyte)* frame, int frame_size, size_t offset, ref mp3dec_frame_info_t info); 14 15 mp3dec_file_info_t mp3dec_load(ref mp3dec_t dec, string file_name, MP3D_PROGRESS_CB progress_cb, void* user_data) { 16 import std.mmfile; 17 auto file = new MmFile(file_name, MmFile.Mode.read, 0, null, 0); 18 scope (exit) { 19 file.destroy(); 20 } 21 mp3dec_file_info_t info; 22 mp3dec_load_buf(dec, cast(ubyte[]) file[0 .. $], info, progress_cb, user_data); 23 return info; 24 } 25 26 int mp3dec_iterate(string file_name, MP3D_ITERATE_CB callback, void* user_data) { 27 import std.mmfile; 28 auto file = new MmFile(file_name, MmFile.Mode.read, 0, null, 0); 29 scope (exit) { 30 file.destroy(); 31 } 32 mp3dec_iterate_buf(cast(ubyte[]) file[0 .. $], callback, user_data); 33 return 0; 34 } 35 36 private size_t mp3dec_skip_id3v2(const(ubyte)* buf, size_t buf_size) { 37 import core.stdc.string : strncmp; 38 if (buf_size > 10 && !strncmp(cast(char*) buf, "ID3", 3)) { 39 return (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; 40 } 41 return 0; 42 } 43 44 private void mp3dec_load_buf(ref mp3dec_t dec, const(ubyte)[] buffer, ref mp3dec_file_info_t info, MP3D_PROGRESS_CB progress_cb, void* user_data) { 45 import core.stdc.string : memcpy, memset; 46 import core.stdc.stdlib : malloc, realloc; 47 auto buf_size = buffer.length; 48 auto buf = buffer.ptr; 49 size_t orig_buf_size = buf_size; 50 mp3d_sample_t[MINIMP3_MAX_SAMPLES_PER_FRAME] pcm; 51 mp3dec_frame_info_t frame_info; 52 memset(&info, 0, info.sizeof); 53 memset(&frame_info, 0, frame_info.sizeof); 54 /* skip id3v2 */ 55 size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size); 56 if (id3v2size > buf_size) 57 return; 58 buf += id3v2size; 59 buf_size -= id3v2size; 60 /* try to make allocation size assumption by first frame */ 61 mp3dec_init(dec); 62 int samples; 63 do { 64 samples = mp3dec_decode_frame(dec, buf, cast(int) buf_size, pcm.ptr, &frame_info); 65 buf += frame_info.frame_bytes; 66 buf_size -= frame_info.frame_bytes; 67 if (samples) 68 break; 69 } 70 while (frame_info.frame_bytes); 71 if (!samples) 72 return; 73 samples *= frame_info.channels; 74 size_t allocated = (buf_size / frame_info.frame_bytes) * samples * mp3d_sample_t.sizeof + MINIMP3_MAX_SAMPLES_PER_FRAME * mp3d_sample_t.sizeof; 75 info.buffer = cast(mp3d_sample_t*) malloc(allocated); 76 if (!info.buffer) 77 return; 78 info.samples = samples; 79 memcpy(info.buffer, pcm.ptr, info.samples * mp3d_sample_t.sizeof); 80 /* save info */ 81 info.channels = frame_info.channels; 82 info.hz = frame_info.hz; 83 info.layer = frame_info.layer; 84 size_t avg_bitrate_kbps = frame_info.bitrate_kbps; 85 size_t frames = 1; 86 /* decode rest frames */ 87 int frame_bytes; 88 do { 89 if ((allocated - info.samples * mp3d_sample_t.sizeof) < MINIMP3_MAX_SAMPLES_PER_FRAME * mp3d_sample_t.sizeof) { 90 allocated *= 2; 91 info.buffer = cast(mp3d_sample_t*) realloc(info.buffer, allocated); 92 } 93 samples = mp3dec_decode_frame(dec, buf, cast(int) buf_size, info.buffer + info.samples, &frame_info); 94 frame_bytes = frame_info.frame_bytes; 95 buf += frame_bytes; 96 buf_size -= frame_bytes; 97 if (samples) { 98 if (info.hz != frame_info.hz || info.layer != frame_info.layer) 99 break; 100 if (info.channels && info.channels != frame_info.channels) { 101 version (MINIMP3_ALLOW_MONO_STEREO_TRANSITION) { 102 info.channels = 0; /* mark file with mono-stereo transition */ 103 } 104 else { 105 break; 106 } 107 } 108 info.samples += samples * frame_info.channels; 109 avg_bitrate_kbps += frame_info.bitrate_kbps; 110 frames++; 111 if (progress_cb) 112 progress_cb(user_data, orig_buf_size, orig_buf_size - buf_size, frame_info); 113 } 114 } 115 while (frame_bytes); 116 /* reallocate to normal buffer size */ 117 if (allocated != info.samples * mp3d_sample_t.sizeof) 118 info.buffer = cast(mp3d_sample_t*) realloc(info.buffer, info.samples * mp3d_sample_t.sizeof); 119 info.avg_bitrate_kbps = cast(int)(avg_bitrate_kbps / frames); 120 } 121 122 private void mp3dec_iterate_buf(const(ubyte)[] buffer, MP3D_ITERATE_CB callback, void* user_data) { 123 import core.stdc.string : memset; 124 auto buf_size = buffer.length; 125 auto buf = buffer.ptr; 126 if (!callback) 127 return; 128 mp3dec_frame_info_t frame_info; 129 memset(&frame_info, 0, frame_info.sizeof); 130 /* skip id3v2 */ 131 size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size); 132 if (id3v2size > buf_size) 133 return; 134 const(ubyte)* orig_buf = buf; 135 buf += id3v2size; 136 buf_size -= id3v2size; 137 do { 138 int free_format_bytes = 0, frame_size = 0; 139 int i = mp3d_find_frame(buf, cast(int) buf_size, &free_format_bytes, &frame_size); 140 buf += i; 141 buf_size -= i; 142 if (i && !frame_size) 143 continue; 144 if (!frame_size) 145 break; 146 const(ubyte)* hdr = buf; 147 frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; 148 frame_info.hz = hdr_sample_rate_hz(hdr); 149 frame_info.layer = 4 - HDR_GET_LAYER(hdr); 150 frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); 151 frame_info.frame_bytes = frame_size; 152 153 if (callback(user_data, hdr, frame_size, hdr - orig_buf, frame_info)) 154 break; 155 buf += frame_size; 156 buf_size -= frame_size; 157 } 158 while (1); 159 }