--- unmo3-0.6.orig/16to8.c +++ unmo3-0.6/16to8.c @@ -1,20 +1,20 @@ - -/* convert RAW 16bits samples into 8 bits */ - -#include - -int main(int argc, char *argv[]) -{ - unsigned char c; - - fgetc(stdin); - c = fgetc(stdin); - while(!feof(stdin)) { - putchar(c); - - fgetc(stdin); - c = fgetc(stdin); - } - - -} + +/* convert RAW 16bits samples into 8 bits */ + +#include + +int main(int argc, char *argv[]) +{ + unsigned char c; + + fgetc(stdin); + c = fgetc(stdin); + while(!feof(stdin)) { + putchar(c); + + fgetc(stdin); + c = fgetc(stdin); + } + + +} --- unmo3-0.6.orig/Makefile +++ unmo3-0.6/Makefile @@ -48,4 +48,4 @@ dep: $(MAKEDEPEND) -f.depend -- ${CFLAGS} -- ${SRCS} -include .depend +#include .depend --- unmo3-0.6.orig/README.txt +++ unmo3-0.6/README.txt @@ -1,101 +1,101 @@ - -unmo3 (opensource) v0.6 ------------------------ -19 Jul 2009 - - -Copyright Laurent Clévy (lclevy@free.fr) -This code is under GPLv2 license. - ------------------------------------------- - -* changelog - -- 19jul2009, code source updated to v0.6 for MO3 v2.4 encoder - . version = 5. Also able to handle version = 3 (encoder 2.2) - . compressed header at offset 12 instead of 8 - . 2 times bytes 0 after samples names instead of 1. - . specification updated to v0.91 -- 26feb2006, initial version : v0.5 - ------------------------------------------- - -* Introduction - -The piece of code has been written as a compagnion (validation code) of the document "the unofficial MO3 specification". -See http://lclevy.free.fr/mo3 -It is targeted to developpers or technical people, not for end users. It can be used by IT/XM/S3M modules -specialists (tracker editor developper or modules players) to write a MO3 import loader, or more generally -to handle MO3 modules in any way. - -The MO3 format has been created by Ian Luck (http://www.un4seen.com). -If you are looking for a good encoder and decoder (but without the source code) and a good module player, -Ian's web site is the right place to go. - -* Features of unmo3 (opensource version) - -Here they are: -- uncompress the MO3 header and samples with lossless compression -- able to save uncompressed header and samples -- able to extract mp3 and ogg compressed samples -- can display a channel of a given pattern into 2 forms - - as encoded inside MO3 file - - as it is usually appears in a tracker editor - -This code has been written under Cygwin/IA32, should work under Linux/IA32, and is supposed portable under other architectures. -It will be tested under Solaris/Ultrasparc. - -If you want to run the auto tests, you have to download "unmo3_test.zip". - -* Syntax - -unmo3 [options] filename.mo3 - -available options are: - --a parselevel (from 1-4) -Display content of the MO3 file with more (-a 4) or less (-a 1) details - --d debuglevel (2) -Display some inner-working information - --v pattern_number voice_number -Display a channel of a given pattern as encoded inside MO3 module (technical output) - --o -Must be combined with -v. Display a given channel, but as seen in any tracker editor (user friendly output). - --h header_output_filename -Write the uncompressed MO3 header into a file, for further study for example. - --s sample_number | all -Save one sample, or all samples of the MO3 module. - -* Usage - -- to build the executable - -#make dep -#make - -- demo -you can try -#make demo -to see a 'demo' - -- tests -#make test -for the auto tests : mainly to check the decompression routines ("unmo3_test.zip" archive is required). - - -* Not provided with this code - -There is remaining work to do to interpret how all IT/XM and S3M effects and samples/instruments parameters -are stored AND interpreted by a player. But 80-90% of this work has been done in the documentation. - -And maybe in a future release I'll write a .mod module writer. - - -Have fun. - -Laurent + +unmo3 (opensource) v0.6 +----------------------- +19 Jul 2009 + + +Copyright Laurent Clévy (lclevy@free.fr) +This code is under GPLv2 license. + +------------------------------------------ + +* changelog + +- 19jul2009, code source updated to v0.6 for MO3 v2.4 encoder + . version = 5. Also able to handle version = 3 (encoder 2.2) + . compressed header at offset 12 instead of 8 + . 2 times bytes 0 after samples names instead of 1. + . specification updated to v0.91 +- 26feb2006, initial version : v0.5 + +------------------------------------------ + +* Introduction + +The piece of code has been written as a compagnion (validation code) of the document "the unofficial MO3 specification". +See http://lclevy.free.fr/mo3 +It is targeted to developpers or technical people, not for end users. It can be used by IT/XM/S3M modules +specialists (tracker editor developper or modules players) to write a MO3 import loader, or more generally +to handle MO3 modules in any way. + +The MO3 format has been created by Ian Luck (http://www.un4seen.com). +If you are looking for a good encoder and decoder (but without the source code) and a good module player, +Ian's web site is the right place to go. + +* Features of unmo3 (opensource version) + +Here they are: +- uncompress the MO3 header and samples with lossless compression +- able to save uncompressed header and samples +- able to extract mp3 and ogg compressed samples +- can display a channel of a given pattern into 2 forms + - as encoded inside MO3 file + - as it is usually appears in a tracker editor + +This code has been written under Cygwin/IA32, should work under Linux/IA32, and is supposed portable under other architectures. +It will be tested under Solaris/Ultrasparc. + +If you want to run the auto tests, you have to download "unmo3_test.zip". + +* Syntax + +unmo3 [options] filename.mo3 + +available options are: + +-a parselevel (from 1-4) +Display content of the MO3 file with more (-a 4) or less (-a 1) details + +-d debuglevel (2) +Display some inner-working information + +-v pattern_number voice_number +Display a channel of a given pattern as encoded inside MO3 module (technical output) + +-o +Must be combined with -v. Display a given channel, but as seen in any tracker editor (user friendly output). + +-h header_output_filename +Write the uncompressed MO3 header into a file, for further study for example. + +-s sample_number | all +Save one sample, or all samples of the MO3 module. + +* Usage + +- to build the executable + +#make dep +#make + +- demo +you can try +#make demo +to see a 'demo' + +- tests +#make test +for the auto tests : mainly to check the decompression routines ("unmo3_test.zip" archive is required). + + +* Not provided with this code + +There is remaining work to do to interpret how all IT/XM and S3M effects and samples/instruments parameters +are stored AND interpreted by a player. But 80-90% of this work has been done in the documentation. + +And maybe in a future release I'll write a .mod module writer. + + +Have fun. + +Laurent --- unmo3-0.6.orig/debian/changelog +++ unmo3-0.6/debian/changelog @@ -0,0 +1,23 @@ +unmo3 (0.6-2) unstable; urgency=medium + + * New maintainer. (Closes: #661460) + * Bump debhelper version to 11. + * Bump standards version to 4.1.3. + + -- Gürkan Myczko Thu, 15 Feb 2018 21:11:34 +0100 + +unmo3 (0.6-1) unstable; urgency=low + + * New upstream version. + * Update my email address. + * Bump debhelper version. + * Bump standards version. + * debian/copyright: updated. + + -- Gürkan Sengün Tue, 21 Jul 2009 09:02:28 +0200 + +unmo3 (0.5-1) unstable; urgency=low + + * Initial release. (Closes: #451128) + + -- Gürkan Sengün Tue, 13 Nov 2007 19:32:23 +0100 --- unmo3-0.6.orig/debian/compat +++ unmo3-0.6/debian/compat @@ -0,0 +1 @@ +11 --- unmo3-0.6.orig/debian/control +++ unmo3-0.6/debian/control @@ -0,0 +1,17 @@ +Source: unmo3 +Section: utils +Priority: optional +Maintainer: Gürkan Myczko +Build-Depends: debhelper (>= 11) +Standards-Version: 4.1.3 +Homepage: http://lclevy.free.fr/mo3 + +Package: unmo3 +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Recommends: opencubicplayer, xmp, schism, milkytracker +Description: Uncompress and extract samples from MO3 modules + The MO3 format means "MOdule with MP3", because the main initial idea was to + reduce the size of a module (in .mod, IT, XM) by compressing the samples + using MPEG audio layer 3. The samples can be compressed using OGG, MP3, and + two kind of specific lossless algorithms. --- unmo3-0.6.orig/debian/copyright +++ unmo3-0.6/debian/copyright @@ -0,0 +1,41 @@ +This package was debianized by: + + Gürkan Sengün on Tue, 13 Nov 2007 19:32:23 +0100. + +It was downloaded from: + + http://lclevy.free.fr/mo3 + +Upstream Author: + + Laurent Clévy + +Copyright: + + Copyright (C) 2006-2009 Laurent Clévy + +License: + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian systems, the complete text of the GNU General +Public License version 2 can be found in `/usr/share/common-licenses/GPL-2'. + +The Debian packaging is: + + Copyright (C) 2009, G..rkan Seng..n + +and is licensed under the GPL version 3, +see `/usr/share/common-licenses/GPL-3'. --- unmo3-0.6.orig/debian/dirs +++ unmo3-0.6/debian/dirs @@ -0,0 +1 @@ +usr/bin --- unmo3-0.6.orig/debian/docs +++ unmo3-0.6/debian/docs @@ -0,0 +1 @@ +README.txt --- unmo3-0.6.orig/debian/examples +++ unmo3-0.6/debian/examples @@ -0,0 +1 @@ +*.mo3 --- unmo3-0.6.orig/debian/install +++ unmo3-0.6/debian/install @@ -0,0 +1 @@ +unmo3 usr/bin --- unmo3-0.6.orig/debian/manpages +++ unmo3-0.6/debian/manpages @@ -0,0 +1 @@ +debian/unmo3.1 --- unmo3-0.6.orig/debian/rules +++ unmo3-0.6/debian/rules @@ -0,0 +1,8 @@ +#!/usr/bin/make -f +#export DH_VERBOSE = 1 + +%: + dh $@ + +override_dh_auto_test: + @echo moo --- unmo3-0.6.orig/debian/unmo3.1 +++ unmo3-0.6/debian/unmo3.1 @@ -0,0 +1,53 @@ +.TH UNMO3 1 "November 13, 2007" +.SH NAME +unmo3 \- uncompress and extract samples from MO3 modules +.SH SYNOPSIS +.B unmo3 +[\-\fBd +.IR debuglevel ] +[\-\fBa +.IR parselevel ] +[\-\fBh +.IR outheaderfile ] + +[\-\fBs +.IR ] +[\-\fBv +.IR patternchannel ] +[\-\fBo ] +.IR filename.mo3 +.SH DESCRIPTION +This manual page documents briefly the +.B unmo3 +command. +.PP +\fBunmo3\fP is a program that uncompresses, and extracts samples from mo3 files. +.SH OPTIONS +A summary of options is included below. +.TP +.B \-a +Set parselevel. +.TP +.B \-d +Set debuglevel. +.TP +.B \-h +Output filename for header. +.TP +.B \-s +Select sample(s). +.TP +.B \-v +Display voice. +.TP +.B \-o +Output track. +.SH SEE ALSO +.BR opencubicplayer (1), +.BR schism (1). +.br +.SH AUTHOR +unmo3 was written by Laurent Clevy. +.PP +This manual page was written by Gürkan Myczko , +for the Debian project (but may be used by others). --- unmo3-0.6.orig/endian_macros.h +++ unmo3-0.6/endian_macros.h @@ -1,13 +1,13 @@ -#ifndef ENDIAN_MACROS_H -#define ENDIAN_MACROS_H 1 - -/* little endian macro */ -#define ifget8(f) ((unsigned long)fgetc(f)) -#define ifget16(f) ( ifget8(f) | (ifget8(f)<<8UL) ) -#define ifget32(f) ( ifget16(f) | (ifget16(f)<<16UL) ) - -#define iget8(p) ((unsigned char)*(p)) -#define iget16(p) ( iget8(p) | (iget8(p+1)<<8UL) ) -#define iget32(p) ( iget16(p) | (iget16(p+2)<<16UL) ) - -#endif // ENDIAN_MACROS_H +#ifndef ENDIAN_MACROS_H +#define ENDIAN_MACROS_H 1 + +/* little endian macro */ +#define ifget8(f) ((unsigned long)fgetc(f)) +#define ifget16(f) ( ifget8(f) | (ifget8(f)<<8UL) ) +#define ifget32(f) ( ifget16(f) | (ifget16(f)<<16UL) ) + +#define iget8(p) ((unsigned char)*(p)) +#define iget16(p) ( iget8(p) | (iget8(p+1)<<8UL) ) +#define iget32(p) ( iget16(p) | (iget16(p+2)<<16UL) ) + +#endif // ENDIAN_MACROS_H --- unmo3-0.6.orig/mo3_mp3.c +++ unmo3-0.6/mo3_mp3.c @@ -1,91 +1,91 @@ -/* - * mo3_mp3.c - */ - -/* the MP3 header is explained here : - * http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm - * - * see also ISO/CEI 11172-3 and ISO/CEI 13818-3 - * http://en.wikipedia.org/wiki/MP3 - */ - -#include"endian_macros.h" - -#include - -extern int debug; - -int br1[3][16]={ - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} -} ; -int br2[2][16]={ - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0}, - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0} -}; - -int freq[3][4] = { - {44100, 48000, 32000, 0}, // L1 - {22050, 24000, 16000, 0}, // L2 - {11025, 12000, 8000, 0} // L2.5 -}; - -long getMp3Length(unsigned char *src) -{ - unsigned short s; - unsigned char *p=src; - int version, layer, bitrateI, frequency; - int bitrate; - - s = iget16(p); - - /* 0000 0000 000vv000 */ - version = (s & (3<<3))>>3; - if (debug>1) - printf("MPEG version bits = %x\n", version); - switch(version) { - case 0: version=3; break; // 2.5 - case 2: break; - case 3: version=1; break; - default: - printf("version=1\n"); - } - - /* 0000 0000 00000ll0 */ - layer = (s & (3<<1))>>1; - if (debug>1) - printf("Layer bits = %x\n", layer); - switch(layer) { - case 1: layer=3; break; - case 2: break; - case 3: layer=1; break; - default: - printf("layer=0\n"); - } - - p+=2; - /* bbbb0000 */ - bitrateI = (*p & 0xf0)>>4; - if (debug>1) - printf("Bitrate index = %x\n", bitrateI); - - if (version==1) { // v1 - bitrate = br1[layer][bitrateI]; - if (debug) - printf("Bitrate = %d kbps\n", bitrate); - } else if (version==2 || version==3) { // resp. v2 or v2.5 - bitrate = br2[layer][bitrateI]; - if (debug>0) - printf("Bitrate = %d kbps\n", bitrate); - } - - /* 0000ff00 */ - frequency = (*p & (3<<2))>>2; - if (debug>1) - printf("Frequency bits = %x\n", frequency); - if (debug>0) - printf("Frequency = %d hz\n", freq[layer][frequency]); - - return 0; -} +/* + * mo3_mp3.c + */ + +/* the MP3 header is explained here : + * http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm + * + * see also ISO/CEI 11172-3 and ISO/CEI 13818-3 + * http://en.wikipedia.org/wiki/MP3 + */ + +#include"endian_macros.h" + +#include + +extern int debug; + +int br1[3][16]={ + { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, + { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} +} ; +int br2[2][16]={ + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0}, + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0} +}; + +int freq[3][4] = { + {44100, 48000, 32000, 0}, // L1 + {22050, 24000, 16000, 0}, // L2 + {11025, 12000, 8000, 0} // L2.5 +}; + +long getMp3Length(unsigned char *src) +{ + unsigned short s; + unsigned char *p=src; + int version, layer, bitrateI, frequency; + int bitrate; + + s = iget16(p); + + /* 0000 0000 000vv000 */ + version = (s & (3<<3))>>3; + if (debug>1) + printf("MPEG version bits = %x\n", version); + switch(version) { + case 0: version=3; break; // 2.5 + case 2: break; + case 3: version=1; break; + default: + printf("version=1\n"); + } + + /* 0000 0000 00000ll0 */ + layer = (s & (3<<1))>>1; + if (debug>1) + printf("Layer bits = %x\n", layer); + switch(layer) { + case 1: layer=3; break; + case 2: break; + case 3: layer=1; break; + default: + printf("layer=0\n"); + } + + p+=2; + /* bbbb0000 */ + bitrateI = (*p & 0xf0)>>4; + if (debug>1) + printf("Bitrate index = %x\n", bitrateI); + + if (version==1) { // v1 + bitrate = br1[layer][bitrateI]; + if (debug) + printf("Bitrate = %d kbps\n", bitrate); + } else if (version==2 || version==3) { // resp. v2 or v2.5 + bitrate = br2[layer][bitrateI]; + if (debug>0) + printf("Bitrate = %d kbps\n", bitrate); + } + + /* 0000ff00 */ + frequency = (*p & (3<<2))>>2; + if (debug>1) + printf("Frequency bits = %x\n", frequency); + if (debug>0) + printf("Frequency = %d hz\n", freq[layer][frequency]); + + return 0; +} --- unmo3-0.6.orig/mo3_mp3.h +++ unmo3-0.6/mo3_mp3.h @@ -1,7 +1,7 @@ -#ifndef MO3_MP3_H -#define MO3_MP3_H 1 - -long getMp3Length(unsigned char *src); - - -#endif // MO3_MP3_H +#ifndef MO3_MP3_H +#define MO3_MP3_H 1 + +long getMp3Length(unsigned char *src); + + +#endif // MO3_MP3_H --- unmo3-0.6.orig/mo3_parse.c +++ unmo3-0.6/mo3_parse.c @@ -1,431 +1,431 @@ -/* - * parses MO3 files - */ - -#include -#include -#include -#include - -#include"endian_macros.h" - -#include"mo3_unpack.h" -#include"mo3_parse.h" - -#define NB_NOTES 12 - -char *notes[NB_NOTES]={ "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" }; - -char *compName[] = { "LosslessDelta8", "LosslessDeltaPred8", "LosslessDelta16","LosslessDeltaPred16", - "NotCompressed", "mp3", "ogg", "removed" }; - -char *typeName[] = { "MOD", "XM", "MTM", "IT", "S3M" }; - -char *resoName[] = { "8bits", "16bits" }; - -extern int debug; - - -unsigned char * parseSamples(unsigned char *p, int parseLevel, struct mo3Data *mo3Hdr ) -{ - int j, i; - int sampleLen = 0x29; - - mo3Hdr->samples=(struct mo3Sample*)malloc(mo3Hdr->sampleNb*sizeof(struct mo3Sample)); - if (!mo3Hdr->samples) { - perror("malloc:"); - return (unsigned char *)-1; - } - - if (parseLevel>1) - printf("Samples table = \n"); - - for(i=0; isampleNb; i++) { -// printf("offset=0x%x\n", p-src); - if (parseLevel>1) - printf(" Sample#%d name = %s\n", i+1, p); - while(*p!=0) - p++; - - if (mo3Hdr->version == 5) - p+=2; - else - p++; - - if (debug>2) { - for(j=0; jsamples[i].len = iget32(p+8); - - if (parseLevel>2) { - printf(" ftune = %d, ", *p-128); - printf(" trpose = %0xd, ", *(p+4)); - printf(" vol = %d, ", *(p+5)); - printf(" size = %ld, ", mo3Hdr->samples[i].len); - } - - mo3Hdr->samples[i].lenComp = iget32(p+35); - mo3Hdr->samples[i].flags = iget16(p+20); - - if (parseLevel>2) { - printf(" start = %d, ", iget32(p+12)); - printf(" end = %d, ", iget32(p+16)); - printf(" comp. size = %ld, ", mo3Hdr->samples[i].lenComp); - printf(" flags = %04x " , mo3Hdr->samples[i].flags ); - } - - if (mo3Hdr->samples[i].flags&0x0001) { - mo3Hdr->samples[i].reso = MO3RESO_16BITS; - mo3Hdr->samples[i].len = mo3Hdr->samples[i].len*2; - } - else { - mo3Hdr->samples[i].reso = MO3RESO_8BITS; - } - mo3Hdr->samples[i].method = 0; - - if ( (mo3Hdr->samples[i].flags&0x3000) == 0x2000 ) { - if (mo3Hdr->samples[i].reso == MO3RESO_16BITS) { - mo3Hdr->samples[i].method = unpackSamp16Delta; - mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS16D; - } - else { - mo3Hdr->samples[i].method = unpackSamp8Delta; - mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS8D; - } - } // & 0x2000 - else { - if (mo3Hdr->samples[i].flags&0x4000) { - if (mo3Hdr->samples[i].reso == MO3RESO_16BITS) { - mo3Hdr->samples[i].method = unpackSamp16DeltaPrediction; - mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS16DP; - } - else { - mo3Hdr->samples[i].method = unpackSamp8DeltaPrediction; - mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS8DP; - } - } // & 0x4000 - else { - if (mo3Hdr->samples[i].flags&0x1000) { - if (mo3Hdr->samples[i].flags&0x2000) - mo3Hdr->samples[i].compression = MO3COMPR_OGG; - else - mo3Hdr->samples[i].compression = MO3COMPR_MP3; - } // lossy compression - else { // not compressed or removed - if (parseLevel>2) { - if (mo3Hdr->samples[i].len>0) { - mo3Hdr->samples[i].compression = MO3COMPR_NONE; - } - else - mo3Hdr->samples[i].compression = MO3COMPR_REMOVED; - } - } - } - } - if (parseLevel>2) { - printf("(%s)", compName[mo3Hdr->samples[i].compression-1]); - if (mo3Hdr->samples[i].method==0) - printf(" %s",resoName[mo3Hdr->samples[i].reso-1]); - putchar('\n'); - } - p+=sampleLen; - } // for - - return p; -} - -int parseVoice(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int parseLevel) -{ - unsigned char *p = src+offset; - unsigned char byte; - int c,d, i; - - p+=4; - byte = *p++; - while(byte!=0) { // each voice is null terminated - c = byte&0x0f; - d = (byte&0xf0)>>4; - if ( c==0 ) { - if (parseLevel>3) - printf("0*%d ", d); - } - else { - if (parseLevel>3) { - if (d>1) - printf("[%d*%d, ",d,c); - else - printf("[%d, ",c); - } - for(i=0; i3) - printf("%x %x ", *p, *(p+1)); - p+=2; - } - if (parseLevel>3) - printf("\b] "); - } - byte = *p++; - } - if (parseLevel>3) - putchar('\n'); - - return 0; -} - -int parseTrack(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int write) -{ - unsigned char *p = src+offset; - unsigned char byte; - int c,d, i; - char note[3+1]; - char empty[]="... .. ..."; - char instr[2+1]; - char eff1[3+1]; - char eff2[3+1]; - int oct, notev; - int row=0; - - if (mo3Hdr->type!=MO3TYPE_MOD) { - printf("Not supported\n"); - return -1; - } - - p+=4; - byte = *p++; - while(byte!=0) { // each voice is null terminated - c = byte&0x0f; - d = (byte&0xf0)>>4; - if ( c==0 ) { - if (!write) - for (i=0; ipatternTable; - if (pattern >= mo3Hdr->patternNb) { - fprintf(stderr, "error: pattern number requested is > number of pattern in module\n"); - return -1; - } - if (channel > mo3Hdr->channelNb) { - fprintf(stderr, "error: channel number requested is > number of channel in module\n"); - return -1; - } - p = p + ((mo3Hdr->channelNb*pattern) + channel-1)*2; - return iget16(p); -} - -unsigned char * parseInstr(unsigned char *p, int parseLevel, struct mo3Data *mo3Hdr) -{ - int i, j; -// unsigned char *p = header; - - for(i=0; iinstrNb; i++) { - if (parseLevel>1) - printf(" Instr#%d name = %s\n", i+1, p); - while(*p!=0) - p++; - p++; - if (debug>2) { - for(j=0; j<4; j++) - printf("%02x ", *(p+j)); - putchar('\n'); - } - if (parseLevel>1) { - printf(" sample map=\n"); - printf(" volume enveloppe : nb nodes=%d\n",*(p+4+480+1)); -/* for(j=0x24e; j<0x254; j++) - printf("%02x ", *(p+j)); - putchar('\n'); */ - printf(" panning enveloppe: nb nodes=%d\n",*(p+0x24f)); - printf(" pitch enveloppe : nb nodes=%d\n",*(p+0x2b9)); - } - if (debug>2) { - for(j=0x322; j<0x33a; j++) - printf("%02x ", *(p+j)); - putchar('\n'); - - } - p+=0x33a; - } - - return p; -} - -int parseHeader(unsigned char *src, unsigned long size, int parseLevel, struct mo3Data *mo3Hdr) -{ - unsigned char *p = src; - int i, j, k=0; - - long voiceLen; - - if (parseLevel>0) - printf("Songname = %s\n", src); - - /* songname terminated by 00 */ - while(*p!=0) - p++; - p++; - - /* comments terminated by 00 */ - while(*p!=0) - p++; - p++; - -// p2=p; - mo3Hdr->channelNb = *p; - mo3Hdr->songLen = iget16(p+1); - mo3Hdr->patternNb = iget16(p+5); - mo3Hdr->uniqueVoice = iget16(p+7); - mo3Hdr->instrNb = iget16(p+9); - mo3Hdr->sampleNb = iget16(p+11); - mo3Hdr->flags = iget32(p+15); - - if (parseLevel>0) { - printf("Nb channels = %d\n", mo3Hdr->channelNb); - printf("Song length = %d\n", mo3Hdr->songLen); - printf("Song restart = %d\n", iget16(p+3)); - printf("Nb pattern = %d\n", mo3Hdr->patternNb); - printf("Nb unique voice = %d\n", mo3Hdr->uniqueVoice); - printf("Nb instr = %d\n", mo3Hdr->instrNb); - printf("Nb sample = %d\n", mo3Hdr->sampleNb); - printf("Ticks/row = %d\n", *(p+13)); - printf("Initial tempo = %d\n", *(p+14)); - } - if (mo3Hdr->flags & 0x0100) - mo3Hdr->type = MO3TYPE_IT; - else if (mo3Hdr->flags & 0x0002) - mo3Hdr->type = MO3TYPE_S3M; - else if ( mo3Hdr->flags & 0x0080) - mo3Hdr->type = MO3TYPE_MOD; - else if (mo3Hdr->flags & 0x0008) - mo3Hdr->type = MO3TYPE_MTM; - else - mo3Hdr->type = MO3TYPE_XM; - - if (parseLevel>0) { - printf("Initial format is "); - printf("%s (0x%08lx)\n", typeName[mo3Hdr->type-1], mo3Hdr->flags); - } - - mo3Hdr->voicePtr=(long*)malloc(mo3Hdr->uniqueVoice*sizeof(long)); - if (!mo3Hdr->voicePtr) { - perror("malloc:"); - return -1; - } - - mo3Hdr->patternLen=(short*)malloc(mo3Hdr->patternNb*sizeof(short)); - if (!mo3Hdr->patternLen) { - perror("malloc:"); - return -1; - } - - p+=0x1a6; - if (parseLevel>1) - printf("Song sequence = "); - for(i=0; isongLen; i++) { - if (parseLevel>1) - printf("%d ",*p); - p++; - } - if (parseLevel>1) - putchar('\n'); - - if (parseLevel>2) - printf("Unique voice number for each pattern = "); - mo3Hdr->patternTable = p-src; - for(i=0; i < mo3Hdr->patternNb * mo3Hdr->channelNb; i++) { - if (parseLevel>2) { - if ( ((i)%mo3Hdr->channelNb)==0 || i==0) - printf("p[%d]: ",(i)/mo3Hdr->channelNb); - printf("%d ",iget16(p)); - } - p+=2; - } - if (parseLevel>2) - putchar('\n'); - - if (parseLevel>3) - printf("Pattern size table = "); - for(i=0; i < mo3Hdr->patternNb; i++) { - mo3Hdr->patternLen[i] = iget16(p); - if (parseLevel>3) - printf("%d ",mo3Hdr->patternLen[i]); - p+=2; - } - if (parseLevel>3) - putchar('\n'); - - if (parseLevel>3) - printf("Voice data table = "); - - for(j=0; juniqueVoice; j++) { - voiceLen = iget32(p); - - if (parseLevel>3) - printf("v[%d] l=0x%lx ", j, voiceLen); - - mo3Hdr->voicePtr[k++] = p-src; - - parseVoice(src, p-src, mo3Hdr, parseLevel); - p+=4; - p+=voiceLen; - } - if (parseLevel>3) - putchar('\n'); - - if (parseLevel>1) - printf("Instr table = \n"); - - mo3Hdr->instr = p-src; - p = parseInstr(p, parseLevel, mo3Hdr); - - p = parseSamples(p, parseLevel, mo3Hdr); - - if (parseLevel>1) - printf("end offset=0x%x\n", p-src); - - return 0; -} - +/* + * parses MO3 files + */ + +#include +#include +#include +#include + +#include"endian_macros.h" + +#include"mo3_unpack.h" +#include"mo3_parse.h" + +#define NB_NOTES 12 + +char *notes[NB_NOTES]={ "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" }; + +char *compName[] = { "LosslessDelta8", "LosslessDeltaPred8", "LosslessDelta16","LosslessDeltaPred16", + "NotCompressed", "mp3", "ogg", "removed" }; + +char *typeName[] = { "MOD", "XM", "MTM", "IT", "S3M" }; + +char *resoName[] = { "8bits", "16bits" }; + +extern int debug; + + +unsigned char * parseSamples(unsigned char *p, int parseLevel, struct mo3Data *mo3Hdr ) +{ + int j, i; + int sampleLen = 0x29; + + mo3Hdr->samples=(struct mo3Sample*)malloc(mo3Hdr->sampleNb*sizeof(struct mo3Sample)); + if (!mo3Hdr->samples) { + perror("malloc:"); + return (unsigned char *)-1; + } + + if (parseLevel>1) + printf("Samples table = \n"); + + for(i=0; isampleNb; i++) { +// printf("offset=0x%x\n", p-src); + if (parseLevel>1) + printf(" Sample#%d name = %s\n", i+1, p); + while(*p!=0) + p++; + + if (mo3Hdr->version == 5) + p+=2; + else + p++; + + if (debug>2) { + for(j=0; jsamples[i].len = iget32(p+8); + + if (parseLevel>2) { + printf(" ftune = %d, ", *p-128); + printf(" trpose = %0xd, ", *(p+4)); + printf(" vol = %d, ", *(p+5)); + printf(" size = %ld, ", mo3Hdr->samples[i].len); + } + + mo3Hdr->samples[i].lenComp = iget32(p+35); + mo3Hdr->samples[i].flags = iget16(p+20); + + if (parseLevel>2) { + printf(" start = %d, ", iget32(p+12)); + printf(" end = %d, ", iget32(p+16)); + printf(" comp. size = %ld, ", mo3Hdr->samples[i].lenComp); + printf(" flags = %04x " , mo3Hdr->samples[i].flags ); + } + + if (mo3Hdr->samples[i].flags&0x0001) { + mo3Hdr->samples[i].reso = MO3RESO_16BITS; + mo3Hdr->samples[i].len = mo3Hdr->samples[i].len*2; + } + else { + mo3Hdr->samples[i].reso = MO3RESO_8BITS; + } + mo3Hdr->samples[i].method = 0; + + if ( (mo3Hdr->samples[i].flags&0x3000) == 0x2000 ) { + if (mo3Hdr->samples[i].reso == MO3RESO_16BITS) { + mo3Hdr->samples[i].method = unpackSamp16Delta; + mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS16D; + } + else { + mo3Hdr->samples[i].method = unpackSamp8Delta; + mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS8D; + } + } // & 0x2000 + else { + if (mo3Hdr->samples[i].flags&0x4000) { + if (mo3Hdr->samples[i].reso == MO3RESO_16BITS) { + mo3Hdr->samples[i].method = unpackSamp16DeltaPrediction; + mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS16DP; + } + else { + mo3Hdr->samples[i].method = unpackSamp8DeltaPrediction; + mo3Hdr->samples[i].compression = MO3COMPR_LOSSLESS8DP; + } + } // & 0x4000 + else { + if (mo3Hdr->samples[i].flags&0x1000) { + if (mo3Hdr->samples[i].flags&0x2000) + mo3Hdr->samples[i].compression = MO3COMPR_OGG; + else + mo3Hdr->samples[i].compression = MO3COMPR_MP3; + } // lossy compression + else { // not compressed or removed + if (parseLevel>2) { + if (mo3Hdr->samples[i].len>0) { + mo3Hdr->samples[i].compression = MO3COMPR_NONE; + } + else + mo3Hdr->samples[i].compression = MO3COMPR_REMOVED; + } + } + } + } + if (parseLevel>2) { + printf("(%s)", compName[mo3Hdr->samples[i].compression-1]); + if (mo3Hdr->samples[i].method==0) + printf(" %s",resoName[mo3Hdr->samples[i].reso-1]); + putchar('\n'); + } + p+=sampleLen; + } // for + + return p; +} + +int parseVoice(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int parseLevel) +{ + unsigned char *p = src+offset; + unsigned char byte; + int c,d, i; + + p+=4; + byte = *p++; + while(byte!=0) { // each voice is null terminated + c = byte&0x0f; + d = (byte&0xf0)>>4; + if ( c==0 ) { + if (parseLevel>3) + printf("0*%d ", d); + } + else { + if (parseLevel>3) { + if (d>1) + printf("[%d*%d, ",d,c); + else + printf("[%d, ",c); + } + for(i=0; i3) + printf("%x %x ", *p, *(p+1)); + p+=2; + } + if (parseLevel>3) + printf("\b] "); + } + byte = *p++; + } + if (parseLevel>3) + putchar('\n'); + + return 0; +} + +int parseTrack(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int write) +{ + unsigned char *p = src+offset; + unsigned char byte; + int c,d, i; + char note[3+1]; + char empty[]="... .. ..."; + char instr[2+1]; + char eff1[3+1]; + char eff2[3+1]; + int oct, notev; + int row=0; + + if (mo3Hdr->type!=MO3TYPE_MOD) { + printf("Not supported\n"); + return -1; + } + + p+=4; + byte = *p++; + while(byte!=0) { // each voice is null terminated + c = byte&0x0f; + d = (byte&0xf0)>>4; + if ( c==0 ) { + if (!write) + for (i=0; ipatternTable; + if (pattern >= mo3Hdr->patternNb) { + fprintf(stderr, "error: pattern number requested is > number of pattern in module\n"); + return -1; + } + if (channel > mo3Hdr->channelNb) { + fprintf(stderr, "error: channel number requested is > number of channel in module\n"); + return -1; + } + p = p + ((mo3Hdr->channelNb*pattern) + channel-1)*2; + return iget16(p); +} + +unsigned char * parseInstr(unsigned char *p, int parseLevel, struct mo3Data *mo3Hdr) +{ + int i, j; +// unsigned char *p = header; + + for(i=0; iinstrNb; i++) { + if (parseLevel>1) + printf(" Instr#%d name = %s\n", i+1, p); + while(*p!=0) + p++; + p++; + if (debug>2) { + for(j=0; j<4; j++) + printf("%02x ", *(p+j)); + putchar('\n'); + } + if (parseLevel>1) { + printf(" sample map=\n"); + printf(" volume enveloppe : nb nodes=%d\n",*(p+4+480+1)); +/* for(j=0x24e; j<0x254; j++) + printf("%02x ", *(p+j)); + putchar('\n'); */ + printf(" panning enveloppe: nb nodes=%d\n",*(p+0x24f)); + printf(" pitch enveloppe : nb nodes=%d\n",*(p+0x2b9)); + } + if (debug>2) { + for(j=0x322; j<0x33a; j++) + printf("%02x ", *(p+j)); + putchar('\n'); + + } + p+=0x33a; + } + + return p; +} + +int parseHeader(unsigned char *src, unsigned long size, int parseLevel, struct mo3Data *mo3Hdr) +{ + unsigned char *p = src; + int i, j, k=0; + + long voiceLen; + + if (parseLevel>0) + printf("Songname = %s\n", src); + + /* songname terminated by 00 */ + while(*p!=0) + p++; + p++; + + /* comments terminated by 00 */ + while(*p!=0) + p++; + p++; + +// p2=p; + mo3Hdr->channelNb = *p; + mo3Hdr->songLen = iget16(p+1); + mo3Hdr->patternNb = iget16(p+5); + mo3Hdr->uniqueVoice = iget16(p+7); + mo3Hdr->instrNb = iget16(p+9); + mo3Hdr->sampleNb = iget16(p+11); + mo3Hdr->flags = iget32(p+15); + + if (parseLevel>0) { + printf("Nb channels = %d\n", mo3Hdr->channelNb); + printf("Song length = %d\n", mo3Hdr->songLen); + printf("Song restart = %d\n", iget16(p+3)); + printf("Nb pattern = %d\n", mo3Hdr->patternNb); + printf("Nb unique voice = %d\n", mo3Hdr->uniqueVoice); + printf("Nb instr = %d\n", mo3Hdr->instrNb); + printf("Nb sample = %d\n", mo3Hdr->sampleNb); + printf("Ticks/row = %d\n", *(p+13)); + printf("Initial tempo = %d\n", *(p+14)); + } + if (mo3Hdr->flags & 0x0100) + mo3Hdr->type = MO3TYPE_IT; + else if (mo3Hdr->flags & 0x0002) + mo3Hdr->type = MO3TYPE_S3M; + else if ( mo3Hdr->flags & 0x0080) + mo3Hdr->type = MO3TYPE_MOD; + else if (mo3Hdr->flags & 0x0008) + mo3Hdr->type = MO3TYPE_MTM; + else + mo3Hdr->type = MO3TYPE_XM; + + if (parseLevel>0) { + printf("Initial format is "); + printf("%s (0x%08lx)\n", typeName[mo3Hdr->type-1], mo3Hdr->flags); + } + + mo3Hdr->voicePtr=(long*)malloc(mo3Hdr->uniqueVoice*sizeof(long)); + if (!mo3Hdr->voicePtr) { + perror("malloc:"); + return -1; + } + + mo3Hdr->patternLen=(short*)malloc(mo3Hdr->patternNb*sizeof(short)); + if (!mo3Hdr->patternLen) { + perror("malloc:"); + return -1; + } + + p+=0x1a6; + if (parseLevel>1) + printf("Song sequence = "); + for(i=0; isongLen; i++) { + if (parseLevel>1) + printf("%d ",*p); + p++; + } + if (parseLevel>1) + putchar('\n'); + + if (parseLevel>2) + printf("Unique voice number for each pattern = "); + mo3Hdr->patternTable = p-src; + for(i=0; i < mo3Hdr->patternNb * mo3Hdr->channelNb; i++) { + if (parseLevel>2) { + if ( ((i)%mo3Hdr->channelNb)==0 || i==0) + printf("p[%d]: ",(i)/mo3Hdr->channelNb); + printf("%d ",iget16(p)); + } + p+=2; + } + if (parseLevel>2) + putchar('\n'); + + if (parseLevel>3) + printf("Pattern size table = "); + for(i=0; i < mo3Hdr->patternNb; i++) { + mo3Hdr->patternLen[i] = iget16(p); + if (parseLevel>3) + printf("%d ",mo3Hdr->patternLen[i]); + p+=2; + } + if (parseLevel>3) + putchar('\n'); + + if (parseLevel>3) + printf("Voice data table = "); + + for(j=0; juniqueVoice; j++) { + voiceLen = iget32(p); + + if (parseLevel>3) + printf("v[%d] l=0x%lx ", j, voiceLen); + + mo3Hdr->voicePtr[k++] = p-src; + + parseVoice(src, p-src, mo3Hdr, parseLevel); + p+=4; + p+=voiceLen; + } + if (parseLevel>3) + putchar('\n'); + + if (parseLevel>1) + printf("Instr table = \n"); + + mo3Hdr->instr = p-src; + p = parseInstr(p, parseLevel, mo3Hdr); + + p = parseSamples(p, parseLevel, mo3Hdr); + + if (parseLevel>1) + printf("end offset=0x%x\n", p-src); + + return 0; +} + --- unmo3-0.6.orig/mo3_parse.h +++ unmo3-0.6/mo3_parse.h @@ -1,58 +1,58 @@ -#ifndef MO3_PARSE_H -#define MO3_PARSE_H 1 - -typedef unsigned char *(*samplePackMethod)(unsigned char *, unsigned char *, long); - -#define MO3TYPE_MOD 1 -#define MO3TYPE_XM 2 -#define MO3TYPE_MTM 3 -#define MO3TYPE_IT 4 -#define MO3TYPE_S3M 5 - -#define MO3COMPR_LOSSLESS8D 1 -#define MO3COMPR_LOSSLESS8DP 2 -#define MO3COMPR_LOSSLESS16D 3 -#define MO3COMPR_LOSSLESS16DP 4 -#define MO3COMPR_NONE 5 -#define MO3COMPR_MP3 6 -#define MO3COMPR_OGG 7 -#define MO3COMPR_REMOVED 8 - -#define MO3RESO_8BITS 1 -#define MO3RESO_16BITS 2 - - -struct mo3Sample { - samplePackMethod method; - long len; - long lenComp; - unsigned short flags; - char compression; - char reso; -}; - -struct mo3Data { - char channelNb; - short songLen; - short uniqueVoice; - short patternNb; - short instrNb; - short sampleNb; - - struct mo3Sample *samples; - - short *patternLen; - long *voicePtr; - long patternTable; - long instr; - unsigned long flags; - int type; - int version; -}; - -int parseHeader(unsigned char *src, unsigned long size, int parseLevel, struct mo3Data *mo3Hdr); -int parseVoice(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int parseLevel); -short findVoiceNumber(short pattern, char channel, unsigned char *mo3, struct mo3Data *mo3Hdr); -int parseTrack(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int write); - -#endif // MO3_PARSE_H +#ifndef MO3_PARSE_H +#define MO3_PARSE_H 1 + +typedef unsigned char *(*samplePackMethod)(unsigned char *, unsigned char *, long); + +#define MO3TYPE_MOD 1 +#define MO3TYPE_XM 2 +#define MO3TYPE_MTM 3 +#define MO3TYPE_IT 4 +#define MO3TYPE_S3M 5 + +#define MO3COMPR_LOSSLESS8D 1 +#define MO3COMPR_LOSSLESS8DP 2 +#define MO3COMPR_LOSSLESS16D 3 +#define MO3COMPR_LOSSLESS16DP 4 +#define MO3COMPR_NONE 5 +#define MO3COMPR_MP3 6 +#define MO3COMPR_OGG 7 +#define MO3COMPR_REMOVED 8 + +#define MO3RESO_8BITS 1 +#define MO3RESO_16BITS 2 + + +struct mo3Sample { + samplePackMethod method; + long len; + long lenComp; + unsigned short flags; + char compression; + char reso; +}; + +struct mo3Data { + char channelNb; + short songLen; + short uniqueVoice; + short patternNb; + short instrNb; + short sampleNb; + + struct mo3Sample *samples; + + short *patternLen; + long *voicePtr; + long patternTable; + long instr; + unsigned long flags; + int type; + int version; +}; + +int parseHeader(unsigned char *src, unsigned long size, int parseLevel, struct mo3Data *mo3Hdr); +int parseVoice(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int parseLevel); +short findVoiceNumber(short pattern, char channel, unsigned char *mo3, struct mo3Data *mo3Hdr); +int parseTrack(unsigned char *src, long offset, struct mo3Data *mo3Hdr, int write); + +#endif // MO3_PARSE_H --- unmo3-0.6.orig/mo3_unpack.c +++ unmo3-0.6/mo3_unpack.c @@ -1,422 +1,422 @@ -/* - * unpack functions for MO3 module - * lclevy@free.fr - * - * the code is under GPL license - */ - -#include -#include -#include -#include - -#include"mo3_unpack.h" - -extern int debug; - -/* unpack macros */ - -/* shift control bits until it is empty: - * a 0 bit means litteral : the next data byte (*s) is copied - * a 1 means compressed data - * then the next 2 bits determines what is the LZ ptr - * ('00' same as previous, else stored in stream (*src)) - */ -#define READ_CTRL_BIT(n) \ - data<<=1; \ - carry = (data >= (1<<(n))); \ - data&=((1<<(n))-1); \ - if (data==0) { \ - data = *src++; \ - data = (data<<1) + 1; \ - carry = (data >= (1<<(n))); \ - data&=((1<<(n))-1); \ - } - -/* length coded within control stream : - * most significant bit is 1 - * than the first bit of each bits pair (noted n1), - * until second bit is 0 (noted n0) - */ -#define DECODE_CTRL_BITS { \ - strLen++; \ - do { \ - READ_CTRL_BIT(8); \ - strLen = (strLen<<1) + carry; \ - READ_CTRL_BIT(8); \ - }while(carry); \ - } - -/* - * this smart algorithm has been designed by Ian Luck - */ -unsigned char * unpack(unsigned char *src, unsigned char *dst, long size) -{ - unsigned short data; - char carry; // x86 carry (used to propagate the most significant bit from one byte to another) - long strLen; // length of previous string - long strOffset; // string offset - unsigned char *string; // pointer to previous string - unsigned char *initDst; - unsigned long ebp, previousPtr; - unsigned long initSize; - - data = 0L; - carry = 0; - strLen = 0; - previousPtr = 0; - - initDst = dst; - initSize = size; - - *dst++ = *src++; // the first byte is not compressed - size--; // bytes left to decompress - - - while (size>0) { - READ_CTRL_BIT(8); - if (!carry) { // a 0 ctrl bit means 'copy', not compressed byte - *dst++ = *src++; - size--; - } - else { // a 1 ctrl bit means compressed bytes are following - ebp = 0; // lenth adjustement - DECODE_CTRL_BITS; // read length, anf if strLen>3 (coded using more than 1 bits pair) also part of the offset value - strLen -=3; - if ((long)(strLen)<0) { // means LZ ptr with same previous relative LZ ptr (saved one) - strOffset = previousPtr; // restore previous Ptr - strLen++; - } - else { // LZ ptr in ctrl stream - strOffset = (strLen<<8) | *src++; // read less significant offset byte from stream - strLen = 0; - strOffset = ~strOffset; - if (strOffset<-1280) - ebp++; - ebp++; // length is always at least 1 - if (strOffset<-32000) - ebp++; - previousPtr = strOffset; // save current Ptr - } - - // read the next 2 bits as part of strLen - READ_CTRL_BIT(8); - strLen = (strLen<<1) + carry; - READ_CTRL_BIT(8); - strLen = (strLen<<1) + carry; - if (strLen==0) { // length do not fit in 2 bits - DECODE_CTRL_BITS; // decode length : 1 is the most significant bit, - strLen+=2; // then first bit of each bits pairs (noted n1), until n0. - } - strLen = strLen + ebp; // length adjustement - size-=strLen; - if (size>=0) { - string = dst + strOffset; // pointer to previous string - for(; strLen>0; strLen--) - *dst++ = *string++; // copies it - } - } // compressed bytes - - } - if ( (dst-initDst)!=initSize ) { - fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", - (dst-initDst), initSize); - } - - return src; - -} - - -/* decode value, encoded as bit pairs (n1), until (n0) */ -#define DECODE_VAL(n) { \ - do { \ - READ_CTRL_BIT((n)); \ - val = (val<<1) + carry; \ - READ_CTRL_BIT((n)); \ - }while(carry); \ - } - -/* decode value , encoded as bit triplets (nn1), until (nn0) */ -#define DECODE_TRIBITS \ - if (dh<5) { \ - do { \ - READ_CTRL_BIT(8); \ - val = (val<<1) + carry; \ - READ_CTRL_BIT(8); \ - val = (val<<1) + carry; \ - READ_CTRL_BIT(8); \ - }while(carry); \ - } \ - else \ - DECODE_VAL(8); - - -/* for 16 bits samples (was unpack2) - * - * very similar to unpackSamp4, but adapted to 16 bits samples - * initial dh=8, - * if dh<5 the left most bits may are encoded using bits triplet (nn1), until 'nn0' - */ -unsigned char * unpackSamp16Delta(unsigned char *src, unsigned char *dst, long size) -{ - - unsigned char dh, cl; - char carry; - unsigned short data; - unsigned short *pdst, *psrc, *initDst; - unsigned short val; - short previous; - unsigned long initSize; - - size/=2; - initDst = pdst = (unsigned short *)dst; - psrc = (unsigned short *)src; - initSize = size; - - dh = 8; - cl = 0; - data = 0; // used in READ_CTRL_BIT - previous = 0; // initial value is 0, sample values are coded using delta. - - while(size>0) { - val = 0; - DECODE_TRIBITS; // decode bits triplets - cl = dh; // length in bits of : delta second part (right most bits of delta) and sign bit - for(; cl>0; cl--) { - READ_CTRL_BIT(8); - val = (val<<1) + carry; - } - cl = 1; - if (val>=4) { - // bsr ecx, val - cl = 15; - while( ((1<1) - cl--; - } - dh = dh + cl; - dh>>=1; // next length in bits of encoded delta second part - carry = val&1; // sign of delta 1=+, 0=not - val>>=1; - if (carry==0) - val=~val; // negative delta - val+=previous; // previous value + delta - *pdst++ = val; - previous = val; - size--; - } - - if ( (pdst-initDst)!=initSize ) { - fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", - (pdst-initDst), initSize); - } - - return src; -} - -/* for 16 bits samples (was unpack3) - * - * same as unpackSamp5, but for 16 bits samples - */ -unsigned char * unpackSamp16DeltaPrediction(unsigned char *src, unsigned char *dst, long size) -{ - /* - * NOT TESTED - */ - - unsigned char dh, cl; - char carry; - short sval; - unsigned short data; - long next, initSize; - unsigned short *pdst, *psrc, *initDst; - unsigned short val; - short delta, previous; - - size/=2; - dh = 8; - cl = 0; - data = 0; // used in READ_CTRL_BIT - previous = next = 0; // initial and next value are 0, sample values are coded using delta against next (predicted). - - initDst = pdst = (unsigned short *)dst; - psrc = (unsigned short *)src; - initSize = size; - - while(size>0) { - val = 0; - DECODE_TRIBITS; // decode bits pair : first part of delta (left most bits) - cl = dh; // length in bits of : delta second part (right most bits of delta) and sign bit - for(; cl>0; cl--) { - READ_CTRL_BIT(8); - val = (val<<1) + carry; - } - cl = 1; - if (val>=4) { - // bsr ecx, val - cl = 15; - while( ((1<1) - cl--; - } - dh = dh + cl; - dh>>=1; // next length in bits of encoded delta second part - carry = val&1; // sign of delta 1=+, 0=not - val>>=1; - if (carry==0) - val=~val; // negative delta - - delta = (short)val; - val=val+next; // predicted value + delta - *pdst++ = val; - sval=(short)val; - next = (sval<<1) + (delta>>1) - previous; // corrected next value - - if (next>32767) // check overflow of next value (signed short) - next = 32767; - else if (next<-32768) - next = -32768; - - previous = sval; - size--; - } - - if ( (pdst-initDst)!=initSize ) { - fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", - (pdst-initDst), initSize); - } - - return src; -} - -/* for 8 bits samples (was unpack4) - * - * 8 bits samples values are encoded as delta. the initial value is 0. - * The 4 left most bits of the delta is first encoded using bit pairs (n1), until n0. - * for example (1)1 (1)1 (1)0 means 7. for low deltas, it is 00. - * then the next bits are encoding the 4 right most bits of the delta, and the delta sign - * if sign bit is 0, it means +delta, else it means not(delta) - * Here is also coded the length of the next 4 right most bits + sign bit. - * This value is initially dh=4, then is divided by 2 each step. The minimal value is 1 for the sign. - * dh may be augmented by cl if val >= 4. - */ -unsigned char * unpackSamp8Delta(unsigned char *src, unsigned char *dst, long size) -{ - unsigned char dh, cl, val, previous; - char carry; - unsigned short data; - long initSize; - unsigned char *initDst; - - initSize = size; - initDst = dst; - dh = 4; - cl = 0; - data = 0; // used in READ_CTRL_BIT - previous = 0; // initial value is 0, sample values are coded using delta. - - while(size>0) { - val = 0; - DECODE_VAL(8); // decode bits pair : first part of delta (4 left most bits) - cl = dh; // length in bits of : delta second part (4 right most bits of delta) and sign bit - for(; cl>0; cl--) { - READ_CTRL_BIT(8); - val = (val<<1) + carry; - } - cl = 1; - if (val>=4) { - // bsr ecx, val - cl = 7; - while( ((1<1) - cl--; - } - dh = dh + cl; - dh>>=1; // next length in bits of encoded delta second part - carry = val&1; // sign of delta 1=+, 0=not - val>>=1; - if (carry==0) - val=~val; // negative delta - val+=previous; // previous value + delta -// *dst++ = 0; // 8bits->16bits conversion - *dst++ = val; - previous = val; - size--; - } - - if ( (dst-initDst)!=initSize ) { - fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", - (dst-initDst), initSize); - } - - return src; -} - -/* for 8 bits samples - * - * the same encoding method as unpackSamp4, but instead of what is coded - * is delta value against predicted value and not only previous value. - * for example if 0 and 3 are 2 following samples values, the next predicted one is 7 - * and the delta encoded is -4 (real value is 3). then the predicted value is corrected - * using recent real value (the prediction is converging to the good value) - * it could be called "differential delta coding" - */ -unsigned char * unpackSamp8DeltaPrediction(unsigned char *src, unsigned char *dst, long size) -{ - unsigned char dh, cl, val; - char carry, delta, previous; - char sval; - unsigned short data; - short next; - - dh = 4; - cl = 0; - data = 0; // used in READ_CTRL_BIT - previous = next = 0; // initial and next value are 0, sample values are coded using delta against next (predicted). - - while(size>0) { - val = 0; - DECODE_VAL(8); // decode bits pair : first part of delta (left most bits) - cl = dh; // length in bits of : delta second part (right most bits of delta) and sign bit - for(; cl>0; cl--) { - READ_CTRL_BIT(8); - val = (val<<1) + carry; - } - cl = 1; - if (val>=4) { - // bsr ecx, val - cl = 7; - while( ((1<1) - cl--; - } - dh = dh + cl; - dh>>=1; // next length in bits of encoded delta second part - carry = val&1; // sign of delta 1=+, 0=not - val>>=1; - if (carry==0) - val=~val; // negative delta - - delta = (char)val; - val=val+next; // predicted value + delta -// *dst++ = 0; // 8bits->16bits conversion - *dst++ = val; - sval=(char)val; - next = (sval<<1) + (delta>>1) - previous; // corrected next value - - if (next>127) // check overflow of next value (signed byte) - next = 127; - else if (next<-128) - next = -128; - - previous = sval; - size--; - } - return src; -} - -unsigned char * notCompressed(unsigned char *src, unsigned char *dst, long size) -{ - - memcpy(dst, src, size); - dst+=size; - - return src+size; -} +/* + * unpack functions for MO3 module + * lclevy@free.fr + * + * the code is under GPL license + */ + +#include +#include +#include +#include + +#include"mo3_unpack.h" + +extern int debug; + +/* unpack macros */ + +/* shift control bits until it is empty: + * a 0 bit means litteral : the next data byte (*s) is copied + * a 1 means compressed data + * then the next 2 bits determines what is the LZ ptr + * ('00' same as previous, else stored in stream (*src)) + */ +#define READ_CTRL_BIT(n) \ + data<<=1; \ + carry = (data >= (1<<(n))); \ + data&=((1<<(n))-1); \ + if (data==0) { \ + data = *src++; \ + data = (data<<1) + 1; \ + carry = (data >= (1<<(n))); \ + data&=((1<<(n))-1); \ + } + +/* length coded within control stream : + * most significant bit is 1 + * than the first bit of each bits pair (noted n1), + * until second bit is 0 (noted n0) + */ +#define DECODE_CTRL_BITS { \ + strLen++; \ + do { \ + READ_CTRL_BIT(8); \ + strLen = (strLen<<1) + carry; \ + READ_CTRL_BIT(8); \ + }while(carry); \ + } + +/* + * this smart algorithm has been designed by Ian Luck + */ +unsigned char * unpack(unsigned char *src, unsigned char *dst, long size) +{ + unsigned short data; + char carry; // x86 carry (used to propagate the most significant bit from one byte to another) + long strLen; // length of previous string + long strOffset; // string offset + unsigned char *string; // pointer to previous string + unsigned char *initDst; + unsigned long ebp, previousPtr; + unsigned long initSize; + + data = 0L; + carry = 0; + strLen = 0; + previousPtr = 0; + + initDst = dst; + initSize = size; + + *dst++ = *src++; // the first byte is not compressed + size--; // bytes left to decompress + + + while (size>0) { + READ_CTRL_BIT(8); + if (!carry) { // a 0 ctrl bit means 'copy', not compressed byte + *dst++ = *src++; + size--; + } + else { // a 1 ctrl bit means compressed bytes are following + ebp = 0; // lenth adjustement + DECODE_CTRL_BITS; // read length, anf if strLen>3 (coded using more than 1 bits pair) also part of the offset value + strLen -=3; + if ((long)(strLen)<0) { // means LZ ptr with same previous relative LZ ptr (saved one) + strOffset = previousPtr; // restore previous Ptr + strLen++; + } + else { // LZ ptr in ctrl stream + strOffset = (strLen<<8) | *src++; // read less significant offset byte from stream + strLen = 0; + strOffset = ~strOffset; + if (strOffset<-1280) + ebp++; + ebp++; // length is always at least 1 + if (strOffset<-32000) + ebp++; + previousPtr = strOffset; // save current Ptr + } + + // read the next 2 bits as part of strLen + READ_CTRL_BIT(8); + strLen = (strLen<<1) + carry; + READ_CTRL_BIT(8); + strLen = (strLen<<1) + carry; + if (strLen==0) { // length do not fit in 2 bits + DECODE_CTRL_BITS; // decode length : 1 is the most significant bit, + strLen+=2; // then first bit of each bits pairs (noted n1), until n0. + } + strLen = strLen + ebp; // length adjustement + size-=strLen; + if (size>=0) { + string = dst + strOffset; // pointer to previous string + for(; strLen>0; strLen--) + *dst++ = *string++; // copies it + } + } // compressed bytes + + } + if ( (dst-initDst)!=initSize ) { + fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", + (dst-initDst), initSize); + } + + return src; + +} + + +/* decode value, encoded as bit pairs (n1), until (n0) */ +#define DECODE_VAL(n) { \ + do { \ + READ_CTRL_BIT((n)); \ + val = (val<<1) + carry; \ + READ_CTRL_BIT((n)); \ + }while(carry); \ + } + +/* decode value , encoded as bit triplets (nn1), until (nn0) */ +#define DECODE_TRIBITS \ + if (dh<5) { \ + do { \ + READ_CTRL_BIT(8); \ + val = (val<<1) + carry; \ + READ_CTRL_BIT(8); \ + val = (val<<1) + carry; \ + READ_CTRL_BIT(8); \ + }while(carry); \ + } \ + else \ + DECODE_VAL(8); + + +/* for 16 bits samples (was unpack2) + * + * very similar to unpackSamp4, but adapted to 16 bits samples + * initial dh=8, + * if dh<5 the left most bits may are encoded using bits triplet (nn1), until 'nn0' + */ +unsigned char * unpackSamp16Delta(unsigned char *src, unsigned char *dst, long size) +{ + + unsigned char dh, cl; + char carry; + unsigned short data; + unsigned short *pdst, *psrc, *initDst; + unsigned short val; + short previous; + unsigned long initSize; + + size/=2; + initDst = pdst = (unsigned short *)dst; + psrc = (unsigned short *)src; + initSize = size; + + dh = 8; + cl = 0; + data = 0; // used in READ_CTRL_BIT + previous = 0; // initial value is 0, sample values are coded using delta. + + while(size>0) { + val = 0; + DECODE_TRIBITS; // decode bits triplets + cl = dh; // length in bits of : delta second part (right most bits of delta) and sign bit + for(; cl>0; cl--) { + READ_CTRL_BIT(8); + val = (val<<1) + carry; + } + cl = 1; + if (val>=4) { + // bsr ecx, val + cl = 15; + while( ((1<1) + cl--; + } + dh = dh + cl; + dh>>=1; // next length in bits of encoded delta second part + carry = val&1; // sign of delta 1=+, 0=not + val>>=1; + if (carry==0) + val=~val; // negative delta + val+=previous; // previous value + delta + *pdst++ = val; + previous = val; + size--; + } + + if ( (pdst-initDst)!=initSize ) { + fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", + (pdst-initDst), initSize); + } + + return src; +} + +/* for 16 bits samples (was unpack3) + * + * same as unpackSamp5, but for 16 bits samples + */ +unsigned char * unpackSamp16DeltaPrediction(unsigned char *src, unsigned char *dst, long size) +{ + /* + * NOT TESTED + */ + + unsigned char dh, cl; + char carry; + short sval; + unsigned short data; + long next, initSize; + unsigned short *pdst, *psrc, *initDst; + unsigned short val; + short delta, previous; + + size/=2; + dh = 8; + cl = 0; + data = 0; // used in READ_CTRL_BIT + previous = next = 0; // initial and next value are 0, sample values are coded using delta against next (predicted). + + initDst = pdst = (unsigned short *)dst; + psrc = (unsigned short *)src; + initSize = size; + + while(size>0) { + val = 0; + DECODE_TRIBITS; // decode bits pair : first part of delta (left most bits) + cl = dh; // length in bits of : delta second part (right most bits of delta) and sign bit + for(; cl>0; cl--) { + READ_CTRL_BIT(8); + val = (val<<1) + carry; + } + cl = 1; + if (val>=4) { + // bsr ecx, val + cl = 15; + while( ((1<1) + cl--; + } + dh = dh + cl; + dh>>=1; // next length in bits of encoded delta second part + carry = val&1; // sign of delta 1=+, 0=not + val>>=1; + if (carry==0) + val=~val; // negative delta + + delta = (short)val; + val=val+next; // predicted value + delta + *pdst++ = val; + sval=(short)val; + next = (sval<<1) + (delta>>1) - previous; // corrected next value + + if (next>32767) // check overflow of next value (signed short) + next = 32767; + else if (next<-32768) + next = -32768; + + previous = sval; + size--; + } + + if ( (pdst-initDst)!=initSize ) { + fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", + (pdst-initDst), initSize); + } + + return src; +} + +/* for 8 bits samples (was unpack4) + * + * 8 bits samples values are encoded as delta. the initial value is 0. + * The 4 left most bits of the delta is first encoded using bit pairs (n1), until n0. + * for example (1)1 (1)1 (1)0 means 7. for low deltas, it is 00. + * then the next bits are encoding the 4 right most bits of the delta, and the delta sign + * if sign bit is 0, it means +delta, else it means not(delta) + * Here is also coded the length of the next 4 right most bits + sign bit. + * This value is initially dh=4, then is divided by 2 each step. The minimal value is 1 for the sign. + * dh may be augmented by cl if val >= 4. + */ +unsigned char * unpackSamp8Delta(unsigned char *src, unsigned char *dst, long size) +{ + unsigned char dh, cl, val, previous; + char carry; + unsigned short data; + long initSize; + unsigned char *initDst; + + initSize = size; + initDst = dst; + dh = 4; + cl = 0; + data = 0; // used in READ_CTRL_BIT + previous = 0; // initial value is 0, sample values are coded using delta. + + while(size>0) { + val = 0; + DECODE_VAL(8); // decode bits pair : first part of delta (4 left most bits) + cl = dh; // length in bits of : delta second part (4 right most bits of delta) and sign bit + for(; cl>0; cl--) { + READ_CTRL_BIT(8); + val = (val<<1) + carry; + } + cl = 1; + if (val>=4) { + // bsr ecx, val + cl = 7; + while( ((1<1) + cl--; + } + dh = dh + cl; + dh>>=1; // next length in bits of encoded delta second part + carry = val&1; // sign of delta 1=+, 0=not + val>>=1; + if (carry==0) + val=~val; // negative delta + val+=previous; // previous value + delta +// *dst++ = 0; // 8bits->16bits conversion + *dst++ = val; + previous = val; + size--; + } + + if ( (dst-initDst)!=initSize ) { + fprintf(stderr,"Error: uncompressed data length is different (%d) than expected (%ld)\n", + (dst-initDst), initSize); + } + + return src; +} + +/* for 8 bits samples + * + * the same encoding method as unpackSamp4, but instead of what is coded + * is delta value against predicted value and not only previous value. + * for example if 0 and 3 are 2 following samples values, the next predicted one is 7 + * and the delta encoded is -4 (real value is 3). then the predicted value is corrected + * using recent real value (the prediction is converging to the good value) + * it could be called "differential delta coding" + */ +unsigned char * unpackSamp8DeltaPrediction(unsigned char *src, unsigned char *dst, long size) +{ + unsigned char dh, cl, val; + char carry, delta, previous; + char sval; + unsigned short data; + short next; + + dh = 4; + cl = 0; + data = 0; // used in READ_CTRL_BIT + previous = next = 0; // initial and next value are 0, sample values are coded using delta against next (predicted). + + while(size>0) { + val = 0; + DECODE_VAL(8); // decode bits pair : first part of delta (left most bits) + cl = dh; // length in bits of : delta second part (right most bits of delta) and sign bit + for(; cl>0; cl--) { + READ_CTRL_BIT(8); + val = (val<<1) + carry; + } + cl = 1; + if (val>=4) { + // bsr ecx, val + cl = 7; + while( ((1<1) + cl--; + } + dh = dh + cl; + dh>>=1; // next length in bits of encoded delta second part + carry = val&1; // sign of delta 1=+, 0=not + val>>=1; + if (carry==0) + val=~val; // negative delta + + delta = (char)val; + val=val+next; // predicted value + delta +// *dst++ = 0; // 8bits->16bits conversion + *dst++ = val; + sval=(char)val; + next = (sval<<1) + (delta>>1) - previous; // corrected next value + + if (next>127) // check overflow of next value (signed byte) + next = 127; + else if (next<-128) + next = -128; + + previous = sval; + size--; + } + return src; +} + +unsigned char * notCompressed(unsigned char *src, unsigned char *dst, long size) +{ + + memcpy(dst, src, size); + dst+=size; + + return src+size; +} --- unmo3-0.6.orig/mo3_unpack.h +++ unmo3-0.6/mo3_unpack.h @@ -1,12 +1,12 @@ -#ifndef MO3_UNPACK_H -#define MO3_UNPACK_H 1 - -unsigned char * unpack(unsigned char *src, unsigned char *dst, long size); -unsigned char * unpackSamp8Delta(unsigned char *src, unsigned char *dst, long size); -unsigned char * unpackSamp8DeltaPrediction(unsigned char *src, unsigned char *dst, long size); -unsigned char * unpackSamp16Delta(unsigned char *src, unsigned char *dst, long size); -unsigned char * unpackSamp16DeltaPrediction(unsigned char *src, unsigned char *dst, long size); - -unsigned char * notCompressed(unsigned char *src, unsigned char *dst, long size); - -#endif // MO3_UNPACK_H +#ifndef MO3_UNPACK_H +#define MO3_UNPACK_H 1 + +unsigned char * unpack(unsigned char *src, unsigned char *dst, long size); +unsigned char * unpackSamp8Delta(unsigned char *src, unsigned char *dst, long size); +unsigned char * unpackSamp8DeltaPrediction(unsigned char *src, unsigned char *dst, long size); +unsigned char * unpackSamp16Delta(unsigned char *src, unsigned char *dst, long size); +unsigned char * unpackSamp16DeltaPrediction(unsigned char *src, unsigned char *dst, long size); + +unsigned char * notCompressed(unsigned char *src, unsigned char *dst, long size); + +#endif // MO3_UNPACK_H --- unmo3-0.6.orig/unmo3.c +++ unmo3-0.6/unmo3.c @@ -1,256 +1,256 @@ -/* - * unmo3.c (unpacks and parses .MO3 files) - * v0.5 : 24Jan2006, lclevy@free.fr, released under GPL license - * - * 19Jul2009 : v0.6 = updates for v2.4 encoder (version==5, compressed data at 0x0c, 2x 0 after sample names). - * - * Special thanks to - * Laurent Laubin (PEtite compression removal) - * Matthew T. Russotto (http://www.speakeasy.org/~russotto/) for the header compression explanation - * Stuart Caie (Kyzer@4u.net) - */ - -#include -#include -#include -#include - -#include"endian_macros.h" - -#include"mo3_unpack.h" -#include"mo3_parse.h" -#include"mo3_mp3.h" - -#define VERSION "0.6" - -extern char *compName[]; -extern char *resoName[]; - -void usage() -{ - printf("unmo3 [-d debuglevel] [-a parselevel] [-h outheaderfile] [-s] [-v pattern channel] [-o] filename.mo3\n"); - exit(1); -} - - -int debug=1; - -int saveFile(char *filename, unsigned char *buf, long len) -{ - FILE *out; - out=(FILE*)fopen(filename,"wb"); - if (!out) { - perror("fopen"); - return -1; - } - fwrite(buf, len, 1, out); - fclose(out); - - return 0; -} - -#define SAVE_NOTHING -2 -#define SAVE_ALL -1 - -int main(int argc, char *argv[]) -{ - unsigned long uncomp_size; - FILE *file; - unsigned char *uncomp_header, *ptr; - unsigned char *mo3; - char *saveName=0, *mo3Name=0; - unsigned char *sample1=0; - int sampleNr = SAVE_NOTHING; - char track=0; - unsigned char headerOffset = 8; - - long mo3Len; - int i; - int parseLevel=0; - struct mo3Data mo3Hdr; - char sampleName[50]; - int pattern=-1, channel=0, voice; - - if (argc<2) - usage(); - - i=0; - while (imo3Hdr.patternNb)) - pattern = 0; - if ( (channel < 1) || (channel > mo3Hdr.channelNb) ) - channel = 1; - voice = findVoiceNumber(pattern, channel, uncomp_header, &mo3Hdr); - if (voice!=-1) { - printf("\nDisplaying encoded channel #%d of pattern #%d (length %d): unique voice #%d \n", - channel, pattern, mo3Hdr.patternLen[i], voice); - parseVoice(uncomp_header, mo3Hdr.voicePtr[voice], &mo3Hdr, 4); - if (track) { - printf("\nDisplaying the channel like in editors:\n"); - parseTrack(uncomp_header, mo3Hdr.voicePtr[voice], &mo3Hdr, 0); - } - } - } - - if (sampleNr!=SAVE_NOTHING) { - putchar('\n'); - for(i=0; i0 ) { - if (mo3Hdr.samples[i].method!=0) { - sample1 = malloc(mo3Hdr.samples[i].len); - if (!sample1) { - perror("malloc"); - break; - } - } - else - sample1 = 0; - - if (debug>1) - printf("sample#%03d is at offset 0x%x in compressed data\n", i+1, ptr-(mo3+8)); - - if (mo3Hdr.samples[i].method!=0) { - ptr = mo3Hdr.samples[i].method(ptr, sample1, mo3Hdr.samples[i].len); - if ( sampleNr==SAVE_ALL || (sampleNr-1)==i ) { - sprintf(sampleName,"sample%03d.dat",i+1); - saveFile(sampleName, sample1, mo3Hdr.samples[i].len); - printf("saving %s (offset 0x%x, length %ld/%ld bytes, compression %s, resolution %s)...\n", - sampleName, ptr-(mo3+8), mo3Hdr.samples[i].len, - mo3Hdr.samples[i].lenComp, compName[mo3Hdr.samples[i].compression-1], - resoName[mo3Hdr.samples[i].reso-1]); - } - - } else { - - if ( sampleNr==SAVE_ALL || (sampleNr-1)==i ) { - if (mo3Hdr.samples[i].compression==MO3COMPR_MP3) - sprintf(sampleName,"sample%03d.mp3",i+1); - if (mo3Hdr.samples[i].compression==MO3COMPR_OGG) - sprintf(sampleName,"sample%03d.ogg",i+1); - if (mo3Hdr.samples[i].compression==MO3COMPR_NONE) - sprintf(sampleName,"sample%03d.dat",i+1); - saveFile(sampleName, ptr, mo3Hdr.samples[i].lenComp); - printf("saving %s (offset 0x%x, length %ld/%ld bytes, compression %s, resolution %s)...\n", - sampleName, ptr-(mo3+8), mo3Hdr.samples[i].len, - mo3Hdr.samples[i].lenComp, compName[mo3Hdr.samples[i].compression-1], - resoName[mo3Hdr.samples[i].reso-1]); - } - ptr+=mo3Hdr.samples[i].lenComp; - - } - if (sample1) - free(sample1); - } // if len - } // for - } // if - - - free(mo3Hdr.samples); - free(mo3Hdr.patternLen); - free(mo3Hdr.voicePtr); - free(mo3); - free(uncomp_header); - - return 0; -} +/* + * unmo3.c (unpacks and parses .MO3 files) + * v0.5 : 24Jan2006, lclevy@free.fr, released under GPL license + * + * 19Jul2009 : v0.6 = updates for v2.4 encoder (version==5, compressed data at 0x0c, 2x 0 after sample names). + * + * Special thanks to + * Laurent Laubin (PEtite compression removal) + * Matthew T. Russotto (http://www.speakeasy.org/~russotto/) for the header compression explanation + * Stuart Caie (Kyzer@4u.net) + */ + +#include +#include +#include +#include + +#include"endian_macros.h" + +#include"mo3_unpack.h" +#include"mo3_parse.h" +#include"mo3_mp3.h" + +#define VERSION "0.6" + +extern char *compName[]; +extern char *resoName[]; + +void usage() +{ + printf("unmo3 [-d debuglevel] [-a parselevel] [-h outheaderfile] [-s] [-v pattern channel] [-o] filename.mo3\n"); + exit(1); +} + + +int debug=1; + +int saveFile(char *filename, unsigned char *buf, long len) +{ + FILE *out; + out=(FILE*)fopen(filename,"wb"); + if (!out) { + perror("fopen"); + return -1; + } + fwrite(buf, len, 1, out); + fclose(out); + + return 0; +} + +#define SAVE_NOTHING -2 +#define SAVE_ALL -1 + +int main(int argc, char *argv[]) +{ + unsigned long uncomp_size; + FILE *file; + unsigned char *uncomp_header, *ptr; + unsigned char *mo3; + char *saveName=0, *mo3Name=0; + unsigned char *sample1=0; + int sampleNr = SAVE_NOTHING; + char track=0; + unsigned char headerOffset = 8; + + long mo3Len; + int i; + int parseLevel=0; + struct mo3Data mo3Hdr; + char sampleName[50]; + int pattern=-1, channel=0, voice; + + if (argc<2) + usage(); + + i=0; + while (imo3Hdr.patternNb)) + pattern = 0; + if ( (channel < 1) || (channel > mo3Hdr.channelNb) ) + channel = 1; + voice = findVoiceNumber(pattern, channel, uncomp_header, &mo3Hdr); + if (voice!=-1) { + printf("\nDisplaying encoded channel #%d of pattern #%d (length %d): unique voice #%d \n", + channel, pattern, mo3Hdr.patternLen[i], voice); + parseVoice(uncomp_header, mo3Hdr.voicePtr[voice], &mo3Hdr, 4); + if (track) { + printf("\nDisplaying the channel like in editors:\n"); + parseTrack(uncomp_header, mo3Hdr.voicePtr[voice], &mo3Hdr, 0); + } + } + } + + if (sampleNr!=SAVE_NOTHING) { + putchar('\n'); + for(i=0; i0 ) { + if (mo3Hdr.samples[i].method!=0) { + sample1 = malloc(mo3Hdr.samples[i].len); + if (!sample1) { + perror("malloc"); + break; + } + } + else + sample1 = 0; + + if (debug>1) + printf("sample#%03d is at offset 0x%x in compressed data\n", i+1, ptr-(mo3+8)); + + if (mo3Hdr.samples[i].method!=0) { + ptr = mo3Hdr.samples[i].method(ptr, sample1, mo3Hdr.samples[i].len); + if ( sampleNr==SAVE_ALL || (sampleNr-1)==i ) { + sprintf(sampleName,"sample%03d.dat",i+1); + saveFile(sampleName, sample1, mo3Hdr.samples[i].len); + printf("saving %s (offset 0x%x, length %ld/%ld bytes, compression %s, resolution %s)...\n", + sampleName, ptr-(mo3+8), mo3Hdr.samples[i].len, + mo3Hdr.samples[i].lenComp, compName[mo3Hdr.samples[i].compression-1], + resoName[mo3Hdr.samples[i].reso-1]); + } + + } else { + + if ( sampleNr==SAVE_ALL || (sampleNr-1)==i ) { + if (mo3Hdr.samples[i].compression==MO3COMPR_MP3) + sprintf(sampleName,"sample%03d.mp3",i+1); + if (mo3Hdr.samples[i].compression==MO3COMPR_OGG) + sprintf(sampleName,"sample%03d.ogg",i+1); + if (mo3Hdr.samples[i].compression==MO3COMPR_NONE) + sprintf(sampleName,"sample%03d.dat",i+1); + saveFile(sampleName, ptr, mo3Hdr.samples[i].lenComp); + printf("saving %s (offset 0x%x, length %ld/%ld bytes, compression %s, resolution %s)...\n", + sampleName, ptr-(mo3+8), mo3Hdr.samples[i].len, + mo3Hdr.samples[i].lenComp, compName[mo3Hdr.samples[i].compression-1], + resoName[mo3Hdr.samples[i].reso-1]); + } + ptr+=mo3Hdr.samples[i].lenComp; + + } + if (sample1) + free(sample1); + } // if len + } // for + } // if + + + free(mo3Hdr.samples); + free(mo3Hdr.patternLen); + free(mo3Hdr.voicePtr); + free(mo3); + free(uncomp_header); + + return 0; +}