diff -ruN TiMidity++-2.8.2/AUTHORS TiMidity++-2.9.0/AUTHORS --- TiMidity++-2.8.2/AUTHORS Mon Sep 27 21:40:40 1999 +++ TiMidity++-2.9.0/AUTHORS Wed Feb 16 01:56:18 2000 @@ -27,4 +27,5 @@ Colour window manager icon by Tim Allen NAS by Michael Haardt Eric A. Welsh + Paolo Bonzini and other many people sends information and bug-fix codes. diff -ruN TiMidity++-2.8.2/ChangeLog TiMidity++-2.9.0/ChangeLog --- TiMidity++-2.8.2/ChangeLog Mon Feb 7 15:33:27 2000 +++ TiMidity++-2.9.0/ChangeLog Sun Feb 27 22:49:44 2000 @@ -1,3 +1,46 @@ +2000-02-27 Masanao Izumo + + * Version 2.9.0 released. + +2000-02-24 Masanao Izumo + + * doc/C/timidity.cfg.5,doc/ja_JP.ujis/timidity.cfg.5 (#extension opt): + Fixed documentation error. + * libunimod/unimod.h (CHAR): Fixed redefiend error on Windows. + +2000-02-19 Masanao Izumo + + * timidity/{playmidi.c,controls.h (CTLE_PROGRAM): Change control interface + of program event. + * timidity/{playmidi.c,controls.h (CTLE_DRUMPART): New event interface. + * interface/ncurs_c.c: Change somethings... + * interface/{gtk_c.cx_sherry.c},libunimod/{mloader.c,unimod.h}, + timidity/mod2midi.h: + Shut gcc warning up. + * libunimod/{unimod.h,unimod_priv.h}: WIN32 => __W32__ + * timidity/playmici.c: Fixed key up/down for MOD file playing. + +2000-02-18 Masanao Izumo + + * timidity/resample.c (FINALINTERP): Ignore. + Now, TiMidity does not hit the end out of data, and ignores a final + interpolation. + * timidity/playmidi.c: Avoid overlapped voice when MOD file is playing. + * interface/ncurs_c.c,timidity/playmidi.c: Fixed a indicator probrem. + +2000-02-16 Paolo Bonzini + + * configure.in,libunimod/*,timidity/{Makefile.am,mod.c,mod.h,mod2midi.c, + mod2midi.h,readmici.c,readmidi.c}: Support full module player. + +2000-02-16 Paolo Bonzini + + * libarc/{url.h,url.c}: Bug fix + +2000-02-15 Masanao Izumo + + * libarc/url.c (url_expand_home_dir): Bug fix of buffer-overrun. + 2000-02-07 Masanao Izumo * Version 2.8.2 released. diff -ruN TiMidity++-2.8.2/Makefile.am TiMidity++-2.9.0/Makefile.am --- TiMidity++-2.8.2/Makefile.am Mon Feb 7 07:28:54 2000 +++ TiMidity++-2.9.0/Makefile.am Wed Feb 16 01:09:29 2000 @@ -22,6 +22,7 @@ utils \ libarc \ interface \ + libunimod \ timidity \ doc diff -ruN TiMidity++-2.8.2/Makefile.in TiMidity++-2.9.0/Makefile.in --- TiMidity++-2.8.2/Makefile.in Mon Feb 7 21:39:12 2000 +++ TiMidity++-2.9.0/Makefile.in Sun Feb 27 22:50:06 2000 @@ -114,7 +114,7 @@ tcltk_dep = @tcltk_dep@ timidity_LDFLAGS = @timidity_LDFLAGS@ -SUBDIRS = utils libarc interface timidity doc +SUBDIRS = utils libarc interface libunimod timidity doc EXTRA_DIST = AUTHORS COPYING ChangeLog ChangeLog.1 INSTALL INSTALL.jp NEWS README README.jp timidity.ide timidity.mak TiMidity-uj.ad TiMidity.ad @@ -350,7 +350,6 @@ fi; \ done $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook - info-am: info: info-recursive dvi-am: diff -ruN TiMidity++-2.8.2/NEWS TiMidity++-2.9.0/NEWS --- TiMidity++-2.8.2/NEWS Mon Feb 7 14:11:40 2000 +++ TiMidity++-2.9.0/NEWS Sun Feb 27 22:49:52 2000 @@ -1,3 +1,7 @@ +02/27, 2000 + * Version 2.9.0 released. + * Support full module player. + 02/07, 2000 * Version 2.8.2 released. * Support ALSA 0.5 diff -ruN TiMidity++-2.8.2/configs/msc-config.h TiMidity++-2.9.0/configs/msc-config.h --- TiMidity++-2.8.2/configs/msc-config.h Mon Feb 7 21:39:43 2000 +++ TiMidity++-2.9.0/configs/msc-config.h Sun Feb 27 22:50:51 2000 @@ -217,7 +217,7 @@ #define HAVE_MMSYSTEM_H /* In VDS Macro AAA=BBB is not available. */ -#define TIMID_VERSION "2.8.2" +#define TIMID_VERSION "2.9.0" #define DEFAULT_PATH ".\\" #define AU_W32 #define WINSOCK diff -ruN TiMidity++-2.8.2/configure TiMidity++-2.9.0/configure --- TiMidity++-2.8.2/configure Mon Feb 7 08:20:57 2000 +++ TiMidity++-2.9.0/configure Mon Feb 21 14:02:40 2000 @@ -884,7 +884,7 @@ PACKAGE=TiMidity++ -VERSION=2.8.2 +VERSION=2.9.0 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } @@ -8053,6 +8053,7 @@ interface/bitmaps/Makefile interface/pixmaps/Makefile libarc/Makefile +libunimod/Makefile timidity/Makefile utils/Makefile doc/Makefile @@ -8246,6 +8247,7 @@ interface/bitmaps/Makefile interface/pixmaps/Makefile libarc/Makefile +libunimod/Makefile timidity/Makefile utils/Makefile doc/Makefile diff -ruN TiMidity++-2.8.2/configure.in TiMidity++-2.9.0/configure.in --- TiMidity++-2.8.2/configure.in Mon Feb 7 07:28:05 2000 +++ TiMidity++-2.9.0/configure.in Mon Feb 21 14:02:33 2000 @@ -55,7 +55,7 @@ AC_INIT(timidity/timidity.c) SHELL=${CONFIG_SHELL-/bin/sh} AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(TiMidity++, 2.8.2, no-define) +AM_INIT_AUTOMAKE(TiMidity++, 2.9.0, no-define) dnl To use CONTAINS() macro (See acinclude.m4) CONTAINS_INIT @@ -1321,6 +1321,7 @@ interface/bitmaps/Makefile interface/pixmaps/Makefile libarc/Makefile +libunimod/Makefile timidity/Makefile utils/Makefile doc/Makefile diff -ruN TiMidity++-2.8.2/doc/C/timidity.cfg.5 TiMidity++-2.9.0/doc/C/timidity.cfg.5 --- TiMidity++-2.8.2/doc/C/timidity.cfg.5 Fri Feb 26 12:41:00 1999 +++ TiMidity++-2.9.0/doc/C/timidity.cfg.5 Thu Feb 24 13:40:39 2000 @@ -188,7 +188,7 @@ FTP server if TiMidity access any file via FTp. .TP -.BI "#extension [\-]{option}" " [optarg]" +.BI "#extension opt [\-]{option}" " [optarg]" Sets the value of boot\-time options. .TP diff -ruN TiMidity++-2.8.2/doc/ja_JP.ujis/timidity.cfg.5 TiMidity++-2.9.0/doc/ja_JP.ujis/timidity.cfg.5 --- TiMidity++-2.8.2/doc/ja_JP.ujis/timidity.cfg.5 Fri Feb 26 12:45:46 1999 +++ TiMidity++-2.9.0/doc/ja_JP.ujis/timidity.cfg.5 Thu Feb 24 13:41:15 2000 @@ -1,234 +1,234 @@ -.TH timidity.cfg 5 "Nov 24 1998" "1.0.0" -.SH NAME -timidity.cfg \- configure file of TiMidity++ - -.SH SYNOPSIS -.TP -.B /etc/timidity.cfg -.TP -.B /usr/local/lib/timidity/timidity.cfg - -.P -.SH DESCRIPTION -\fItimidity.cfg\fP は、timidity(1) の実行時の様々な設定を行うための設定ファイルです。 -音色データの置き場所、音色自体の設定、その他諸々を設定する事が出来ます。 -.br -\fITiMidity++\fP は、起動時にコマンドラインオプションを見る前に、 -\fItimidity.cfg\fP を探索します。 -このファイルにアクセスできない場合、また、ライブラリパスが -コマンドラインで \fB\-L\fP オプションによって変更されている場合は、 -全てのオプションを見た後に、 -新しいライブラリパスに従ってデフォルトファイルを -(\fB\-c\fP オプションで別の設定ファイルが指定されていないならば) -再探索します。 -.br -もし複数のファイルが指定された場合には、 -後に読み込まれた設定によって前の設定が上書きされます。 - -.P -設定ファイル中には以下の書式が指定可能です: - -.TP -.BI dir " directory" -\fIdirectory\fP を探索パスに加えます。加え方は\fB\-L\fP オプションと同様。 -.br -TiMidity++ では、アーカイブファイルをパッチセットにすることができます。 - -例: -.br -dir /usr/local/lib/timidity/inst/foo.zip# -.br -bank 0 -.br -0 bar.pat -.br -1 baz.pat -.br -2 zoo.pat -.br -まず、dir で通常のディレクトリのようにアーカイブファイル (上の例では -/usr/local/lib/timidity/inst/foo.zip) -を指定します。このとき、アーカイブファイル名 -の最後に \fB#\fP をつけてください。この \fB#\fP があることで、アーカイブファイルで -あることを \fITiMidity++\fP は認識します。こうしておくと、\fIdir\fP で指定された -アーカイブファイルの中のパッチファイルも読み込み対象になります。 -上の例では、foo.zip の中にある bar.pat、 baz.pat、zoo.pat が読み込まれます。 - -.TP -.BI source " file" -他の設定ファイルをその場所に挿入し、続行します。 - -.TP -.BI bank " number" -これ以降変更するトーンバンクを選択します。 -この文以後の patch の対応付けは、指定されたトーンバンクに対して行われます。 - -.TP -.BI progbase " number" -これ以降、プログラム番号を \fInumber\fP から \fInumber+128\fP で設定・表示します。 -たとえば、\fBprogbase 1\fP とした場合は、それ以降プログラム番号は 1 から 128 で設定・表示されます。 - -.TP -.BI drumset " number" -変更するドラムセットを選択します。 -この文以後の patch の対応付けは、指定されたドラムセットに対して行われます。 - -.TP -.BI number " file [options]" -現在のトーンバンクやドラムセットで、 MIDI プログラムナンバー \fInumber\fP で -使用する \fIpatch file\fP を指定します。 -\fIoptions\fP は次のものが使用可能です: -.RS -.TP -\fBamp=\fP\fIamplification\fP -インスツルメントのボリュームを \fIamplification\fP % にします。 -もし値が指定されていない場合、 -インスツルメントが読み込まれる時に自動的に設定されます。 -.TP -\fBnote=\fP\fInote\fP -インスツルメントを演奏する時に決まった MIDI ノート(音階) を使用します。 -\fInote\fP を \fB0\fP にすると、 -最初に Note On イベントが発生した時点でのノートを使用します。 -パーカッションインスツルメントに対しては、 -もし設定ファイルで値が設定されていなければ、 -\fBpatch\fP ファイルに入っている値を使用します。 -.TP -\fBpan=\fP\fIpanning\fP -インスツルメントのデフォルトのパンニングを設定します。 -\fIpanning\fP は \fBleft\fP、\fBright\fP、\fBcenter\fP、あるいは -\fB\-100\fP から \fB100\fP までの整数値を取ることができます。\fB-100\fP が最も左、 -\fB100\fP が最も右になります。 -値が与えられていない場合には、\fBpatch\fP ファイルに入っている値を使用します。 -もちろん、MIDI ファイル中のパンニングコントロールの方が優先されます。 -.TP -\fBkeep=\fP{\fBloop\fP|\fBenv\fP} -パーカッションインスツルメントでは、 -デフォルトでループ情報とエンベロープ情報が破棄されます。 -また、メロディーインスツルメントに異常なエンベロープが存在した場合にも、 -エンベロープ情報は自動的に破棄されます。 -\fBkeep\fP を指定することで、エンベロープ情報やループ情報が破棄されるのを防ぎます。 -例えば、Short、Long Whistle パーカッションインスツルメント -(General MIDI の 71、72 番) に対しては、 -設定ファイルで ``\fBkeep=loop keep=env\fP'' としておく必要があります。 -.TP -\fBstrip=\fP{\fBloop\fP|\fBenv\fP|\fBtail\fP} -インスツルメントとして使用する \fIpatch\fP の、ループ情報やエンベロープ情報や -テール(ループの後にあるデータ)を全て強制的に破棄します。 -サードパーティーのインスツルメントにはループの後にゴミが付いているものがあり、 -インスツルメントを演奏する度にクリッキングノイズが入ってしまうことがあります。 -その場合、\fBstrip=tail\fP オプションを指定すれば音質が改善されます。 -.RE -.LP -.P - -TiMidity++ では、以下の拡張命令が追加されています: - -.TP -.BI "#extension altassign" " program1 program2 ..." -ドラムセットについて、オルタネートアサインを設定します。 -.br -drumset 0 -.br -altassign 42 44 46 -.br -と書くと、ドラムセット 0 の 42/44/46 が排他的に鳴ります。 -ドラムセット 0 で定義されたオルタネートアサインは -デフォルトで使用されます。 - -.TP -.BI "#extension comm" " program comment" -Instrument 番号 \fIprogram\fP にコメント \fIcomment\fP を指定します. -ここで設定した \fIcomment\fP は \fB\-iNt\fP や \fI\-iTt\fP オプション -で起動した時に、インジケータラインに表示されます。 -.TP -.BI "#extension timeout" " program secound" -Instrument 番号 \fIprogram\fP で \fIsecound\fP 秒以上 Suspend 状態 -が続いた場合、その音をオフにします。 -.TP -.BI "#extension copydrumset" " drumset" -\fIdrumset\fP 番号の状態すべてを現在の \fIdrumset\fP にコピーします。 -.TP -.BI "#extension copybank" " bank" -\fIbank\fP 番号の状態すべてを現在の \fIbank\fP にコピーします。 -.TP -.BI "#extension HTTPproxy" " hostname:port" -HTTP の proxy を設定します。proxy のホスト名を \fIhostname\fPに、 -ポート番号を \fIport\fP に指定します。 -.TP -.BI "#extension FTPproxy" " hostname:port" -FTP の proxy を設定します。proxy のホスト名を \fIhostname\fPに、 -ポート番号を \fIport\fP に指定します。 -.TP -.BI "#extension mailaddr" " your\-mail\-address" -ユーザのメールアドレスを \fIyour\-mail\-address\fP に指定します。 -このメールアドレスは、 -FTP 接続を proxy を介さずにダイレクトに繋ぐ場合に用いられます。 -.TP -.BI "#extension [\-]{option}" " [optarg]" -起動時のオプションを指定します。 -.TP -.BI "#extension undef" " progno" -現在のバンクのプログラム番号\fIprogno\fP を未定義にします。 - -.P -これらの拡張命令は \fB#\fP から始まっており、古い \fITiMidity++\fP では -単なるコメントと扱われ無視されます。よって、古い \fITiMidity\fP -との互換性を保つことができます。 -.br -なお、TiMidity++ では #extension は空白として扱われるようになっています。 - -.P -\fITiMidity++\fP の設定ファイル (*.cfg) 中の source の引数に UNIX のコマンド -からの出力を利用できます(UNIX のみ)。ファイル名の最後に -\fI\|\fP(ASCII 0x7c) を記述すると UNIX コマンドとみなされ、 -そのコマンドの出力が source の引数になります。 -.br -\fBsource\fP \fIcommand|\fP -のようにすると,\fIcommand\fP の出力が \fBsource\fP の引数になります。 -環境によって \fITiMidity++\fP の設定を選択したい場合などに便利です。なお、 -\fIcommand\fP \fI|\fP のように、途中にスペースが入ると、 -設定ファイル読み込み時に -区切られてしまい、コマンドと見なされなくなってしまいます。 -この機能はファイル名を指定できる全ての場所に適用できます。 - - timidity 'cat fild.mid|' -.br - -は、cat fild.mid の出力結果から読み取ります。 - -.P -*.cfg の \fIsoundfont\fP のオプションに \fIremove\fP を指定すると、 -指定されているファイルを未定義にします。 - -.P -.SH SEE ALSO -timidity(1), lsmidiprog(1), mididump(1), patinfo(1), sf2text(1), wav2pat(1) - -.P -.SH COPYRIGHT -Copyright (C) 1999 Masanao Izumo -Copyright (C) 1995 Tuukka Toivonen -.P -Original version was developed under the name of Tuukka Toivonen - until the version of TiMidity-0.2i. His development was -discontinued because of his busy work. -.P -This program is free software; you can redistribute it and/or modify -it under the terms of the \fIGNU General Public License\fP as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. -.P -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 \fIGNU -General Public License\fP for more details. -.P -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., 675 Mass Ave, Cambridge, MA 02139, USA. - -.SH AVAILABILITY -The latest release is available on the TiMidity++ Page, -.br -URL http://www.goice.co.jp/member/mo/timidity/ -.br +.TH timidity.cfg 5 "Nov 24 1998" "1.0.0" +.SH NAME +timidity.cfg \- configure file of TiMidity++ + +.SH SYNOPSIS +.TP +.B /etc/timidity.cfg +.TP +.B /usr/local/lib/timidity/timidity.cfg + +.P +.SH DESCRIPTION +\fItimidity.cfg\fP は、timidity(1) の実行時の様々な設定を行うための設定ファイルです。 +音色データの置き場所、音色自体の設定、その他諸々を設定する事が出来ます。 +.br +\fITiMidity++\fP は、起動時にコマンドラインオプションを見る前に、 +\fItimidity.cfg\fP を探索します。 +このファイルにアクセスできない場合、また、ライブラリパスが +コマンドラインで \fB\-L\fP オプションによって変更されている場合は、 +全てのオプションを見た後に、 +新しいライブラリパスに従ってデフォルトファイルを +(\fB\-c\fP オプションで別の設定ファイルが指定されていないならば) +再探索します。 +.br +もし複数のファイルが指定された場合には、 +後に読み込まれた設定によって前の設定が上書きされます。 + +.P +設定ファイル中には以下の書式が指定可能です: + +.TP +.BI dir " directory" +\fIdirectory\fP を探索パスに加えます。加え方は\fB\-L\fP オプションと同様。 +.br +TiMidity++ では、アーカイブファイルをパッチセットにすることができます。 + +例: +.br +dir /usr/local/lib/timidity/inst/foo.zip# +.br +bank 0 +.br +0 bar.pat +.br +1 baz.pat +.br +2 zoo.pat +.br +まず、dir で通常のディレクトリのようにアーカイブファイル (上の例では +/usr/local/lib/timidity/inst/foo.zip) +を指定します。このとき、アーカイブファイル名 +の最後に \fB#\fP をつけてください。この \fB#\fP があることで、アーカイブファイルで +あることを \fITiMidity++\fP は認識します。こうしておくと、\fIdir\fP で指定された +アーカイブファイルの中のパッチファイルも読み込み対象になります。 +上の例では、foo.zip の中にある bar.pat、 baz.pat、zoo.pat が読み込まれます。 + +.TP +.BI source " file" +他の設定ファイルをその場所に挿入し、続行します。 + +.TP +.BI bank " number" +これ以降変更するトーンバンクを選択します。 +この文以後の patch の対応付けは、指定されたトーンバンクに対して行われます。 + +.TP +.BI progbase " number" +これ以降、プログラム番号を \fInumber\fP から \fInumber+128\fP で設定・表示します。 +たとえば、\fBprogbase 1\fP とした場合は、それ以降プログラム番号は 1 から 128 で設定・表示されます。 + +.TP +.BI drumset " number" +変更するドラムセットを選択します。 +この文以後の patch の対応付けは、指定されたドラムセットに対して行われます。 + +.TP +.BI number " file [options]" +現在のトーンバンクやドラムセットで、 MIDI プログラムナンバー \fInumber\fP で +使用する \fIpatch file\fP を指定します。 +\fIoptions\fP は次のものが使用可能です: +.RS +.TP +\fBamp=\fP\fIamplification\fP +インスツルメントのボリュームを \fIamplification\fP % にします。 +もし値が指定されていない場合、 +インスツルメントが読み込まれる時に自動的に設定されます。 +.TP +\fBnote=\fP\fInote\fP +インスツルメントを演奏する時に決まった MIDI ノート(音階) を使用します。 +\fInote\fP を \fB0\fP にすると、 +最初に Note On イベントが発生した時点でのノートを使用します。 +パーカッションインスツルメントに対しては、 +もし設定ファイルで値が設定されていなければ、 +\fBpatch\fP ファイルに入っている値を使用します。 +.TP +\fBpan=\fP\fIpanning\fP +インスツルメントのデフォルトのパンニングを設定します。 +\fIpanning\fP は \fBleft\fP、\fBright\fP、\fBcenter\fP、あるいは +\fB\-100\fP から \fB100\fP までの整数値を取ることができます。\fB-100\fP が最も左、 +\fB100\fP が最も右になります。 +値が与えられていない場合には、\fBpatch\fP ファイルに入っている値を使用します。 +もちろん、MIDI ファイル中のパンニングコントロールの方が優先されます。 +.TP +\fBkeep=\fP{\fBloop\fP|\fBenv\fP} +パーカッションインスツルメントでは、 +デフォルトでループ情報とエンベロープ情報が破棄されます。 +また、メロディーインスツルメントに異常なエンベロープが存在した場合にも、 +エンベロープ情報は自動的に破棄されます。 +\fBkeep\fP を指定することで、エンベロープ情報やループ情報が破棄されるのを防ぎます。 +例えば、Short、Long Whistle パーカッションインスツルメント +(General MIDI の 71、72 番) に対しては、 +設定ファイルで ``\fBkeep=loop keep=env\fP'' としておく必要があります。 +.TP +\fBstrip=\fP{\fBloop\fP|\fBenv\fP|\fBtail\fP} +インスツルメントとして使用する \fIpatch\fP の、ループ情報やエンベロープ情報や +テール(ループの後にあるデータ)を全て強制的に破棄します。 +サードパーティーのインスツルメントにはループの後にゴミが付いているものがあり、 +インスツルメントを演奏する度にクリッキングノイズが入ってしまうことがあります。 +その場合、\fBstrip=tail\fP オプションを指定すれば音質が改善されます。 +.RE +.LP +.P + +TiMidity++ では、以下の拡張命令が追加されています: + +.TP +.BI "#extension altassign" " program1 program2 ..." +ドラムセットについて、オルタネートアサインを設定します。 +.br +drumset 0 +.br +altassign 42 44 46 +.br +と書くと、ドラムセット 0 の 42/44/46 が排他的に鳴ります。 +ドラムセット 0 で定義されたオルタネートアサインは +デフォルトで使用されます。 + +.TP +.BI "#extension comm" " program comment" +Instrument 番号 \fIprogram\fP にコメント \fIcomment\fP を指定します. +ここで設定した \fIcomment\fP は \fB\-iNt\fP や \fI\-iTt\fP オプション +で起動した時に、インジケータラインに表示されます。 +.TP +.BI "#extension timeout" " program secound" +Instrument 番号 \fIprogram\fP で \fIsecound\fP 秒以上 Suspend 状態 +が続いた場合、その音をオフにします。 +.TP +.BI "#extension copydrumset" " drumset" +\fIdrumset\fP 番号の状態すべてを現在の \fIdrumset\fP にコピーします。 +.TP +.BI "#extension copybank" " bank" +\fIbank\fP 番号の状態すべてを現在の \fIbank\fP にコピーします。 +.TP +.BI "#extension HTTPproxy" " hostname:port" +HTTP の proxy を設定します。proxy のホスト名を \fIhostname\fPに、 +ポート番号を \fIport\fP に指定します。 +.TP +.BI "#extension FTPproxy" " hostname:port" +FTP の proxy を設定します。proxy のホスト名を \fIhostname\fPに、 +ポート番号を \fIport\fP に指定します。 +.TP +.BI "#extension mailaddr" " your\-mail\-address" +ユーザのメールアドレスを \fIyour\-mail\-address\fP に指定します。 +このメールアドレスは、 +FTP 接続を proxy を介さずにダイレクトに繋ぐ場合に用いられます。 +.TP +.BI "#extension opt [\-]{option}" " [optarg]" +起動時のオプションを指定します。 +.TP +.BI "#extension undef" " progno" +現在のバンクのプログラム番号\fIprogno\fP を未定義にします。 + +.P +これらの拡張命令は \fB#\fP から始まっており、古い \fITiMidity++\fP では +単なるコメントと扱われ無視されます。よって、古い \fITiMidity\fP +との互換性を保つことができます。 +.br +なお、TiMidity++ では #extension は空白として扱われるようになっています。 + +.P +\fITiMidity++\fP の設定ファイル (*.cfg) 中の source の引数に UNIX のコマンド +からの出力を利用できます(UNIX のみ)。ファイル名の最後に +\fI\|\fP(ASCII 0x7c) を記述すると UNIX コマンドとみなされ、 +そのコマンドの出力が source の引数になります。 +.br +\fBsource\fP \fIcommand|\fP +のようにすると,\fIcommand\fP の出力が \fBsource\fP の引数になります。 +環境によって \fITiMidity++\fP の設定を選択したい場合などに便利です。なお、 +\fIcommand\fP \fI|\fP のように、途中にスペースが入ると、 +設定ファイル読み込み時に +区切られてしまい、コマンドと見なされなくなってしまいます。 +この機能はファイル名を指定できる全ての場所に適用できます。 + + timidity 'cat fild.mid|' +.br + +は、cat fild.mid の出力結果から読み取ります。 + +.P +*.cfg の \fIsoundfont\fP のオプションに \fIremove\fP を指定すると、 +指定されているファイルを未定義にします。 + +.P +.SH SEE ALSO +timidity(1), lsmidiprog(1), mididump(1), patinfo(1), sf2text(1), wav2pat(1) + +.P +.SH COPYRIGHT +Copyright (C) 1999 Masanao Izumo +Copyright (C) 1995 Tuukka Toivonen +.P +Original version was developed under the name of Tuukka Toivonen + until the version of TiMidity-0.2i. His development was +discontinued because of his busy work. +.P +This program is free software; you can redistribute it and/or modify +it under the terms of the \fIGNU General Public License\fP as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. +.P +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 \fIGNU +General Public License\fP for more details. +.P +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., 675 Mass Ave, Cambridge, MA 02139, USA. + +.SH AVAILABILITY +The latest release is available on the TiMidity++ Page, +.br +URL http://www.goice.co.jp/member/mo/timidity/ +.br diff -ruN TiMidity++-2.8.2/interface/Makefile.in TiMidity++-2.9.0/interface/Makefile.in --- TiMidity++-2.8.2/interface/Makefile.in Mon Feb 7 21:39:21 2000 +++ TiMidity++-2.9.0/interface/Makefile.in Sun Feb 27 22:50:16 2000 @@ -366,10 +366,6 @@ ../timidity/output.h ../timidity/controls.h \ ../timidity/instrum.h ../timidity/playmidi.h \ ../timidity/readmidi.h -dynamic_c.o: dynamic_c.c ../config.h ../timidity/timidity.h \ - ../utils/support.h ../timidity/common.h ../libarc/url.h \ - ../utils/mblock.h ../timidity/output.h ../timidity/controls.h \ - ../timidity/dlutils.h emacs_c.o: emacs_c.c ../config.h ../timidity/timidity.h \ ../utils/support.h ../timidity/common.h ../libarc/url.h \ ../utils/mblock.h ../timidity/output.h ../timidity/controls.h \ @@ -378,7 +374,8 @@ gtk_c.o: gtk_c.c ../config.h ../timidity/timidity.h ../utils/support.h \ ../timidity/common.h ../libarc/url.h ../utils/mblock.h \ ../timidity/instrum.h ../timidity/playmidi.h \ - ../timidity/output.h ../timidity/controls.h gtk_h.h + ../timidity/output.h ../timidity/controls.h gtk_h.h \ + ../timidity/readmidi.h gtk_i.o: gtk_i.c ../config.h ../timidity/timidity.h ../utils/support.h \ ../timidity/common.h ../libarc/url.h ../utils/mblock.h gtk_h.h \ pixmaps/playpaus.xpm pixmaps/prevtrk.xpm pixmaps/nexttrk.xpm \ diff -ruN TiMidity++-2.8.2/interface/gtk_c.c TiMidity++-2.9.0/interface/gtk_c.c --- TiMidity++-2.8.2/interface/gtk_c.c Mon Feb 7 07:50:16 2000 +++ TiMidity++-2.9.0/interface/gtk_c.c Sat Feb 19 20:43:12 2000 @@ -41,7 +41,11 @@ #include #include #include - +#ifndef NO_STRING_H +#include +#else +#include +#endif #include "timidity.h" #include "common.h" #include "instrum.h" @@ -49,6 +53,7 @@ #include "output.h" #include "controls.h" #include "gtk_h.h" +#include "readmidi.h" static int ctl_open(int using_stdin, int using_stdout); static void ctl_close(void); diff -ruN TiMidity++-2.8.2/interface/mac_trace.c TiMidity++-2.9.0/interface/mac_trace.c --- TiMidity++-2.8.2/interface/mac_trace.c Mon Feb 7 07:53:47 2000 +++ TiMidity++-2.9.0/interface/mac_trace.c Sat Feb 19 22:34:11 2000 @@ -161,8 +161,8 @@ if(!ctl->trace_playing) return; - if(channel[ch].special_sample) - pr = val = channel[ch].special_sample; + if(IS_CURRENT_MOD_FILE) + pr = val; else pr = val + progbase; diff -ruN TiMidity++-2.8.2/interface/ncurs_c.c TiMidity++-2.9.0/interface/ncurs_c.c --- TiMidity++-2.8.2/interface/ncurs_c.c Mon Feb 7 07:49:46 2000 +++ TiMidity++-2.9.0/interface/ncurs_c.c Sat Feb 19 22:31:08 2000 @@ -97,8 +97,8 @@ #define CHECK_NOTE_SLEEP_TIME 5.0 #define NCURS_MIN_LINES 8 +#define CTL_STATUS_UPDATE -98 #define CTL_STATUS_INIT -99 -#define CTL_LAST_STATUS -1 #ifndef MIDI_TITLE #undef DISPLAY_MID_MODE @@ -128,11 +128,13 @@ static struct { - int prog; - int disp_cnt; + int bank, bank_lsb, bank_msb, prog, vol, exp, pan, sus, pitch, wheel; + int is_drum; + int bend_mark; + double last_note_on; char *comm; -} instr_comment[MAX_CHANNELS]; +} ChannelStatus[MAX_CHANNELS]; enum indicator_mode_t { @@ -146,7 +148,6 @@ static char *current_indicator_message = NULL; static char *indicator_msgptr = NULL; static int current_indicator_chan = 0; -static int next_indicator_chan = -1; static double indicator_last_update; static int indicator_mode = INDICATOR_DEFAULT; static int display_velocity_flag = 0; @@ -161,7 +162,6 @@ static void update_indicator(void); static void reset_indicator(void); static void indicator_chan_update(int ch); -static void indicator_set_prog(int ch, int val, char *comm); static void display_lyric(char *lyric, int sep); static void display_play_system(int mode); static void display_aq_ratio(void); @@ -190,12 +190,15 @@ }; static void ctl_note(int status, int ch, int note, int vel); -static void ctl_program(int ch, int val, char *vp); +static void ctl_drumpart(int ch, int is_drum); +static void ctl_program(int ch, int prog, char *vp, unsigned int banks); static void ctl_volume(int channel, int val); static void ctl_expression(int channel, int val); static void ctl_panning(int channel, int val); static void ctl_sustain(int channel, int val); +static void update_bend_mark(int ch); static void ctl_pitch_bend(int channel, int val); +static void ctl_mod_wheel(int channel, int wheel); static void ctl_lyric(int lyricid); static void ctl_gslcd(int id); static void ctl_reset(void); @@ -287,6 +290,7 @@ static void ctl_ncurs_mode_init(void); static void init_trace_window_chan(int ch); +static void init_chan_status(void); static void ctl_cmd_J_move(int diff); static int ctl_cmd_J_enter(void); static void ctl_cmd_L_dir(int move); @@ -428,8 +432,8 @@ N_ctl_werase(dftwin); wmove(dftwin, VERSION_LINE,0); waddstr(dftwin, "TiMidity++ v"); waddstr(dftwin, timidity_version); - wmove(dftwin, VERSION_LINE,COLS-52); - waddstr(dftwin, "(C) 1995,1999 Tuukka Toivonen and Masanao Izumo"); + wmove(dftwin, VERSION_LINE,COLS-54); + waddstr(dftwin, "(C) 1995,1999,2000 Tuukka Toivonen, Masanao Izumo"); wmove(dftwin, FILE_LINE,0); waddstr(dftwin, "File:"); #ifdef MIDI_TITLE @@ -457,13 +461,14 @@ indicator_width = COLS - 2; if(indicator_width < 40) indicator_width = 40; - if(comment_indicator_buffer == NULL) - { - memset(comment_indicator_buffer = - (char *)safe_malloc(indicator_width), 0, indicator_width); - memset(current_indicator_message = - (char *)safe_malloc(indicator_width), 0, indicator_width); - } + if(comment_indicator_buffer != NULL) + free(comment_indicator_buffer); + if(current_indicator_message != NULL) + free(current_indicator_message); + memset(comment_indicator_buffer = + (char *)safe_malloc(indicator_width), 0, indicator_width); + memset(current_indicator_message = + (char *)safe_malloc(indicator_width), 0, indicator_width); if(ctl.trace_playing) { @@ -524,152 +529,145 @@ for(i = 0; i < c; i++) waddch(dftwin, '.'); - if(ISDRUMCHANNEL(ch)) - ctl_program(ch, channel[ch].bank, channel_instrum_name(ch)); - else - ctl_program(ch, channel[ch].program, channel_instrum_name(ch)); - ctl_volume(0, CTL_STATUS_INIT); - ctl_volume(ch, channel[ch].volume); - ctl_expression(0, CTL_STATUS_INIT); - ctl_expression(ch, channel[ch].expression); - ctl_panning(ch, channel[ch].panning); - ctl_sustain(ch, channel[ch].sustain); - ctl_pitch_bend(ch, CTL_STATUS_INIT); - if(channel[ch].pitchbend == 0x2000 && channel[ch].modulation_wheel > 0) - ctl_pitch_bend(ch, -2); - else - ctl_pitch_bend(ch, channel[ch].pitchbend); + ctl_program(ch, CTL_STATUS_UPDATE, NULL, 0); + ctl_volume(ch, CTL_STATUS_UPDATE); + ctl_expression(ch, CTL_STATUS_UPDATE); + ctl_panning(ch, CTL_STATUS_UPDATE); + ctl_sustain(ch, CTL_STATUS_UPDATE); + update_bend_mark(ch); clear_bitset(channel_program_flags + ch, 0, 128); } else { + ToneBankElement *prog; + ToneBank *bank; + int b, type, pr; + wattron(dftwin, A_BOLD); wprintw(dftwin, "%02d ", ch + 1); wattroff(dftwin, A_BOLD); - if(ISDRUMCHANNEL(ch)) + b = ChannelStatus[ch].bank; + pr = ChannelStatus[ch].prog; + bank = tonebank[b]; + if(bank == NULL || bank->tone[pr].instrument == NULL) { - if(drumset[channel[ch].bank]) - wprintw(dftwin, "Drumset %d", channel[ch].bank + progbase); - else - wprintw(dftwin, "Drumset %d(=>%d)", - channel[ch].bank + progbase, progbase); + b = 0; + bank = tonebank[0]; + } + + if(ChannelStatus[ch].is_drum) + { + wprintw(dftwin, "Drumset Bank %d=>%d", + ChannelStatus[ch].bank + progbase, b + progbase); } else { - ToneBankElement *prog; - ToneBank *bank; - int b, type, pr; - - b = channel[ch].bank; - pr = channel[ch].program; - if((bank = tonebank[b]) == NULL || - bank->tone[pr].instrument == NULL) - { - b = 0; - bank = tonebank[0]; - } - prog = &bank->tone[pr]; - if(IS_CURRENT_MOD_FILE) { - type = INST_MOD; - waddstr(dftwin, "MOD "); + wprintw(dftwin, "MOD %d (%s)", + ChannelStatus[ch].prog, + ChannelStatus[ch].comm ? ChannelStatus[ch].comm : + "Not installed"); } else { + prog = &bank->tone[pr]; + if(prog->instrument != NULL && !IS_MAGIC_INSTRUMENT(prog->instrument)) { type = prog->instrument->type; - if(type == INST_SF2) - waddstr(dftwin, "SF "); + /* check instrument alias */ + if(b != 0 && + tonebank[0]->tone[pr].instrument == prog->instrument) + { + b = 0; + bank = tonebank[0]; + prog = &bank->tone[pr]; + } } else type = -1; - } - if(type == INST_GUS) - { - if(prog->name == NULL && b != 0) - { - b = 0; - bank = tonebank[0]; - prog = &bank->tone[pr]; - } - - wprintw(dftwin, "Bank %d%s Prog %d", - channel[ch].bank, - b == channel[ch].bank ? "" : "(=>0)", - pr + progbase); + wprintw(dftwin, "%d Bank %d/%d=>%d Prog %d", + type, + ChannelStatus[ch].bank_msb, + ChannelStatus[ch].bank_lsb, + b, + ChannelStatus[ch].prog + progbase); - if(prog->name) + if(type == INST_GUS) { - waddch(dftwin, ' '); - waddstr(dftwin, prog->name); + if(prog->name) + { + waddch(dftwin, ' '); + waddstr(dftwin, prog->name); + } + if(prog->comment != NULL) + wprintw(dftwin, "(%s)", prog->comment); } - if(prog->comment != NULL) - wprintw(dftwin, "(%s)", prog->comment); - } - else if(type == INST_SF2) - { - char *name, *fn; - - if(prog->instype == 1) + else if(type == INST_SF2) { - b = prog->font_bank; - pr = prog->font_preset; - } + char *name, *fn; - name = soundfont_preset_name(b, pr, -1, &fn); - if(name == NULL && b != 0) - { - if((name = soundfont_preset_name(0, pr, -1, &fn)) != NULL) - b = 0; - } + waddstr(dftwin, " (SF "); - wprintw(dftwin, "Bank %d%s Prog %d", - channel[ch].bank, - b == channel[ch].bank ? "" : "(=>0)", - pr + progbase); + if(prog->instype == 1) + { + /* Restore original one */ + b = prog->font_bank; + pr = prog->font_preset; + } - if(name != NULL) - { - char *p; - if((p = pathsep_strrchr(fn)) != NULL) - p++; - else - p = fn; - wprintw(dftwin, " (%s:%s)", name, p); - } - } - else if(type == INST_MOD) - { - pr = channel[ch].special_sample; - if(pr > 0 && special_patch[pr] != NULL) - { - if(special_patch[pr]->name != NULL) - wprintw(dftwin, "SampleID %d (%s)", - pr, special_patch[pr]->name); - else - wprintw(dftwin, "SampleID %d", pr); + name = soundfont_preset_name(b, pr, -1, &fn); + if(name == NULL && b != 0) + { + if((name = soundfont_preset_name(0, pr, -1, &fn)) != NULL) + b = 0; + } + + wprintw(dftwin, "%d,%d", b, pr + progbase); + + if(name != NULL) + { + char *p; + if((p = pathsep_strrchr(fn)) != NULL) + p++; + else + p = fn; + wprintw(dftwin, ",%s", name, p); + } + waddch(dftwin, ')'); } - else if(pr == 0) - wprintw(dftwin, "(Not installed)", pr); - else - wprintw(dftwin, "SampleID %d (Not installed)", pr); - } - else - { - wprintw(dftwin, "Bank %d%s Prog %d", - channel[ch].bank, - b == channel[ch].bank ? "" : "(=>0)", - pr + progbase); } } } } +static void init_chan_status(void) +{ + int ch; + + for(ch = 0; ch < MAX_CHANNELS; ch++) + { + ChannelStatus[ch].bank = 0; + ChannelStatus[ch].bank_msb = 0; + ChannelStatus[ch].bank_lsb = 0; + ChannelStatus[ch].prog = 0; + ChannelStatus[ch].is_drum = ISDRUMCHANNEL(ch); + ChannelStatus[ch].vol = 0; + ChannelStatus[ch].exp = 0; + ChannelStatus[ch].pan = NO_PANNING; + ChannelStatus[ch].sus = 0; + ChannelStatus[ch].pitch = 0x2000; + ChannelStatus[ch].wheel = 0; + ChannelStatus[ch].bend_mark = ' '; + ChannelStatus[ch].last_note_on = 0.0; + ChannelStatus[ch].comm = NULL; + } +} + static void display_play_system(int mode) { wmove(dftwin, TIME_LINE, 23); @@ -997,8 +995,8 @@ static void redraw_all(void) { N_ctl_scrinit(); - ctl_total_time(CTL_LAST_STATUS); - ctl_master_volume(CTL_LAST_STATUS); + ctl_total_time(CTL_STATUS_UPDATE); + ctl_master_volume(CTL_STATUS_UPDATE); display_key_helpmsg(); ctl_file_name(NULL); ctl_ncurs_mode_init(); @@ -1017,6 +1015,8 @@ redraw_all(); break; case CTLE_PLAY_START: + init_chan_status(); + ctl_ncurs_mode_init(); ctl_total_time((int)e->v1); break; case CTLE_PLAY_END: @@ -1037,7 +1037,10 @@ ctl_master_volume((int)e->v1); break; case CTLE_PROGRAM: - ctl_program((int)e->v1, (int)e->v2, (char *)e->v3); + ctl_program((int)e->v1, (int)e->v2, (char *)e->v3, (unsigned int)e->v4); + break; + case CTLE_DRUMPART: + ctl_drumpart((int)e->v1, (int)e->v2); break; case CTLE_VOLUME: ctl_volume((int)e->v1, (int)e->v2); @@ -1055,7 +1058,7 @@ ctl_pitch_bend((int)e->v1, (int)e->v2); break; case CTLE_MOD_WHEEL: - ctl_pitch_bend((int)e->v1, e->v2 ? -2 : CTL_LAST_STATUS); + ctl_mod_wheel((int)e->v1, (int)e->v2); break; case CTLE_CHORUS_EFFECT: break; @@ -1085,10 +1088,10 @@ static void ctl_total_time(int tt) { - static int last_tt = CTL_LAST_STATUS; + static int last_tt = CTL_STATUS_UPDATE; int mins, secs; - if(tt == CTL_LAST_STATUS) + if(tt == CTL_STATUS_UPDATE) tt = last_tt; else last_tt = tt; @@ -1107,9 +1110,9 @@ static void ctl_master_volume(int mv) { - static int lastvol = CTL_LAST_STATUS; + static int lastvol = CTL_STATUS_UPDATE; - if(mv == CTL_LAST_STATUS) + if(mv == CTL_STATUS_UPDATE) mv = lastvol; else lastvol = mv; @@ -1147,48 +1150,45 @@ static void ctl_current_time(int secs, int v) { - int mins; - static int last_voices = CTL_STATUS_INIT, last_v = CTL_STATUS_INIT; - static int last_secs = CTL_STATUS_INIT; - - if(secs == CTL_STATUS_INIT) - { - last_voices = last_v = last_secs = CTL_STATUS_INIT; - return; - } + int mins; + static int last_voices = CTL_STATUS_INIT, last_v = CTL_STATUS_INIT; + static int last_secs = CTL_STATUS_INIT; - if(midi_trace.flush_flag) - return; + if(secs == CTL_STATUS_INIT) + { + last_voices = last_v = last_secs = CTL_STATUS_INIT; + return; + } - if(last_secs != secs) - { - last_secs = secs; - mins=secs/60; - secs-=mins*60; - wmove(dftwin, TIME_LINE,5); - wattron(dftwin, A_BOLD); - wprintw(dftwin, "%3d:%02d", mins, secs); - wattroff(dftwin, A_BOLD); - scr_modified_flag = 1; - } + if(last_secs != secs) + { + last_secs = secs; + mins = secs/60; + secs -= mins*60; + wmove(dftwin, TIME_LINE, 5); + wattron(dftwin, A_BOLD); + wprintw(dftwin, "%3d:%02d", mins, secs); + wattroff(dftwin, A_BOLD); + scr_modified_flag = 1; + } - if(last_v != v) - { - last_v = v; - wmove(dftwin, VOICE_LINE,47); - wattron(dftwin, A_BOLD); - wprintw(dftwin, "%3d", v); - wattroff(dftwin, A_BOLD); - scr_modified_flag = 1; - } + if(last_v != v) + { + last_v = v; + wmove(dftwin, VOICE_LINE, 47); + wattron(dftwin, A_BOLD); + wprintw(dftwin, "%3d", v); + wattroff(dftwin, A_BOLD); + scr_modified_flag = 1; + } - if(last_voices != voices) - { - last_voices = voices; - wmove(dftwin, VOICE_LINE, 52); - wprintw(dftwin, "%3d", voices); - scr_modified_flag = 1; - } + if(last_voices != voices) + { + last_voices = voices; + wmove(dftwin, VOICE_LINE, 52); + wprintw(dftwin, "%3d", voices); + scr_modified_flag = 1; + } } static void ctl_note(int status, int ch, int note, int vel) @@ -1281,184 +1281,250 @@ } } -static void ctl_program(int ch, int val, char *comm) +static void ctl_drumpart(int ch, int is_drum) { - int pr; + if(ch >= display_channels) + return; + ChannelStatus[ch].is_drum = is_drum; +} + +static void ctl_program(int ch, int prog, char *comm, unsigned int banks) +{ + int val; + int bank; if(ch >= display_channels) return; - if(comm != NULL) - indicator_set_prog(ch, val, comm); + if(prog != CTL_STATUS_UPDATE) + { + bank = banks & 0xff; + ChannelStatus[ch].prog = prog; + ChannelStatus[ch].bank = bank; + ChannelStatus[ch].bank_lsb = (banks >> 8) & 0xff; + ChannelStatus[ch].bank_msb = (banks >> 16) & 0xff; + ChannelStatus[ch].comm = (comm ? comm : ""); + } else { + prog = ChannelStatus[ch].prog; + bank = ChannelStatus[ch].bank; + } + ChannelStatus[ch].last_note_on = 0.0; /* reset */ - if(!ctl.trace_playing) + if(ctl_ncurs_mode != NCURS_MODE_TRACE) return; - if(channel[ch].special_sample) - pr = val = channel[ch].special_sample; + if(selected_channel == ch) + { + init_trace_window_chan(ch); + return; + } + + if(ChannelStatus[ch].is_drum) + val = bank; else - pr = val + progbase; + val = prog; + if(!IS_CURRENT_MOD_FILE) + val += progbase; - if(ctl_ncurs_mode == NCURS_MODE_TRACE) + wmove(dftwin, NOTE_LINE + ch, COLS - 21); + if(ChannelStatus[ch].is_drum) { - if(ch == selected_channel) - init_trace_window_chan(ch); - else - { - wmove(dftwin, NOTE_LINE+ch, COLS-21); - if(ISDRUMCHANNEL(ch)) - { - wattron(dftwin, A_BOLD); - wprintw(dftwin, " %03d", pr); - wattroff(dftwin, A_BOLD); - } - else - wprintw(dftwin, " %03d", pr); - } + wattron(dftwin, A_BOLD); + wprintw(dftwin, " %03d", val); + wattroff(dftwin, A_BOLD); } - + else + wprintw(dftwin, " %03d", val); scr_modified_flag = 1; } static void ctl_volume(int ch, int vol) { - static int last_vols[MAX_CHANNELS]; - int i; - if(ch >= display_channels) return; - if(vol == CTL_STATUS_INIT) + if(vol != CTL_STATUS_UPDATE) { - for(i = 0; i < MAX_CHANNELS; i++) - last_vols[i] = CTL_STATUS_INIT; - return; + if(ChannelStatus[ch].vol == vol) + return; + ChannelStatus[ch].vol = vol; } + else + vol = ChannelStatus[ch].vol; if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch) return; - if(last_vols[ch] != vol) - { - last_vols[ch] = vol; - wmove(dftwin, NOTE_LINE + ch, COLS - 16); - wprintw(dftwin, "%3d", vol); - scr_modified_flag = 1; - } + wmove(dftwin, NOTE_LINE + ch, COLS - 16); + wprintw(dftwin, "%3d", vol); + scr_modified_flag = 1; } -static void ctl_expression(int ch, int vol) +static void ctl_expression(int ch, int exp) { - static int last_vols[MAX_CHANNELS]; - int i; - if(ch >= display_channels) return; - if(vol == CTL_STATUS_INIT) + if(exp != CTL_STATUS_UPDATE) { - for(i = 0; i < MAX_CHANNELS; i++) - last_vols[i] = CTL_STATUS_INIT; - return; + if(ChannelStatus[ch].exp == exp) + return; + ChannelStatus[ch].exp = exp; } + else + exp = ChannelStatus[ch].exp; if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch) return; - if(last_vols[ch] != vol) - { - last_vols[ch] = vol; - wmove(dftwin, NOTE_LINE + ch, COLS - 12); - wprintw(dftwin, "%3d", vol); - scr_modified_flag = 1; - } + wmove(dftwin, NOTE_LINE + ch, COLS - 12); + wprintw(dftwin, "%3d", exp); + scr_modified_flag = 1; } -static void ctl_panning(int ch, int val) +static void ctl_panning(int ch, int pan) { - if(ch >= display_channels || ctl_ncurs_mode != NCURS_MODE_TRACE || - selected_channel == ch) + if(ch >= display_channels) return; + + if(pan != CTL_STATUS_UPDATE) + { + if(pan == NO_PANNING) + ; + else if(pan < 5) + pan = 0; + else if(pan > 123) + pan = 127; + else if(pan > 60 && pan < 68) + pan = 64; + if(ChannelStatus[ch].pan == pan) + return; + ChannelStatus[ch].pan = pan; + } + else + pan = ChannelStatus[ch].pan; + + if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch) + return; + wmove(dftwin, NOTE_LINE + ch, COLS - 8); - if(val == NO_PANNING) + switch(pan) + { + case NO_PANNING: waddstr(dftwin, " "); - else if(val < 5) + break; + case 0: waddstr(dftwin, " L "); - else if(val > 123) - waddstr(dftwin, " R "); - else if(val > 60 && val < 68) + break; + case 64: waddstr(dftwin, " C "); - else - { - val -= 64; - if(val < 0) + break; + case 127: + waddstr(dftwin, " R "); + break; + default: + pan -= 64; + if(pan < 0) { waddch(dftwin, '-'); - val = -val; + pan = -pan; } else waddch(dftwin, '+'); - wprintw(dftwin, "%02d", val); + wprintw(dftwin, "%02d", pan); + break; } scr_modified_flag = 1; } -static void ctl_sustain(int ch, int val) +static void ctl_sustain(int ch, int sus) { - if(ch >= display_channels || - ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch) + if(ch >= display_channels) + return; + + if(sus != CTL_STATUS_UPDATE) + { + if(ChannelStatus[ch].sus == sus) + return; + ChannelStatus[ch].sus = sus; + } + else + sus = ChannelStatus[ch].sus; + + if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch) return; - wmove(dftwin, NOTE_LINE+ch, COLS - 4); - if(val) + + wmove(dftwin, NOTE_LINE + ch, COLS - 4); + if(sus) waddch(dftwin, 'S'); else waddch(dftwin, ' '); scr_modified_flag = 1; } -static void ctl_pitch_bend(int ch, int val) +static void update_bend_mark(int ch) { - static int lastbends[MAX_CHANNELS]; - int i, restore; + wmove(dftwin, NOTE_LINE + ch, COLS - 2); + waddch(dftwin, ChannelStatus[ch].bend_mark); + scr_modified_flag = 1; +} + +static void ctl_pitch_bend(int ch, int pitch) +{ + int mark; if(ch >= display_channels) return; - if(val == CTL_STATUS_INIT) - { - for(i = 0; i < MAX_CHANNELS; i++) - lastbends[i] = CTL_STATUS_INIT; + ChannelStatus[ch].pitch = pitch; + + if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch) return; - } + + if(ChannelStatus[ch].wheel) + mark = '='; + else if(pitch > 0x2000) + mark = '>'; + else if(pitch < 0x2000) + mark = '<'; + else + mark = ' '; + + if(ChannelStatus[ch].bend_mark == mark) + return; + ChannelStatus[ch].bend_mark = mark; + update_bend_mark(ch); +} + +static void ctl_mod_wheel(int ch, int wheel) +{ + int mark; + + if(ch >= display_channels) + return; + + ChannelStatus[ch].wheel = wheel; if(ctl_ncurs_mode != NCURS_MODE_TRACE || selected_channel == ch) return; - if(val == CTL_LAST_STATUS) - { - restore = 1; - val = lastbends[ch]; - if(!val || (val != '<' && val != '>')) - val = ' '; - } + if(wheel) + mark = '='; else { - restore = 0; - if (val==-2) val = '='; - else if (val>0x2000) val = '>'; - else if (val<0x2000) val = '<'; - else val = ' '; + /* restore pitch bend mark */ + if(ChannelStatus[ch].pitch > 0x2000) + mark = '>'; + else if(ChannelStatus[ch].pitch < 0x2000) + mark = '<'; + else + mark = ' '; } - if(restore || lastbends[ch] != val) - { - if(val != '=') - lastbends[ch] = val; - else lastbends[ch] = ' '; - wmove(dftwin, NOTE_LINE+ch, COLS-2); - waddch(dftwin, val); - scr_modified_flag = 1; - } + if(ChannelStatus[ch].bend_mark == mark) + return; + ChannelStatus[ch].bend_mark = mark; + update_bend_mark(ch); } static void ctl_lyric(int lyricid) @@ -1671,6 +1737,7 @@ ctl_ncurs_mode = NCURS_MODE_MAIN; ctl_ncurs_back = ctl_ncurs_mode; + init_chan_status(); N_ctl_scrinit(); if(ctl.trace_playing) @@ -1741,7 +1808,10 @@ selected_channel -= display_channels + 1; if(selected_channel != -1) + { init_trace_window_chan(selected_channel); + current_indicator_chan = selected_channel; + } N_ctl_refresh(); } @@ -1986,7 +2056,7 @@ if(*text == '+') { ch = atoi(text + 1) - 1; - if(ch >= 0 && ISDRUMCHANNEL(ch)) + if(ch >= 0 && ChannelStatus[ch].is_drum) { *val = ch; rc = RC_TOGGLE_DRUMCHAN; @@ -1995,7 +2065,7 @@ else if(*text == '-') { ch = atoi(text + 1) - 1; - if(ch >= 0 && ISDRUMCHANNEL(ch)) + if(ch >= 0 && ChannelStatus[ch].is_drum) { *val = ch; rc = RC_TOGGLE_DRUMCHAN; @@ -2368,8 +2438,8 @@ ctl.trace_playing = !ctl.trace_playing; if(ctl_open(0, 0)) return RC_QUIT; /* Error */ - ctl_total_time(CTL_LAST_STATUS); - ctl_master_volume(CTL_LAST_STATUS); + ctl_total_time(CTL_STATUS_UPDATE); + ctl_master_volume(CTL_STATUS_UPDATE); ctl_file_name(NULL); display_key_helpmsg(); if(ctl.trace_playing) @@ -2872,15 +2942,14 @@ memset(comment_indicator_buffer, ' ', indicator_width - 1); comment_indicator_buffer[indicator_width - 1] = '\0'; - next_indicator_chan = -1; indicator_last_update = get_current_calender_time(); indicator_mode = INDICATOR_DEFAULT; indicator_msgptr = NULL; for(i = 0; i < MAX_CHANNELS; i++) { - instr_comment[i].last_note_on = 0.0; - instr_comment[i].comm = channel_instrum_name(i); + ChannelStatus[i].last_note_on = 0.0; + ChannelStatus[i].comm = channel_instrum_name(i); } } @@ -2945,12 +3014,9 @@ t = get_current_calender_time(); if(indicator_mode != INDICATOR_DEFAULT) { - int save_chan; if(indicator_last_update + LYRIC_OUT_THRESHOLD > t) return; - save_chan = next_indicator_chan; reset_indicator(); - next_indicator_chan = save_chan; } indicator_last_update = t; @@ -2959,57 +3025,41 @@ if(indicator_msgptr == NULL) { - if(next_indicator_chan >= 0 && - instr_comment[next_indicator_chan].comm != NULL && - *instr_comment[next_indicator_chan].comm) - { - current_indicator_chan = next_indicator_chan; - } - else - { - int prog, first_ch; - - prog = instr_comment[current_indicator_chan].prog; - first_ch = -1; - /* Find next message */ - for(i = 0; i < MAX_CHANNELS; i++) - { - current_indicator_chan++; - if(current_indicator_chan == MAX_CHANNELS) - current_indicator_chan = 0; - - if(first_ch != -1 && - instr_comment[current_indicator_chan].last_note_on > 0) - first_ch = current_indicator_chan; - - if(instr_comment[current_indicator_chan].comm != NULL && - *instr_comment[current_indicator_chan].comm && - instr_comment[current_indicator_chan].prog != prog && - (instr_comment[current_indicator_chan].last_note_on - + CHECK_NOTE_SLEEP_TIME > t || - instr_comment[current_indicator_chan].disp_cnt == 0)) - break; - } + int i, prog, first_ch; - if(i == MAX_CHANNELS) - { - if(first_ch == -1) - first_ch = 0; - current_indicator_chan = first_ch; - } + first_ch = -1; + prog = ChannelStatus[current_indicator_chan].prog; + /* Find next message */ + for(i = 0; i < MAX_CHANNELS; i++, + current_indicator_chan = (current_indicator_chan + 1) % MAX_CHANNELS) + { + if(ChannelStatus[current_indicator_chan].is_drum || + ChannelStatus[current_indicator_chan].comm == NULL || + *ChannelStatus[current_indicator_chan].comm == '\0') + continue; + + if(first_ch == -1 && + ChannelStatus[current_indicator_chan].last_note_on > 0) + first_ch = current_indicator_chan; + if(ChannelStatus[current_indicator_chan].prog != prog && + (ChannelStatus[current_indicator_chan].last_note_on + + CHECK_NOTE_SLEEP_TIME > t)) + break; } - next_indicator_chan = -1; - if(instr_comment[current_indicator_chan].comm == NULL || - *instr_comment[current_indicator_chan].comm == '\0') - return; + if(i == MAX_CHANNELS) + { + if(first_ch == -1) + first_ch = 0; + if(ChannelStatus[first_ch].comm == NULL || + *ChannelStatus[first_ch].comm == '\0') + return; + current_indicator_chan = first_ch; + } - i = instr_comment[current_indicator_chan].prog; - if(!IS_CURRENT_MOD_FILE) - i += progbase; snprintf(current_indicator_message, indicator_width, "%03d:%s ", - i, instr_comment[current_indicator_chan].comm); - instr_comment[current_indicator_chan].disp_cnt++; + ChannelStatus[current_indicator_chan].prog, + ChannelStatus[current_indicator_chan].comm); indicator_msgptr = current_indicator_message; } @@ -3026,31 +3076,17 @@ static void indicator_chan_update(int ch) { - double t; - - t = get_current_calender_time(); - if(next_indicator_chan == -1 && - instr_comment[ch].last_note_on + CHECK_NOTE_SLEEP_TIME < t) - next_indicator_chan = ch; - instr_comment[ch].last_note_on = t; - instr_comment[ch].disp_cnt = 0; - if(instr_comment[ch].comm == NULL) + ChannelStatus[ch].last_note_on = get_current_calender_time(); + if(ChannelStatus[ch].comm == NULL) { - if((instr_comment[ch].comm = default_instrument_name) == NULL) + if((ChannelStatus[ch].comm = default_instrument_name) == NULL) { - if(!ISDRUMCHANNEL(ch)) - instr_comment[ch].comm = ""; + if(ChannelStatus[ch].is_drum) + ChannelStatus[ch].comm = ""; else - instr_comment[ch].comm = ""; + ChannelStatus[ch].comm = ""; } } -} - -static void indicator_set_prog(int ch, int val, char *comm) -{ - instr_comment[ch].comm = comm; - instr_comment[ch].prog = val; - instr_comment[ch].last_note_on = 0.0; } static void display_lyric(char *lyric, int sep) diff -ruN TiMidity++-2.8.2/interface/w32g_c.c TiMidity++-2.9.0/interface/w32g_c.c --- TiMidity++-2.8.2/interface/w32g_c.c Mon Feb 7 07:43:28 2000 +++ TiMidity++-2.9.0/interface/w32g_c.c Sun Feb 27 22:38:08 2000 @@ -38,6 +38,7 @@ #include "output.h" #include "instrum.h" #include "playmidi.h" +#include "readmidi.h" #include "controls.h" #include "miditrace.h" #include "strtab.h" @@ -758,9 +759,7 @@ return; if(!ctl.trace_playing) return; - if(channel[ch].special_sample) - val = channel[ch].special_sample; - else + if(!IS_CURRENT_MOD_FILE) val += progbase; Panel->channel[ch].program = val; diff -ruN TiMidity++-2.8.2/interface/x_sherry.c TiMidity++-2.9.0/interface/x_sherry.c --- TiMidity++-2.8.2/interface/x_sherry.c Mon Feb 7 07:40:51 2000 +++ TiMidity++-2.9.0/interface/x_sherry.c Sat Feb 19 20:44:53 2000 @@ -161,6 +161,9 @@ static int isRealPaletteChanged, isRealScreenChanged; static int updateClipX1, updateClipY1, updateClipX2, updateClipY2; +static int check_range(VirtualScreen *scr, int x1, int y1, int x2, int y2); + + static Window try_create_window(Display *disp, int width, int height, int want_class, int want_depth, Visual **newVisual, diff -ruN TiMidity++-2.8.2/interface/xaw_c.c TiMidity++-2.9.0/interface/xaw_c.c --- TiMidity++-2.8.2/interface/xaw_c.c Mon Feb 7 07:40:21 2000 +++ TiMidity++-2.9.0/interface/xaw_c.c Sat Feb 19 22:34:16 2000 @@ -723,9 +723,7 @@ if(ch >= MAX_XAW_MIDI_CHANNELS) return; if(!ctl.trace_playing) return; - if(channel[ch].special_sample) - val = channel[ch].special_sample; - else + if(!IS_CURRENT_MOD_FILE) val += progbase; sprintf(local_buf, "PP%c%d", ch+'A', val); a_pipe_write(local_buf); diff -ruN TiMidity++-2.8.2/libarc/Makefile.in TiMidity++-2.9.0/libarc/Makefile.in --- TiMidity++-2.8.2/libarc/Makefile.in Mon Feb 7 21:39:18 2000 +++ TiMidity++-2.9.0/libarc/Makefile.in Sun Feb 27 22:50:12 2000 @@ -251,16 +251,10 @@ arc.o: arc.c ../config.h ../timidity/timidity.h ../utils/support.h \ ../timidity/common.h url.h ../utils/mblock.h arc.h \ ../utils/strtab.h zip.h unlzh.h explode.h -arc_dir.o: arc_dir.c ../config.h ../timidity/timidity.h \ - ../utils/support.h arc.h ../utils/memb.h ../utils/mblock.h \ - url.h arc_lzh.o: arc_lzh.c ../config.h ../timidity/timidity.h \ ../utils/support.h arc.h url.h ../utils/mblock.h arc_mime.o: arc_mime.c ../config.h ../timidity/timidity.h \ ../utils/support.h ../utils/mblock.h zip.h arc.h url.h -arc_newsgroup.o: arc_newsgroup.c ../config.h ../timidity/timidity.h \ - ../utils/support.h arc.h ../utils/memb.h ../utils/mblock.h \ - url.h arc_tar.o: arc_tar.c ../config.h ../timidity/timidity.h \ ../utils/support.h ../utils/mblock.h zip.h arc.h url.h arc_zip.o: arc_zip.c ../config.h ../timidity/timidity.h \ diff -ruN TiMidity++-2.8.2/libarc/url.c TiMidity++-2.9.0/libarc/url.c --- TiMidity++-2.8.2/libarc/url.c Mon Feb 7 07:37:15 2000 +++ TiMidity++-2.9.0/libarc/url.c Wed Feb 16 01:59:43 2000 @@ -121,8 +121,10 @@ return 0; url_errno = URLERR_NONE; errno = 0; - if(url->nread >= url->readlimit) + if(url->nread >= url->readlimit) { + url->eof = 1; return 0; + } if(url->nread + n > url->readlimit) n = (long)(url->readlimit - url->nread); n = url->url_read(url, buff, n); @@ -142,8 +144,11 @@ errno = 0; i = url_read(url, buff, n); } while(i == -1 && errno == EINTR); +#if 0 + /* Already done in url_read!! */ if(i > 0) url->nread += i; +#endif return i; } @@ -376,6 +381,7 @@ url->nread = 0; url->readlimit = URL_MAX_READLIMIT; + url->eof = 0; return url; } @@ -432,7 +438,7 @@ int i; fname++; - for(i = 0; i < sizeof(path) && fname[i] && !IS_PATH_SEP(fname[i]); i++) + for(i = 0; i < sizeof(path) - 1 && fname[i] && !IS_PATH_SEP(fname[i]); i++) path[i] = fname[i]; path[i] = '\0'; if((pw = getpwnam(path)) == NULL) @@ -441,9 +447,9 @@ dir = pw->pw_dir; } dirlen = strlen(dir); - strncpy(path, dir, sizeof(path)); + strncpy(path, dir, sizeof(path) - 1); if(sizeof(path) > dirlen) - strncat(path, fname, sizeof(path) - dirlen); + strncat(path, fname, sizeof(path) - dirlen - 1); path[sizeof(path) - 1] = '\0'; return path; } diff -ruN TiMidity++-2.8.2/libarc/url.h TiMidity++-2.9.0/libarc/url.h --- TiMidity++-2.8.2/libarc/url.h Mon Feb 7 07:37:13 2000 +++ TiMidity++-2.9.0/libarc/url.h Wed Feb 16 01:04:17 2000 @@ -61,9 +61,12 @@ unsigned long nread; /* Reset in url_seek, url_rewind, url_set_readlimit */ unsigned long readlimit; + int eof; /* Used in url_nread and others */ } *URL; #define URLm(url, m) (((URL)url)->m) +#define url_eof(url) URLm((url), eof) + /* open URL stream */ extern URL url_open(char *url_string); @@ -89,7 +92,7 @@ /* read a byte */ extern int url_fgetc(URL url); #define url_getc(url) \ - ((url)->nread >= (url)->readlimit ? EOF : \ + ((url)->nread >= (url)->readlimit ? ((url)->eof = 1, EOF) : \ (url)->url_fgetc != NULL ? ((url)->nread++, (url)->url_fgetc(url)) : \ url_fgetc(url)) diff -ruN TiMidity++-2.8.2/libunimod/AUTHORS TiMidity++-2.9.0/libunimod/AUTHORS --- TiMidity++-2.8.2/libunimod/AUTHORS Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/AUTHORS Thu Feb 17 23:22:34 2000 @@ -0,0 +1,124 @@ +Code in this directory was modified by Paolo Bonzini starting +from libmikmod 3.1.8 + +libmikmod was cleaned up, removing code that was needed by libmikmod's +portability (MD_) layer and data that were needed by the player. The player +itself now forms the core of TiMidity++'s mod.c file but is detached from +libunimod which is nothing more a generic module->UNI converter. In addition, +libmikmod's own portable file I/O routines were changed to rely on libarc's +URL objects. + +The code should be compatible enough that new libmikmod loaders should be +plugged in without even touching the code (only mloader.c's final part). +Some might require changing MREADER * to URL (e.g. amf, it). + +libmikmod main authors +---------------------- + +* Jean-Paul Mikkers (MikMak) + wrote MikMod and maintained it until version 3. +* Jake Stine (Air Richter) [email doesn't work anymore...] + made decisive contributions to the code (esp. IT support) and maintained + MikMod version 3 until it was discontinued. He still works on the WinAmp + module plugin, roughly based on MikMod. +* Miodrag Vallat + current libmikmod maintainer (since version 3.0.4), made an audit of the + code resulting in many bugs fixed. + +Previous Unix maintainers +------------------------- + +* Steve McIntyre + maintained MikMod'Unix version 2. +* Peter Amstutz + maintained MikMod'Unix version 3.0. + +Contributors on the Unix side +----------------------------- + +* Arne de Bruijn + wrote the compressed IT sample support. +* Douglas Carmichael + made MikMod work under FreeBSD. +* Chris Conn + wrote the OSS driver. +* Roine Gustaffson + wrote the Digital AudioFile driver. +* Stephan Kanthak + wrote the SGI driver. +* Lutz Vieweg + wrote the AIX and HP-UX drivers. +* Valtteri Vuorikoski + wrote the Sun driver. +* Andy Lo A Foe + wrote the Ultra driver (for the Gravis Ultrasound sound card). +* C Ray C + updated the Ultra driver to work with libmikmod 3. +* ``MenTaLguY'' + autoconfized the Unix libmikmod distribution. +* Claudio Matsuoka + wrote the STX loader and submitted bug fixes. +* Tobias Gloth + created the new I/O interface, made the code MT-safe and submitted bug fixes. +* Kev Vance + wrote the GDM loader. +* Simon Hosie + wrote the piped output driver, and submitted speed optimizations and bugfixes + for the software mixer. + +Contributors on the Windows side +-------------------------------- + +* Brian McKinney + created the DirectSound driver. +* Bjornar Henden + created the Multimedia API windows driver. + +Contributors on the Dos side +---------------------------- + +Their code isn't there anymore, but they contributed to the success of +libmikmod... + +* Jean-Philippe Ajirent wrote the EMS memory routines. +* Peter Breitling ported MikMod to DJGPP. +* Arnout Cosman wrote the PAS driver. +* Mario Koeppen wrote the WSS driver. +* Mike Leibow wrote the GUS driver. +* Jeremy McDonald wrote a fast assembly-language mixer. +* Steffen Rusitschka and Vince Vu wrote the AWE driver. + +Contributors on the Macintosh side +---------------------------------- + +* Anders Bjoerklund + ported libmikmod to the Macintosh. + +Contributors on the OS/2 side +----------------------------- + +* Stefan Tibus + ported libmikmod to OS/2. +* Andrew Zabolotny + improved the existing OS/2 drivers. + +Contributors on the BeOS side +----------------------------- + +* Thomas Neumann + integrated libmikmod into his BeOS APlayer, and contributed many bug fixes. + +Other contributors +------------------ + +* Sebastiaan A. Megens + fixed various bugs (memory leaks, endianness issues, etc). + +* Paul Fisher made decisive contributions and improvements. +* Alexander Kerkhove fixed an ULT panning effect bug. +* ``Kodiak'' helped on the interfaces of libmikmod. +* Sylvain Marchand make MikMod more portable and GCC compilable. + +-- +If your name is missing, don't hesitate to remind me at + diff -ruN TiMidity++-2.8.2/libunimod/Makefile.am TiMidity++-2.9.0/libunimod/Makefile.am --- TiMidity++-2.8.2/libunimod/Makefile.am Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/Makefile.am Thu Feb 17 23:22:34 2000 @@ -0,0 +1,54 @@ +# TiMidity++ -- MIDI to WAVE converter and player +# Copyright (C) 1999,2000 Masanao Izumo +# Copyright (C) 1995 Tuukka Toivonen +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +include $(top_builddir)/common.makefile + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/timidity \ + -I$(top_srcdir)/utils \ + -I$(top_srcdir)/libarc \ + $(EXTRAINCS) + + +noinst_LIBRARIES = libunimod.a + +libunimod_a_SOURCES = \ + load_669.c \ + load_amf.c \ + load_dsm.c \ + load_far.c \ + load_gdm.c \ + load_imf.c \ + load_it.c \ + load_m15.c \ + load_med.c \ + load_mod.c \ + load_mtm.c \ + load_s3m.c \ + load_stm.c \ + load_stx.c \ + load_ult.c \ + load_uni.c \ + load_xm.c \ + mloader.c \ + mlutil.c \ + mmsup.c \ + munitrk.c \ + unimod.h \ + unimod_priv.h diff -ruN TiMidity++-2.8.2/libunimod/Makefile.in TiMidity++-2.9.0/libunimod/Makefile.in --- TiMidity++-2.8.2/libunimod/Makefile.in Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/Makefile.in Sun Feb 27 22:50:29 2000 @@ -0,0 +1,355 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# TiMidity++ -- MIDI to WAVE converter and player +# Copyright (C) 1999,2000 Masanao Izumo +# Copyright (C) 1995 Tuukka Toivonen +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +CC = @CC@ +ELFILES = @ELFILES@ +EMACS = @EMACS@ +ESD_CFLAGS = @ESD_CFLAGS@ +ESD_CONFIG = @ESD_CONFIG@ +ESD_LIBS = @ESD_LIBS@ +EXTRALIBS = @EXTRALIBS@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_CONFIG = @GTK_CONFIG@ +GTK_LIBS = @GTK_LIBS@ +INTERFACE_SRCS = @INTERFACE_SRCS@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +NETSRCS = @NETSRCS@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +SHCFLAGS = @SHCFLAGS@ +SHELL = @SHELL@ +SHLD = @SHLD@ +SYSEXTRAS = @SYSEXTRAS@ +VERSION = @VERSION@ +WISH = @WISH@ +dynamic_targets = @dynamic_targets@ +lispdir = @lispdir@ +program_transform_name = @program_transform_name@ +so = @so@ +tcltk_dep = @tcltk_dep@ +timidity_LDFLAGS = @timidity_LDFLAGS@ + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/timidity -I$(top_srcdir)/utils -I$(top_srcdir)/libarc $(EXTRAINCS) + + +noinst_LIBRARIES = libunimod.a + +libunimod_a_SOURCES = load_669.c load_amf.c load_dsm.c load_far.c load_gdm.c load_imf.c load_it.c load_m15.c load_med.c load_mod.c load_mtm.c load_s3m.c load_stm.c load_stx.c load_ult.c load_uni.c load_xm.c mloader.c mlutil.c mmsup.c munitrk.c unimod.h unimod_priv.h + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h ../interface.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +libunimod_a_LIBADD = +libunimod_a_OBJECTS = load_669.o load_amf.o load_dsm.o load_far.o \ +load_gdm.o load_imf.o load_it.o load_m15.o load_med.o load_mod.o \ +load_mtm.o load_s3m.o load_stm.o load_stx.o load_ult.o load_uni.o \ +load_xm.o mloader.o mlutil.o mmsup.o munitrk.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = AUTHORS Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +SOURCES = $(libunimod_a_SOURCES) +OBJECTS = $(libunimod_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps libunimod/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libunimod.a: $(libunimod_a_OBJECTS) $(libunimod_a_DEPENDENCIES) + -rm -f libunimod.a + $(AR) cru libunimod.a $(libunimod_a_OBJECTS) $(libunimod_a_LIBADD) + $(RANLIB) libunimod.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = libunimod + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +load_669.o: load_669.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_amf.o: load_amf.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_dsm.o: load_dsm.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_far.o: load_far.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_gdm.o: load_gdm.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_imf.o: load_imf.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_it.o: load_it.c ../config.h unimod_priv.h unimod.h ../libarc/url.h +load_m15.o: load_m15.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_med.o: load_med.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_mod.o: load_mod.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_mtm.o: load_mtm.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_s3m.o: load_s3m.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_stm.o: load_stm.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_stx.o: load_stx.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_ult.o: load_ult.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_uni.o: load_uni.c ../config.h unimod_priv.h unimod.h \ + ../libarc/url.h +load_xm.o: load_xm.c ../config.h unimod_priv.h unimod.h ../libarc/url.h +mloader.o: mloader.c ../config.h unimod_priv.h unimod.h ../libarc/url.h +mlutil.o: mlutil.c ../config.h unimod_priv.h unimod.h ../libarc/url.h +mmsup.o: mmsup.c unimod_priv.h unimod.h ../libarc/url.h +munitrk.o: munitrk.c ../config.h unimod_priv.h unimod.h ../libarc/url.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +include $(top_builddir)/common.makefile + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff -ruN TiMidity++-2.8.2/libunimod/load_669.c TiMidity++-2.9.0/libunimod/load_669.c --- TiMidity++-2.8.2/libunimod/load_669.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_669.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,414 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_669.c,v 1.30 1999/10/25 16:31:41 miod Exp $ + + Composer 669 module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +/* header */ +typedef struct S69HEADER + { + UBYTE marker[2]; + CHAR message[108]; + UBYTE nos; + UBYTE nop; + UBYTE looporder; + UBYTE orders[0x80]; + UBYTE tempos[0x80]; + UBYTE breaks[0x80]; + } +S69HEADER; + +/* sample information */ +typedef struct S69SAMPLE + { + CHAR filename[13]; + SLONG length; + SLONG loopbeg; + SLONG loopend; + } +S69SAMPLE; + +/* encoded note */ +typedef struct S69NOTE + { + UBYTE a, b, c; + } +S69NOTE; + +/*========== Loader variables */ + +/* current pattern */ +static S69NOTE *s69pat = NULL; +/* Module header */ +static S69HEADER *mh = NULL; + +/* file type identification */ +static CHAR *S69_Version[] = +{ + "Composer 669", + "Extended 669" +}; + +/*========== Loader code */ + +BOOL +S69_Test (void) +{ + UBYTE buf[0x80]; + + if (!_mm_read_UBYTES (buf, 2, modreader)) + return 0; + /* look for id */ + if (!memcmp (buf, "if", 2) || !memcmp (buf, "JN", 2)) + { + int i; + + /* skip song message */ + _mm_fseek (modreader, 108, SEEK_CUR); + /* sanity checks */ + if (_mm_read_UBYTE (modreader) > 64) + return 0; + if (_mm_read_UBYTE (modreader) > 128) + return 0; + if (_mm_read_UBYTE (modreader) > 127) + return 0; + /* check order table */ + if (!_mm_read_UBYTES (buf, 0x80, modreader)) + return 0; + for (i = 0; i < 0x80; i++) + if ((buf[i] >= 0x80) && (buf[i] != 0xff)) + return 0; + /* check tempos table */ + if (!_mm_read_UBYTES (buf, 0x80, modreader)) + return 0; + for (i = 0; i < 0x80; i++) + if ((!buf[i]) || (buf[i] > 32)) + return 0; + /* check pattern length table */ + if (!_mm_read_UBYTES (buf, 0x80, modreader)) + return 0; + for (i = 0; i < 0x80; i++) + if (buf[i] > 0x3f) + return 0; + } + else + return 0; + + return 1; +} + +BOOL +S69_Init (void) +{ + if (!(s69pat = (S69NOTE *) _mm_malloc (64 * 8 * sizeof (S69NOTE)))) + return 0; + if (!(mh = (S69HEADER *) _mm_malloc (sizeof (S69HEADER)))) + return 0; + + return 1; +} + +void +S69_Cleanup (void) +{ + _mm_free (s69pat); + _mm_free (mh); +} + +static BOOL +S69_LoadPatterns (void) +{ + int track, row, channel; + UBYTE note, inst, vol, effect, lastfx, lastval; + S69NOTE *cur; + int tracks = 0; + + if (!AllocPatterns ()) + return 0; + if (!AllocTracks ()) + return 0; + + for (track = 0; track < of.numpat; track++) + { + /* set pattern break locations */ + of.pattrows[track] = mh->breaks[track] + 1; + + /* load the 669 pattern */ + cur = s69pat; + for (row = 0; row < 64; row++) + { + for (channel = 0; channel < 8; channel++, cur++) + { + cur->a = _mm_read_UBYTE (modreader); + cur->b = _mm_read_UBYTE (modreader); + cur->c = _mm_read_UBYTE (modreader); + } + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + /* translate the pattern */ + for (channel = 0; channel < 8; channel++) + { + UniReset (); + /* set pattern tempo */ + UniPTEffect (0xf, 78); + UniPTEffect (0xf, mh->tempos[track]); + + lastfx = 0xff, lastval = 0; + + for (row = 0; row <= mh->breaks[track]; row++) + { + int a, b, c; + + /* fetch the encoded note */ + a = s69pat[(row * 8) + channel].a; + b = s69pat[(row * 8) + channel].b; + c = s69pat[(row * 8) + channel].c; + + /* decode it */ + note = a >> 2; + inst = ((a & 0x3) << 4) | ((b & 0xf0) >> 4); + vol = b & 0xf; + + if (a < 0xff) + { + if (a < 0xfe) + { + UniInstrument (inst); + UniNote (note + 2 * OCTAVE); + lastfx = 0xff; /* reset background effect memory */ + } + UniPTEffect (0xc, vol << 2); + } + + if ((c != 0xff) || (lastfx != 0xff)) + { + if (c == 0xff) + c = lastfx, effect = lastval; + else + effect = c & 0xf; + + switch (c >> 4) + { + case 0: /* porta up */ + UniPTEffect (0x1, effect); + lastfx = c, lastval = effect; + break; + case 1: /* porta down */ + UniPTEffect (0x2, effect); + lastfx = c, lastval = effect; + break; + case 2: /* porta to note */ + UniPTEffect (0x3, effect); + lastfx = c, lastval = effect; + break; + case 3: /* frequency adjust */ + /* DMP converts this effect to S3M FF1. Why not ? */ + UniEffect (UNI_S3MEFFECTF, 0xf0 | effect); + break; + case 4: /* vibrato */ + UniPTEffect (0x4, effect); + lastfx = c, lastval = effect; + break; + case 5: /* set speed */ + if (effect) + UniPTEffect (0xf, effect); + else if (mh->marker[0] != 0x69) + { +#ifdef MIKMOD_DEBUG + fprintf (stderr, "\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n", + track, row, channel); +#endif + } + break; + } + } + UniNewline (); + } + if (!(of.tracks[tracks++] = UniDup ())) + return 0; + } + } + + return 1; +} + +BOOL +S69_Load (BOOL curious) +{ + int i; + SAMPLE *current; + S69SAMPLE sample; + + /* module header */ + _mm_read_UBYTES (mh->marker, 2, modreader); + _mm_read_UBYTES (mh->message, 108, modreader); + mh->nos = _mm_read_UBYTE (modreader); + mh->nop = _mm_read_UBYTE (modreader); + mh->looporder = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->orders, 0x80, modreader); + for (i = 0; i < 0x80; i++) + if ((mh->orders[i] >= 0x80) && (mh->orders[i] != 0xff)) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 1; + } + _mm_read_UBYTES (mh->tempos, 0x80, modreader); + for (i = 0; i < 0x80; i++) + if ((!mh->tempos[i]) || (mh->tempos[i] > 32)) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 1; + } + _mm_read_UBYTES (mh->breaks, 0x80, modreader); + for (i = 0; i < 0x80; i++) + if (mh->breaks[i] > 0x3f) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 1; + } + + /* set module variables */ + of.initspeed = 4; + of.inittempo = 78; + of.songname = DupStr (mh->message, 36, 1); + of.modtype = strdup (S69_Version[memcmp (mh->marker, "JN", 2) == 0]); + of.numchn = 8; + of.numpat = mh->nop; + of.numins = of.numsmp = mh->nos; + of.numtrk = of.numchn * of.numpat; + of.flags = UF_XMPERIODS | UF_LINEAR; + + for (i = 35; (i >= 0) && (mh->message[i] == ' '); i--) + mh->message[i] = 0; + for (i = 36 + 35; (i >= 36 + 0) && (mh->message[i] == ' '); i--) + mh->message[i] = 0; + for (i = 72 + 35; (i >= 72 + 0) && (mh->message[i] == ' '); i--) + mh->message[i] = 0; + if ((mh->message[0]) || (mh->message[36]) || (mh->message[72])) + if ((of.comment = (CHAR *) _mm_malloc (3 * (36 + 1) + 1))) + { + strncpy (of.comment, mh->message, 36); + strcat (of.comment, "\r"); + if (mh->message[36]) + strncat (of.comment, mh->message + 36, 36); + strcat (of.comment, "\r"); + if (mh->message[72]) + strncat (of.comment, mh->message + 72, 36); + strcat (of.comment, "\r"); + of.comment[3 * (36 + 1)] = 0; + } + + if (!AllocPositions (0x80)) + return 0; + for (i = 0; i < 0x80; i++) + { + if (mh->orders[i] >= mh->nop) + break; + of.positions[i] = mh->orders[i]; + } + of.numpos = i; + of.reppos = mh->looporder < of.numpos ? mh->looporder : 0; + + if (!AllocSamples ()) + return 0; + current = of.samples; + + for (i = 0; i < of.numins; i++) + { + /* sample information */ + _mm_read_UBYTES ((UBYTE *) sample.filename, 13, modreader); + sample.length = _mm_read_I_SLONG (modreader); + sample.loopbeg = _mm_read_I_SLONG (modreader); + sample.loopend = _mm_read_I_SLONG (modreader); + if (sample.loopend == 0xfffff) + sample.loopend = 0; + + if ((sample.length < 0) || (sample.loopbeg < -1) || (sample.loopend < -1)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + current->samplename = DupStr (sample.filename, 13, 1); + current->seekpos = 0; + current->speed = 0; + current->length = sample.length; + current->loopstart = sample.loopbeg; + current->loopend = (sample.loopend < sample.length) ? sample.loopend : sample.length; + current->flags = (sample.loopbeg < sample.loopend) ? SF_LOOP : 0; + current->volume = 64; + + current++; + } + + if (!S69_LoadPatterns ()) + return 0; + + return 1; +} + +CHAR * +S69_LoadTitle (void) +{ + CHAR s[36]; + + _mm_fseek (modreader, 2, SEEK_SET); + if (!_mm_read_UBYTES (s, 36, modreader)) + return NULL; + + return (DupStr (s, 36, 1)); +} + +/*========== Loader information */ + +MLOADER load_669 = +{ + NULL, + "669", + "669 (Composer 669, Unis 669)", + S69_Init, + S69_Test, + S69_Load, + S69_Cleanup, + S69_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_amf.c TiMidity++-2.9.0/libunimod/load_amf.c --- TiMidity++-2.8.2/libunimod/load_amf.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_amf.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,613 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_amf.c,v 1.28 1999/10/25 16:31:41 miod Exp $ + + DMP Advanced Module Format loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +typedef struct AMFHEADER + { + UBYTE id[3]; /* AMF file marker */ + UBYTE version; /* upper major, lower nibble minor version number */ + CHAR songname[32]; /* ASCIIZ songname */ + UBYTE numsamples; /* number of samples saved */ + UBYTE numorders; + UWORD numtracks; /* number of tracks saved */ + UBYTE numchannels; /* number of channels used */ + SBYTE panpos[32]; /* voice pan positions */ + UBYTE songbpm; + UBYTE songspd; + } +AMFHEADER; + +typedef struct AMFSAMPLE + { + UBYTE type; + CHAR samplename[32]; + CHAR filename[13]; + ULONG offset; + ULONG length; + UWORD c2spd; + UBYTE volume; + ULONG reppos; + ULONG repend; + } +AMFSAMPLE; + +typedef struct AMFNOTE + { + UBYTE note, instr, volume, fxcnt; + UBYTE effect[3]; + SBYTE parameter[3]; + } +AMFNOTE; + +/*========== Loader variables */ + +static AMFHEADER *mh = NULL; +#define AMFTEXTLEN 22 +static CHAR AMF_Version[AMFTEXTLEN + 1] = "DSMI Module Format 0.0"; +static AMFNOTE *track = NULL; + +/*========== Loader code */ + +BOOL +AMF_Test (void) +{ + UBYTE id[3], ver; + + if (!_mm_read_UBYTES (id, 3, modreader)) + return 0; + if (memcmp (id, "AMF", 3)) + return 0; + + ver = _mm_read_UBYTE (modreader); + if ((ver >= 10) && (ver <= 14)) + return 1; + return 0; +} + +BOOL +AMF_Init (void) +{ + if (!(mh = (AMFHEADER *) _mm_malloc (sizeof (AMFHEADER)))) + return 0; + if (!(track = (AMFNOTE *) _mm_calloc (64, sizeof (AMFNOTE)))) + return 0; + + return 1; +} + +void +AMF_Cleanup (void) +{ + _mm_free (mh); + _mm_free (track); +} + +static BOOL +AMF_UnpackTrack (URL modreader) +{ + ULONG tracksize; + UBYTE row, cmd; + SBYTE arg; + + /* empty track */ + memset (track, 0, 64 * sizeof (AMFNOTE)); + + /* read packed track */ + if (modreader) + { + tracksize = _mm_read_I_UWORD (modreader); + tracksize += ((ULONG) _mm_read_UBYTE (modreader)) << 16; + if (tracksize) + while (tracksize--) + { + row = _mm_read_UBYTE (modreader); + cmd = _mm_read_UBYTE (modreader); + arg = _mm_read_SBYTE (modreader); + /* unexpected end of track */ + if (!tracksize) + { + if ((row == 0xff) && (cmd == 0xff) && (arg == -1)) + break; + /* the last triplet should be FF FF FF, but this is not + always the case... maybe a bug in m2amf ? + else + return 0; + */ + + } + /* invalid row (probably unexpected end of row) */ + if (row >= 64) + return 0; + if (cmd < 0x7f) + { + /* note, vol */ + track[row].note = cmd; + track[row].volume = (UBYTE) arg + 1; + } + else if (cmd == 0x7f) + { + /* duplicate row */ + if ((arg < 0) && (row + arg >= 0)) + { + memcpy (track + row, track + (row + arg), sizeof (AMFNOTE)); + } + } + else if (cmd == 0x80) + { + /* instr */ + track[row].instr = arg + 1; + } + else if (cmd == 0x83) + { + /* volume without note */ + track[row].volume = (UBYTE) arg + 1; + } + else if (track[row].fxcnt < 3) + { + /* effect, param */ + if (cmd > 0x97) + return 0; + track[row].effect[track[row].fxcnt] = cmd & 0x7f; + track[row].parameter[track[row].fxcnt] = arg; + track[row].fxcnt++; + } + else + return 0; + } + } + return 1; +} + +static UBYTE * +AMF_ConvertTrack (void) +{ + int row, fx4memory = 0; + + /* convert track */ + UniReset (); + for (row = 0; row < 64; row++) + { + if (track[row].instr) + UniInstrument (track[row].instr - 1); + if (track[row].note > OCTAVE) + UniNote (track[row].note - OCTAVE); + + /* AMF effects */ + while (track[row].fxcnt--) + { + SBYTE inf = track[row].parameter[track[row].fxcnt]; + + switch (track[row].effect[track[row].fxcnt]) + { + case 1: /* Set speed */ + UniEffect (UNI_S3MEFFECTA, inf); + break; + case 2: /* Volume slide */ + if (inf) + { + UniWriteByte (UNI_S3MEFFECTD); + if (inf >= 0) + UniWriteByte ((inf & 0xf) << 4); + else + UniWriteByte ((-inf) & 0xf); + } + break; + /* effect 3, set channel volume, done in UnpackTrack */ + case 4: /* Porta up/down */ + if (inf) + { + if (inf > 0) + { + UniEffect (UNI_S3MEFFECTE, inf); + fx4memory = UNI_S3MEFFECTE; + } + else + { + UniEffect (UNI_S3MEFFECTF, -inf); + fx4memory = UNI_S3MEFFECTF; + } + } + else if (fx4memory) + UniEffect (fx4memory, 0); + break; + /* effect 5, "Porta abs", not supported */ + case 6: /* Porta to note */ + UniEffect (UNI_ITEFFECTG, inf); + break; + case 7: /* Tremor */ + UniEffect (UNI_S3MEFFECTI, inf); + break; + case 8: /* Arpeggio */ + UniPTEffect (0x0, inf); + break; + case 9: /* Vibrato */ + UniPTEffect (0x4, inf); + break; + case 0xa: /* Porta + Volume slide */ + UniPTEffect (0x3, 0); + if (inf) + { + UniWriteByte (UNI_S3MEFFECTD); + if (inf >= 0) + UniWriteByte ((inf & 0xf) << 4); + else + UniWriteByte ((-inf) & 0xf); + } + break; + case 0xb: /* Vibrato + Volume slide */ + UniPTEffect (0x4, 0); + if (inf) + { + UniWriteByte (UNI_S3MEFFECTD); + if (inf >= 0) + UniWriteByte ((inf & 0xf) << 4); + else + UniWriteByte ((-inf) & 0xf); + } + break; + case 0xc: /* Pattern break (in hex) */ + UniPTEffect (0xd, inf); + break; + case 0xd: /* Pattern jump */ + UniPTEffect (0xb, inf); + break; + /* effect 0xe, "Sync", not supported */ + case 0xf: /* Retrig */ + UniEffect (UNI_S3MEFFECTQ, inf & 0xf); + break; + case 0x10: /* Sample offset */ + UniPTEffect (0x9, inf); + break; + case 0x11: /* Fine volume slide */ + if (inf) + { + UniWriteByte (UNI_S3MEFFECTD); + if (inf >= 0) + UniWriteByte ((inf & 0xf) << 4 | 0xf); + else + UniWriteByte (0xf0 | ((-inf) & 0xf)); + } + break; + case 0x12: /* Fine portamento */ + if (inf) + { + if (inf > 0) + { + UniEffect (UNI_S3MEFFECTE, 0xf0 | (inf & 0xf)); + fx4memory = UNI_S3MEFFECTE; + } + else + { + UniEffect (UNI_S3MEFFECTF, 0xf0 | ((-inf) & 0xf)); + fx4memory = UNI_S3MEFFECTF; + } + } + else if (fx4memory) + UniEffect (fx4memory, 0); + break; + case 0x13: /* Delay note */ + UniPTEffect (0xe, 0xd0 | (inf & 0xf)); + break; + case 0x14: /* Note cut */ + UniPTEffect (0xc, 0); + track[row].volume = 0; + break; + case 0x15: /* Set tempo */ + UniEffect (UNI_S3MEFFECTT, inf); + break; + case 0x16: /* Extra fine portamento */ + if (inf) + { + if (inf > 0) + { + UniEffect (UNI_S3MEFFECTE, 0xe0 | ((inf >> 2) & 0xf)); + fx4memory = UNI_S3MEFFECTE; + } + else + { + UniEffect (UNI_S3MEFFECTF, 0xe0 | (((-inf) >> 2) & 0xf)); + fx4memory = UNI_S3MEFFECTF; + } + } + else if (fx4memory) + UniEffect (fx4memory, 0); + break; + case 0x17: /* Panning */ + if (inf > 64) + UniEffect (UNI_ITEFFECTS0, 0x91); /* surround */ + else + UniPTEffect (0x8, (inf == 64) ? 255 : (inf + 64) << 1); + break; + } + + } + if (track[row].volume) + UniVolEffect (VOL_VOLUME, track[row].volume - 1); + UniNewline (); + } + return UniDup (); +} + +BOOL +AMF_Load (BOOL curious) +{ + int t, u, realtrackcnt, realsmpcnt; + AMFSAMPLE s; + SAMPLE *q; + UWORD *track_remap; + ULONG samplepos; + int channel_remap[16]; + + /* try to read module header */ + _mm_read_UBYTES (mh->id, 3, modreader); + mh->version = _mm_read_UBYTE (modreader); + _mm_read_string (mh->songname, 32, modreader); + mh->numsamples = _mm_read_UBYTE (modreader); + mh->numorders = _mm_read_UBYTE (modreader); + mh->numtracks = _mm_read_I_UWORD (modreader); + mh->numchannels = _mm_read_UBYTE (modreader); + if ((!mh->numchannels) || (mh->numchannels > (mh->version >= 12 ? 32 : 16))) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + + if (mh->version >= 11) + { + memset (mh->panpos, 0, 32); + _mm_read_SBYTES (mh->panpos, (mh->version >= 13) ? 32 : 16, modreader); + } + else + _mm_read_UBYTES (channel_remap, 16, modreader); + + if (mh->version >= 13) + { + mh->songbpm = _mm_read_UBYTE (modreader); + if (mh->songbpm < 32) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + mh->songspd = _mm_read_UBYTE (modreader); + if (mh->songspd > 32) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + } + else + { + mh->songbpm = 125; + mh->songspd = 6; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.initspeed = mh->songspd; + of.inittempo = mh->songbpm; + AMF_Version[AMFTEXTLEN - 3] = '0' + (mh->version / 10); + AMF_Version[AMFTEXTLEN - 1] = '0' + (mh->version % 10); + of.modtype = strdup (AMF_Version); + of.numchn = mh->numchannels; + of.numtrk = mh->numorders * mh->numchannels; + if (mh->numtracks > of.numtrk) + of.numtrk = mh->numtracks; + of.songname = DupStr (mh->songname, 32, 1); + of.numpos = mh->numorders; + of.numpat = mh->numorders; + of.reppos = 0; + of.flags |= UF_S3MSLIDES; + for (t = 0; t < 32; t++) + { + if (mh->panpos[t] > 64) + of.panning[t] = PAN_SURROUND; + else if (mh->panpos[t] == 64) + of.panning[t] = 255; + else + of.panning[t] = (mh->panpos[t] + 64) << 1; + } + of.numins = of.numsmp = mh->numsamples; + + if (!AllocPositions (of.numpos)) + return 0; + for (t = 0; t < of.numpos; t++) + of.positions[t] = t; + + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + /* read AMF order table */ + for (t = 0; t < of.numpat; t++) + { + if (mh->version >= 14) + /* track size */ + of.pattrows[t] = _mm_read_I_UWORD (modreader); + if (mh->version >= 10) + _mm_read_I_UWORDS (of.patterns + (t * of.numchn), of.numchn, modreader); + else + for (u = 0; u < of.numchn; u++) + of.patterns[t * of.numchn + channel_remap[u]] = _mm_read_I_UWORD (modreader); + } + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* read sample information */ + if (!AllocSamples ()) + return 0; + q = of.samples; + for (t = 0; t < of.numins; t++) + { + /* try to read sample info */ + s.type = _mm_read_UBYTE (modreader); + _mm_read_string (s.samplename, 32, modreader); + _mm_read_string (s.filename, 13, modreader); + s.offset = _mm_read_I_ULONG (modreader); + s.length = _mm_read_I_ULONG (modreader); + s.c2spd = _mm_read_I_UWORD (modreader); + if (s.c2spd == 8368) + s.c2spd = 8363; + s.volume = _mm_read_UBYTE (modreader); + if (mh->version >= 11) + { + s.reppos = _mm_read_I_ULONG (modreader); + s.repend = _mm_read_I_ULONG (modreader); + } + else + { + s.reppos = _mm_read_I_UWORD (modreader); + s.repend = s.length; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr (s.samplename, 32, 1); + q->speed = s.c2spd; + q->volume = s.volume; + if (s.type) + { + q->seekpos = s.offset; + q->length = s.length; + q->loopstart = s.reppos; + q->loopend = s.repend; + if ((s.repend - s.reppos) > 2) + q->flags |= SF_LOOP; + } + q++; + } + + /* read track table */ + if (!(track_remap = _mm_calloc (mh->numtracks + 1, sizeof (UWORD)))) + return 0; + _mm_read_I_UWORDS (track_remap + 1, mh->numtracks, modreader); + if (_mm_eof (modreader)) + { + free (track_remap); + _mm_errno = MMERR_LOADING_TRACK; + return 0; + } + + for (realtrackcnt = t = 0; t <= mh->numtracks; t++) + if (realtrackcnt < track_remap[t]) + realtrackcnt = track_remap[t]; + for (t = 0; t < of.numpat * of.numchn; t++) + of.patterns[t] = (of.patterns[t] <= mh->numtracks) ? + track_remap[of.patterns[t]] - 1 : realtrackcnt; + + free (track_remap); + + /* unpack tracks */ + for (t = 0; t < realtrackcnt; t++) + { + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_TRACK; + return 0; + } + if (!AMF_UnpackTrack (modreader)) + { + _mm_errno = MMERR_LOADING_TRACK; + return 0; + } + if (!(of.tracks[t] = AMF_ConvertTrack ())) + return 0; + } + /* add en extra void track */ + UniReset (); + for (t = 0; t < 64; t++) + UniNewline (); + of.tracks[realtrackcnt++] = UniDup (); + for (t = realtrackcnt; t < of.numtrk; t++) + of.tracks[t] = NULL; + + /* compute sample offsets */ + samplepos = _mm_ftell (modreader); + for (realsmpcnt = t = 0; t < of.numsmp; t++) + if (realsmpcnt < of.samples[t].seekpos) + realsmpcnt = of.samples[t].seekpos; + for (t = 1; t <= realsmpcnt; t++) + { + q = of.samples; + while (q->seekpos != t) + q++; + q->seekpos = samplepos; + samplepos += q->length; + } + + return 1; +} + +CHAR * +AMF_LoadTitle (void) +{ + CHAR s[32]; + + _mm_fseek (modreader, 4, SEEK_SET); + if (!_mm_read_UBYTES (s, 32, modreader)) + return NULL; + + return (DupStr (s, 32, 1)); +} + +/*========== Loader information */ + +MLOADER load_amf = +{ + NULL, + "AMF", + "AMF (DSMI Advanced Module Format)", + AMF_Init, + AMF_Test, + AMF_Load, + AMF_Cleanup, + AMF_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_dsm.c TiMidity++-2.9.0/libunimod/load_dsm.c --- TiMidity++-2.8.2/libunimod/load_dsm.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_dsm.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,404 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_dsm.c,v 1.28 1999/10/25 16:31:41 miod Exp $ + + DSIK internal format (DSM) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +#define DSM_MAXCHAN (16) +#define DSM_MAXORDERS (128) + +typedef struct DSMSONG + { + CHAR songname[28]; + UWORD version; + UWORD flags; + ULONG reserved2; + UWORD numord; + UWORD numsmp; + UWORD numpat; + UWORD numtrk; + UBYTE globalvol; + UBYTE mastervol; + UBYTE speed; + UBYTE bpm; + UBYTE panpos[DSM_MAXCHAN]; + UBYTE orders[DSM_MAXORDERS]; + } +DSMSONG; + +typedef struct DSMINST + { + CHAR filename[13]; + UWORD flags; + UBYTE volume; + ULONG length; + ULONG loopstart; + ULONG loopend; + ULONG reserved1; + UWORD c2spd; + UWORD period; + CHAR samplename[28]; + } +DSMINST; + +typedef struct DSMNOTE + { + UBYTE note, ins, vol, cmd, inf; + } +DSMNOTE; + +#define DSM_SURROUND (0xa4) + +/*========== Loader variables */ + +static CHAR *SONGID = "SONG"; +static CHAR *INSTID = "INST"; +static CHAR *PATTID = "PATT"; + +static UBYTE blockid[4]; +static ULONG blockln; +static ULONG blocklp; +static DSMSONG *mh = NULL; +static DSMNOTE *dsmbuf = NULL; + +static CHAR DSM_Version[] = "DSIK DSM-format"; + +static unsigned char DSMSIG[4 + 4] = +{'R', 'I', 'F', 'F', 'D', 'S', 'M', 'F'}; + +/*========== Loader code */ + +BOOL +DSM_Test (void) +{ + UBYTE id[12]; + + if (!_mm_read_UBYTES (id, 12, modreader)) + return 0; + if (!memcmp (id, DSMSIG, 4) && !memcmp (id + 8, DSMSIG + 4, 4)) + return 1; + + return 0; +} + +BOOL +DSM_Init (void) +{ + if (!(dsmbuf = (DSMNOTE *) _mm_malloc (DSM_MAXCHAN * 64 * sizeof (DSMNOTE)))) + return 0; + if (!(mh = (DSMSONG *) _mm_calloc (1, sizeof (DSMSONG)))) + return 0; + return 1; +} + +void +DSM_Cleanup (void) +{ + _mm_free (dsmbuf); + _mm_free (mh); +} + +static BOOL +GetBlockHeader (void) +{ + /* make sure we're at the right position for reading the + next riff block, no matter how many bytes read */ + _mm_fseek (modreader, blocklp + blockln, SEEK_SET); + + while (1) + { + _mm_read_UBYTES (blockid, 4, modreader); + blockln = _mm_read_I_ULONG (modreader); + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if (memcmp (blockid, SONGID, 4) && memcmp (blockid, INSTID, 4) && + memcmp (blockid, PATTID, 4)) + { +#ifdef MIKMOD_DEBUG + fprintf (stderr, "\rDSM: Skipping unknown block type %4.4s\n", blockid); +#endif + _mm_fseek (modreader, blockln, SEEK_CUR); + } + else + break; + } + + blocklp = _mm_ftell (modreader); + + return 1; +} + +static BOOL +DSM_ReadPattern (void) +{ + int flag, row = 0; + SWORD length; + DSMNOTE *n; + + /* clear pattern data */ + memset (dsmbuf, 255, DSM_MAXCHAN * 64 * sizeof (DSMNOTE)); + length = _mm_read_I_SWORD (modreader); + + while (row < 64) + { + flag = _mm_read_UBYTE (modreader); + if ((_mm_eof (modreader)) || (--length < 0)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if (flag) + { + n = &dsmbuf[((flag & 0xf) * 64) + row]; + if (flag & 0x80) + n->note = _mm_read_UBYTE (modreader); + if (flag & 0x40) + n->ins = _mm_read_UBYTE (modreader); + if (flag & 0x20) + n->vol = _mm_read_UBYTE (modreader); + if (flag & 0x10) + { + n->cmd = _mm_read_UBYTE (modreader); + n->inf = _mm_read_UBYTE (modreader); + } + } + else + row++; + } + + return 1; +} + +static UBYTE * +DSM_ConvertTrack (DSMNOTE * tr) +{ + int t; + UBYTE note, ins, vol, cmd, inf; + + UniReset (); + for (t = 0; t < 64; t++) + { + note = tr[t].note; + ins = tr[t].ins; + vol = tr[t].vol; + cmd = tr[t].cmd; + inf = tr[t].inf; + + if (ins != 0 && ins != 255) + UniInstrument (ins - 1); + if (note != 255) + UniNote (note - 1); /* normal note */ + if (vol < 65) + UniPTEffect (0xc, vol); + + if (cmd != 255) + { + if (cmd == 0x8) + { + if (inf == DSM_SURROUND) + UniEffect (UNI_ITEFFECTS0, 0x91); + else if (inf <= 0x80) + { + inf = (inf < 0x80) ? inf << 1 : 255; + UniPTEffect (cmd, inf); + } + } + else if (cmd == 0xb) + { + if (inf <= 0x7f) + UniPTEffect (cmd, inf); + } + else + { + /* Convert pattern jump from Dec to Hex */ + if (cmd == 0xd) + inf = (((inf & 0xf0) >> 4) * 10) + (inf & 0xf); + UniPTEffect (cmd, inf); + } + } + UniNewline (); + } + return UniDup (); +} + +BOOL +DSM_Load (BOOL curious) +{ + int t; + DSMINST s; + SAMPLE *q; + int cursmp = 0, curpat = 0, track = 0; + + blocklp = 0; + blockln = 12; + + if (!GetBlockHeader ()) + return 0; + if (memcmp (blockid, SONGID, 4)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + _mm_read_UBYTES (mh->songname, 28, modreader); + mh->version = _mm_read_I_UWORD (modreader); + mh->flags = _mm_read_I_UWORD (modreader); + mh->reserved2 = _mm_read_I_ULONG (modreader); + mh->numord = _mm_read_I_UWORD (modreader); + mh->numsmp = _mm_read_I_UWORD (modreader); + mh->numpat = _mm_read_I_UWORD (modreader); + mh->numtrk = _mm_read_I_UWORD (modreader); + mh->globalvol = _mm_read_UBYTE (modreader); + mh->mastervol = _mm_read_UBYTE (modreader); + mh->speed = _mm_read_UBYTE (modreader); + mh->bpm = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->panpos, DSM_MAXCHAN, modreader); + _mm_read_UBYTES (mh->orders, DSM_MAXORDERS, modreader); + + /* set module variables */ + of.initspeed = mh->speed; + of.inittempo = mh->bpm; + of.modtype = strdup (DSM_Version); + of.numchn = mh->numtrk; + of.numpat = mh->numpat; + of.numtrk = of.numchn * of.numpat; + of.songname = DupStr (mh->songname, 28, 1); /* make a cstr of songname */ + of.reppos = 0; + + for (t = 0; t < DSM_MAXCHAN; t++) + of.panning[t] = mh->panpos[t] == DSM_SURROUND ? PAN_SURROUND : + mh->panpos[t] < 0x80 ? (mh->panpos[t] << 1) : 255; + + if (!AllocPositions (mh->numord)) + return 0; + of.numpos = 0; + for (t = 0; t < mh->numord; t++) + { + of.positions[of.numpos] = mh->orders[t]; + if (mh->orders[t] < 254) + of.numpos++; + } + + of.numins = of.numsmp = mh->numsmp; + + if (!AllocSamples ()) + return 0; + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + while (cursmp < of.numins || curpat < of.numpat) + { + if (!GetBlockHeader ()) + return 0; + if (!memcmp (blockid, INSTID, 4) && cursmp < of.numins) + { + q = &of.samples[cursmp]; + + /* try to read sample info */ + _mm_read_UBYTES (s.filename, 13, modreader); + s.flags = _mm_read_I_UWORD (modreader); + s.volume = _mm_read_UBYTE (modreader); + s.length = _mm_read_I_ULONG (modreader); + s.loopstart = _mm_read_I_ULONG (modreader); + s.loopend = _mm_read_I_ULONG (modreader); + s.reserved1 = _mm_read_I_ULONG (modreader); + s.c2spd = _mm_read_I_UWORD (modreader); + s.period = _mm_read_I_UWORD (modreader); + _mm_read_UBYTES (s.samplename, 28, modreader); + + q->samplename = DupStr (s.samplename, 28, 1); + q->seekpos = _mm_ftell (modreader); + q->speed = s.c2spd; + q->length = s.length; + q->loopstart = s.loopstart; + q->loopend = s.loopend; + q->volume = s.volume; + + if (s.flags & 1) + q->flags |= SF_LOOP; + if (s.flags & 2) + q->flags |= SF_SIGNED; + /* (s.flags&4) means packed sample, + but did they really exist in dsm ? */ + cursmp++; + } + else if (!memcmp (blockid, PATTID, 4) && curpat < of.numpat) + { + DSM_ReadPattern (); + for (t = 0; t < of.numchn; t++) + if (!(of.tracks[track++] = DSM_ConvertTrack (&dsmbuf[t * 64]))) + return 0; + curpat++; + } + } + + return 1; +} + +CHAR * +DSM_LoadTitle (void) +{ + CHAR s[28]; + + _mm_fseek (modreader, 12, SEEK_SET); + if (!_mm_read_UBYTES (s, 28, modreader)) + return NULL; + + return (DupStr (s, 28, 1)); +} + +/*========== Loader information */ + +MLOADER load_dsm = +{ + NULL, + "DSM", + "DSM (DSIK internal format)", + DSM_Init, + DSM_Test, + DSM_Load, + DSM_Cleanup, + DSM_LoadTitle +}; + + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_far.c TiMidity++-2.9.0/libunimod/load_far.c --- TiMidity++-2.8.2/libunimod/load_far.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_far.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,376 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_far.c,v 1.29 1999/10/25 16:31:41 miod Exp $ + + Farandole (FAR) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +typedef struct FARHEADER1 + { + UBYTE id[4]; /* file magic */ + CHAR songname[40]; /* songname */ + CHAR blah[3]; /* 13,10,26 */ + UWORD headerlen; /* remaining length of header in bytes */ + UBYTE version; + UBYTE onoff[16]; + UBYTE edit1[9]; + UBYTE speed; + UBYTE panning[16]; + UBYTE edit2[4]; + UWORD stlen; + } +FARHEADER1; + +typedef struct FARHEADER2 + { + UBYTE orders[256]; + UBYTE numpat; + UBYTE snglen; + UBYTE loopto; + UWORD patsiz[256]; + } +FARHEADER2; + +typedef struct FARSAMPLE + { + CHAR samplename[32]; + ULONG length; + UBYTE finetune; + UBYTE volume; + ULONG reppos; + ULONG repend; + UBYTE type; + UBYTE loop; + } +FARSAMPLE; + +typedef struct FARNOTE + { + UBYTE note, ins, vol, eff; + } +FARNOTE; + +/*========== Loader variables */ + +static CHAR FAR_Version[] = "Farandole"; +static FARHEADER1 *mh1 = NULL; +static FARHEADER2 *mh2 = NULL; +static FARNOTE *pat = NULL; + +static unsigned char FARSIG[4 + 3] = +{'F', 'A', 'R', 0xfe, 13, 10, 26}; + +/*========== Loader code */ + +BOOL +FAR_Test (void) +{ + UBYTE id[47]; + + if (!_mm_read_UBYTES (id, 47, modreader)) + return 0; + if ((memcmp (id, FARSIG, 4)) || (memcmp (id + 44, FARSIG + 4, 3))) + return 0; + return 1; +} + +BOOL +FAR_Init (void) +{ + if (!(mh1 = (FARHEADER1 *) _mm_malloc (sizeof (FARHEADER1)))) + return 0; + if (!(mh2 = (FARHEADER2 *) _mm_malloc (sizeof (FARHEADER2)))) + return 0; + if (!(pat = (FARNOTE *) _mm_malloc (256 * 16 * 4 * sizeof (FARNOTE)))) + return 0; + + return 1; +} + +void +FAR_Cleanup (void) +{ + _mm_free (mh1); + _mm_free (mh2); + _mm_free (pat); +} + +static UBYTE * +FAR_ConvertTrack (FARNOTE * n, int rows) +{ + int t, vibdepth = 1; + + UniReset (); + for (t = 0; t < rows; t++) + { + if (n->note) + { + UniInstrument (n->ins); + UniNote (n->note + 3 * OCTAVE - 1); + } + if (n->vol & 0xf) + UniPTEffect (0xc, (n->vol & 0xf) << 2); + if (n->eff) + switch (n->eff >> 4) + { + case 0x3: /* porta to note */ + UniPTEffect (0x3, (n->eff & 0xf) << 4); + break; + case 0x5: /* set vibrato depth */ + vibdepth = n->eff & 0xf; + break; + case 0x6: /* vibrato */ + UniPTEffect (0x4, ((n->eff & 0xf) << 4) | vibdepth); + break; + case 0x7: /* volume slide up */ + UniPTEffect (0xa, (n->eff & 0xf) << 4); + break; + case 0x8: /* volume slide down */ + UniPTEffect (0xa, n->eff & 0xf); + break; + case 0xf: /* set speed */ + UniPTEffect (0xf, n->eff & 0xf); + break; + + /* others not yet implemented */ + default: +#ifdef MIKMOD_DEBUG + fprintf (stderr, "\rFAR: unsupported effect %02X\n", n->eff); +#endif + break; + } + + UniNewline (); + n += 16; + } + return UniDup (); +} + +BOOL +FAR_Load (BOOL curious) +{ + int t, u, tracks = 0; + SAMPLE *q; + FARSAMPLE s; + FARNOTE *crow; + UBYTE smap[8]; + + /* try to read module header (first part) */ + _mm_read_UBYTES (mh1->id, 4, modreader); + _mm_read_SBYTES (mh1->songname, 40, modreader); + _mm_read_SBYTES (mh1->blah, 3, modreader); + mh1->headerlen = _mm_read_I_UWORD (modreader); + mh1->version = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh1->onoff, 16, modreader); + _mm_read_UBYTES (mh1->edit1, 9, modreader); + mh1->speed = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh1->panning, 16, modreader); + _mm_read_UBYTES (mh1->edit2, 4, modreader); + mh1->stlen = _mm_read_I_UWORD (modreader); + + /* init modfile data */ + of.modtype = strdup (FAR_Version); + of.songname = DupStr (mh1->songname, 40, 1); + of.numchn = 16; + of.initspeed = mh1->speed; + of.inittempo = 80; + of.reppos = 0; + for (t = 0; t < 16; t++) + of.panning[t] = mh1->panning[t] << 4; + + /* read songtext into comment field */ + if (mh1->stlen) + if (!ReadComment (mh1->stlen)) + return 0; + + /* try to read module header (second part) */ + _mm_read_UBYTES (mh2->orders, 256, modreader); + mh2->numpat = _mm_read_UBYTE (modreader); + mh2->snglen = _mm_read_UBYTE (modreader); + mh2->loopto = _mm_read_UBYTE (modreader); + _mm_read_I_UWORDS (mh2->patsiz, 256, modreader); + + of.numpos = mh2->snglen; + if (!AllocPositions (of.numpos)) + return 0; + for (t = 0; t < of.numpos; t++) + { + if (mh2->orders[t] == 0xff) + break; + of.positions[t] = mh2->orders[t]; + } + + /* count number of patterns stored in file */ + of.numpat = 0; + for (t = 0; t < 256; t++) + if (mh2->patsiz[t]) + if ((t + 1) > of.numpat) + of.numpat = t + 1; + of.numtrk = of.numpat * of.numchn; + + /* seek across eventual new data */ + _mm_fseek (modreader, mh1->headerlen - (869 + mh1->stlen), SEEK_CUR); + + /* alloc track and pattern structures */ + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + for (t = 0; t < of.numpat; t++) + { + UBYTE rows = 0, tempo; + + memset (pat, 0, 256 * 16 * 4 * sizeof (FARNOTE)); + if (mh2->patsiz[t]) + { + rows = _mm_read_UBYTE (modreader); + tempo = _mm_read_UBYTE (modreader); + + crow = pat; + /* file often allocates 64 rows even if there are less in pattern */ + if (mh2->patsiz[t] < 2 + (rows * 16 * 4)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + for (u = (mh2->patsiz[t] - 2) / 4; u; u--, crow++) + { + crow->note = _mm_read_UBYTE (modreader); + crow->ins = _mm_read_UBYTE (modreader); + crow->vol = _mm_read_UBYTE (modreader); + crow->eff = _mm_read_UBYTE (modreader); + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + crow = pat; + of.pattrows[t] = rows; + for (u = 16; u; u--, crow++) + if (!(of.tracks[tracks++] = FAR_ConvertTrack (crow, rows))) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + } + else + tracks += 16; + } + + /* read sample map */ + if (!_mm_read_UBYTES (smap, 8, modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* count number of samples used */ + of.numins = 0; + for (t = 0; t < 64; t++) + if (smap[t >> 3] & (1 << (t & 7))) + of.numins = t + 1; + of.numsmp = of.numins; + + /* alloc sample structs */ + if (!AllocSamples ()) + return 0; + + q = of.samples; + for (t = 0; t < of.numsmp; t++) + { + q->speed = 8363; + q->flags = SF_SIGNED; + if (smap[t >> 3] & (1 << (t & 7))) + { + _mm_read_SBYTES (s.samplename, 32, modreader); + s.length = _mm_read_I_ULONG (modreader); + s.finetune = _mm_read_UBYTE (modreader); + s.volume = _mm_read_UBYTE (modreader); + s.reppos = _mm_read_I_ULONG (modreader); + s.repend = _mm_read_I_ULONG (modreader); + s.type = _mm_read_UBYTE (modreader); + s.loop = _mm_read_UBYTE (modreader); + + q->samplename = DupStr (s.samplename, 32, 1); + q->length = s.length; + q->loopstart = s.reppos; + q->loopend = s.repend; + q->volume = s.volume << 2; + + if (s.type & 1) + q->flags |= SF_16BITS; + if (s.loop & 8) + q->flags |= SF_LOOP; + + q->seekpos = _mm_ftell (modreader); + _mm_fseek (modreader, q->length, SEEK_CUR); + } + else + q->samplename = DupStr (NULL, 0, 0); + q++; + } + return 1; +} + +CHAR * +FAR_LoadTitle (void) +{ + CHAR s[40]; + + _mm_fseek (modreader, 4, SEEK_SET); + if (!_mm_read_UBYTES (s, 40, modreader)) + return NULL; + + return (DupStr (s, 40, 1)); +} + +/*========== Loader information */ + +MLOADER load_far = +{ + NULL, + "FAR", + "FAR (Farandole Composer)", + FAR_Init, + FAR_Test, + FAR_Load, + FAR_Cleanup, + FAR_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_gdm.c TiMidity++-2.9.0/libunimod/load_gdm.c --- TiMidity++-2.8.2/libunimod/load_gdm.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_gdm.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,603 @@ +/* MikMod sound library + (c) 1998,1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software;you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library;if not,write to the Free Software + Foundation,Inc.,59 Temple Place - Suite 330,Boston,MA + 02111-1307,USA. + */ + +/*============================================================================== + + $Id: load_gdm.c,v 1.5 1999/10/25 16:31:41 miod Exp $ + + General DigiMusic (GDM) module loader + +==============================================================================*/ + +/* + + Written by Kev Vance + based on the file format description written by 'MenTaLguY' + + + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "unimod_priv.h" + +typedef struct GDMNOTE + { + UBYTE note; + UBYTE samp; + struct + { + UBYTE effect; + UBYTE param; + } + effect[4]; + } +GDMNOTE; + +typedef GDMNOTE GDMTRACK[64]; + +typedef struct GDMHEADER + { + CHAR id1[4]; + CHAR songname[32]; + CHAR author[32]; + CHAR eofmarker[3]; + CHAR id2[4]; + + UBYTE majorver; + UBYTE minorver; + UWORD trackerid; + UBYTE t_majorver; + UBYTE t_minorver; + UBYTE pantable[32]; + UBYTE mastervol; + UBYTE mastertempo; + UBYTE masterbpm; + UWORD flags; + + ULONG orderloc; + UBYTE ordernum; + ULONG patternloc; + UBYTE patternnum; + ULONG samhead; + ULONG samdata; + UBYTE samnum; + ULONG messageloc; + ULONG messagelen; + ULONG scrollyloc; + UWORD scrollylen; + ULONG graphicloc; + UWORD graphiclen; + } +GDMHEADER; + +typedef struct GDMSAMPLE + { + CHAR sampname[32]; + CHAR filename[13]; + UBYTE ems; + ULONG length; + ULONG loopbeg; + ULONG loopend; + UBYTE flags; + UWORD c4spd; + UBYTE vol; + UBYTE pan; + } +GDMSAMPLE; + +static GDMHEADER *mh = NULL; /* pointer to GDM header */ +static GDMNOTE *gdmbuf = NULL; /* pointer to a complete GDM pattern */ + +CHAR GDM_Version[] = "General DigiMusic 1.xx"; + +BOOL +GDM_Test (void) +{ + /* test for gdm magic numbers */ + UBYTE id[4]; + + _mm_fseek (modreader, 0x00, SEEK_SET); + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + if (!memcmp (id, "GDM\xfe", 4)) + { + _mm_fseek (modreader, 71, SEEK_SET); + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + if (!memcmp (id, "GMFS", 4)) + return 1; + } + return 0; +} + +BOOL +GDM_Init (void) +{ + if (!(gdmbuf = (GDMNOTE *) _mm_malloc (32 * 64 * sizeof (GDMNOTE)))) + return 0; + if (!(mh = (GDMHEADER *) _mm_malloc (sizeof (GDMHEADER)))) + return 0; + + return 1; +} + +void +GDM_Cleanup (void) +{ + _mm_free (mh); + _mm_free (gdmbuf); +} + +BOOL +GDM_ReadPattern (void) +{ + int pos, flag, ch, i, maxch; + GDMNOTE n; + UWORD length, x = 0; + + /* get pattern length */ + length = _mm_read_I_UWORD (modreader) - 2; + + /* clear pattern data */ + memset (gdmbuf, 255, 32 * 64 * sizeof (GDMNOTE)); + pos = 0; + maxch = 0; + + while (x < length) + { + memset (&n, 255, sizeof (GDMNOTE)); + flag = _mm_read_UBYTE (modreader); + x++; + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + ch = flag & 31; + if (ch > maxch) + maxch = ch; + if (!flag) + { + pos++; + continue; + } + if (flag & 0x60) + { + if (flag & 0x20) + { + /* new note */ + n.note = _mm_read_UBYTE (modreader) & 127; + n.samp = _mm_read_UBYTE (modreader); + x += 2; + } + if (flag & 0x40) + { + do + { + /* effect channel set */ + i = _mm_read_UBYTE (modreader); + n.effect[i >> 6].effect = i & 31; + n.effect[i >> 6].param = _mm_read_UBYTE (modreader); + x += 2; + } + while (i & 32); + } + memcpy (gdmbuf + (64U * ch) + pos, &n, sizeof (n)); + } + } + return 1; +} + +UBYTE * +GDM_ConvertTrack (GDMNOTE * tr) +{ + int t, i = 0; + UBYTE note, ins; + + UniReset (); + for (t = 0; t < 64; t++) + { + note = tr[t].note; + ins = tr[t].samp; + + if ((ins) && (ins != 255)) + UniInstrument (ins - 1); + if (note != 255) + { + UniNote (((note >> 4) * OCTAVE) + (note & 0xf) - 1); + } + for (i = 0; i < 4; i++) + { + switch (tr[t].effect[i].effect) + { + case 1: /* toneslide up */ + UniEffect (UNI_S3MEFFECTF, tr[t].effect[i].param); + break; + case 2: /* toneslide down */ + UniEffect (UNI_S3MEFFECTE, tr[t].effect[i].param); + break; + case 3: /* glissando to note */ + UniEffect (UNI_ITEFFECTG, tr[t].effect[i].param); + break; + case 4: /* vibrato */ + UniEffect (UNI_ITEFFECTH, tr[t].effect[i].param); + break; + case 5: /* portamento+volslide */ + UniEffect (UNI_ITEFFECTG, 0); + UniEffect (UNI_S3MEFFECTD, tr[t].effect[i].param); + break; + case 6: /* vibrato+volslide */ + UniEffect (UNI_ITEFFECTH, 0); + UniEffect (UNI_S3MEFFECTD, tr[t].effect[i].param); + break; + case 7: /* tremolo */ + UniEffect (UNI_S3MEFFECTR, tr[t].effect[i].param); + break; + case 8: /* tremor */ + UniEffect (UNI_S3MEFFECTI, tr[t].effect[i].param); + break; + case 9: /* offset */ + UniPTEffect (0x09, tr[t].effect[i].param); + break; + case 0x0a: /* volslide */ + UniEffect (UNI_S3MEFFECTD, tr[t].effect[i].param); + break; + case 0x0b: /* jump to order */ + UniPTEffect (0x0b, tr[t].effect[i].param); + break; + case 0x0c: /* volume set */ + UniPTEffect (0x0c, tr[t].effect[i].param); + break; + case 0x0d: /* pattern break */ + UniPTEffect (0x0d, tr[t].effect[i].param); + break; + case 0x0e: /* extended */ + switch (tr[t].effect[i].param & 0xf0) + { + case 0x10: /* fine portamento up */ + UniEffect (UNI_S3MEFFECTF, + 0x0f | ((tr[t].effect[i].param << 4) & 0x0f)); + break; + case 0x20: /* fine portamento down */ + UniEffect (UNI_S3MEFFECTE, + 0xf0 | (tr[t].effect[i].param & 0x0f)); + break; + case 0x30: /* glissando control */ + UniEffect (SS_GLISSANDO, + tr[t].effect[i].param & 0x0f); + break; + case 0x40: /* vibrato waveform */ + UniEffect (SS_VIBWAVE, + tr[t].effect[i].param & 0x0f); + break; + case 0x50: /* set c4spd */ + UniEffect (SS_FINETUNE, + tr[t].effect[i].param & 0x0f); + break; + case 0x60: /* loop fun */ + UniEffect (UNI_ITEFFECTS0, + (tr[t].effect[i].param & 0x0f) | 0xb0); + break; + case 0x70: /* tremolo waveform */ + UniEffect (SS_TREMWAVE, + tr[t].effect[i].param & 0x0f); + break; + case 0x80: /* extra fine porta up */ + UniEffect (UNI_S3MEFFECTF, + 0x0e | ((tr[t].effect[i].param << 4) & 0x0f)); + break; + case 0x90: /* extra fine porta down */ + UniEffect (UNI_S3MEFFECTE, + 0xe0 | (tr[t].effect[i].param & 0x0f)); + break; + case 0xa0: /* fine volslide up */ + UniEffect (UNI_S3MEFFECTD, + 0x0f | ((tr[t].effect[i].param << 4) & 0x0f)); + break; + case 0xb0: /* fine volslide down */ + UniEffect (UNI_S3MEFFECTE, + 0xf0 | (tr[t].effect[i].param & 0x0f)); + break; + case 0xc0: /* note cut */ + case 0xd0: /* note delay */ + case 0xe0: /* extend row */ + UniPTEffect (0xe, tr[t].effect[i].param); + break; + } + break; + case 0x0f: /* set tempo */ + UniEffect (UNI_S3MEFFECTA, tr[t].effect[i].param); + break; + case 0x10: /* arpeggio */ + UniPTEffect (0x0, tr[t].effect[i].param); + break; + case 0x12: /* retrigger */ + UniEffect (UNI_S3MEFFECTQ, tr[t].effect[i].param); + break; + case 0x13: /* set global volume */ + UniEffect (UNI_XMEFFECTG, tr[t].effect[i].param); + break; + case 0x14: /* fine vibrato */ + UniEffect (UNI_ITEFFECTU, tr[t].effect[i].param); + break; + case 0x1e: /* special */ + switch (tr[t].effect[i].param & 0xf0) + { + case 8: /* set pan position */ + if (tr[t].effect[i].param >= 128) + UniPTEffect (0x08, 255); + else + UniPTEffect (0x08, tr[t].effect[i].param << 1); + break; + } + break; + case 0x1f: /* set bpm */ + if (tr[t].effect[i].param >= 0x20) + UniEffect (UNI_S3MEFFECTT, tr[t].effect[i].param); + break; + } + } + UniNewline (); + } + return UniDup (); +} + +BOOL +GDM_Load (BOOL curious) +{ + int i, x, u, track; + SAMPLE *q; + GDMSAMPLE s; + ULONG position; + + /* read header */ + _mm_read_string (mh->id1, 4, modreader); + _mm_read_string (mh->songname, 32, modreader); + _mm_read_string (mh->author, 32, modreader); + _mm_read_string (mh->eofmarker, 3, modreader); + _mm_read_string (mh->id2, 4, modreader); + + mh->majorver = _mm_read_UBYTE (modreader); + mh->minorver = _mm_read_UBYTE (modreader); + mh->trackerid = _mm_read_I_UWORD (modreader); + mh->t_majorver = _mm_read_UBYTE (modreader); + mh->t_minorver = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->pantable, 32, modreader); + mh->mastervol = _mm_read_UBYTE (modreader); + mh->mastertempo = _mm_read_UBYTE (modreader); + mh->masterbpm = _mm_read_UBYTE (modreader); + mh->flags = _mm_read_I_UWORD (modreader); + + mh->orderloc = _mm_read_I_ULONG (modreader); + mh->ordernum = _mm_read_UBYTE (modreader); + mh->patternloc = _mm_read_I_ULONG (modreader); + mh->patternnum = _mm_read_UBYTE (modreader); + mh->samhead = _mm_read_I_ULONG (modreader); + mh->samdata = _mm_read_I_ULONG (modreader); + mh->samnum = _mm_read_UBYTE (modreader); + mh->messageloc = _mm_read_I_ULONG (modreader); + mh->messagelen = _mm_read_I_ULONG (modreader); + mh->scrollyloc = _mm_read_I_ULONG (modreader); + mh->scrollylen = _mm_read_I_UWORD (modreader); + mh->graphicloc = _mm_read_I_ULONG (modreader); + mh->graphiclen = _mm_read_I_UWORD (modreader); + + /* have we ended abruptly? */ + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* any orders? */ + if (mh->ordernum == 255) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + /* now we fill */ + of.modtype = strdup (GDM_Version); + of.modtype[18] = mh->majorver + '0'; + of.modtype[20] = mh->minorver / 10 + '0'; + of.modtype[21] = mh->minorver % 10 + '0'; + of.songname = DupStr (mh->songname, 32, 0); + of.numpat = mh->patternnum + 1; + of.reppos = 0; + of.numins = of.numsmp = mh->samnum + 1; + of.initspeed = mh->mastertempo; + of.inittempo = mh->masterbpm; + of.initvolume = mh->mastervol << 1; + of.flags |= UF_S3MSLIDES; + + /* read the order data */ + if (!AllocPositions (mh->ordernum + 1)) + { + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + + _mm_fseek (modreader, mh->orderloc, SEEK_SET); + for (i = 0; i < mh->ordernum + 1; i++) + of.positions[i] = _mm_read_UBYTE (modreader); + + of.numpos = 0; + for (i = 0; i < mh->ordernum + 1; i++) + { + of.positions[of.numpos] = of.positions[i]; + if (of.positions[i] < 254) + of.numpos++; + } + + /* have we ended abruptly yet? */ + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* time to load the samples */ + if (!AllocSamples ()) + { + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + + q = of.samples; + position = mh->samdata; + + /* seek to instrument position */ + _mm_fseek (modreader, mh->samhead, SEEK_SET); + + for (i = 0; i < of.numins; i++) + { + /* load sample info */ + _mm_read_UBYTES (s.sampname, 32, modreader); + _mm_read_UBYTES (s.filename, 12, modreader); + s.ems = _mm_read_UBYTE (modreader); + s.length = _mm_read_I_ULONG (modreader); + s.loopbeg = _mm_read_I_ULONG (modreader); + s.loopend = _mm_read_I_ULONG (modreader); + s.flags = _mm_read_UBYTE (modreader); + s.c4spd = _mm_read_I_UWORD (modreader); + s.vol = _mm_read_UBYTE (modreader); + s.pan = _mm_read_UBYTE (modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + q->samplename = DupStr (s.sampname, 32, 0); + q->speed = s.c4spd; + q->length = s.length; + q->loopstart = s.loopbeg; + q->loopend = s.loopend; + q->volume = s.vol; + q->panning = s.pan; + q->seekpos = position; + + position += s.length; + + if (s.flags & 1) + q->flags |= SF_LOOP; + if (s.flags & 2) + q->flags |= SF_16BITS; + if (s.flags & 16) + q->flags |= SF_STEREO; + q++; + } + + /* set the panning */ + for (i = x = 0; i < 32; i++) + { + of.panning[i] = mh->pantable[i]; + if (!of.panning[i]) + of.panning[i] = PAN_LEFT; + else if (of.panning[i] == 8) + of.panning[i] = PAN_CENTER; + else if (of.panning[i] == 15) + of.panning[i] = PAN_RIGHT; + else if (of.panning[i] == 16) + of.panning[i] = PAN_SURROUND; + else if (of.panning[i] == 255) + of.panning[i] = 128; + else + of.panning[i] <<= 3; + of.panning[i] = PAN_CENTER; + if (mh->pantable[i] != 255) + x = i; + } + + of.numchn = x + 1; + if (of.numchn < 1) + of.numchn = 1; /* for broken counts */ + + /* load the pattern info */ + of.numtrk = of.numpat * of.numchn; + + /* jump to patterns */ + _mm_fseek (modreader, mh->patternloc, SEEK_SET); + + if (!AllocTracks ()) + { + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + + if (!AllocPatterns ()) + { + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + + for (i = track = 0; i < of.numpat; i++) + { + if (!GDM_ReadPattern ()) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + for (u = 0; u < of.numchn; u++, track++) + { + of.tracks[track] = GDM_ConvertTrack (&gdmbuf[u << 6]); + if (!of.tracks[track]) + { + _mm_errno = MMERR_LOADING_TRACK; + return 0; + } + } + } + return 1; +} + +CHAR * +GDM_LoadTitle (void) +{ + CHAR s[32]; + + _mm_fseek (modreader, 4, SEEK_SET); + if (!_mm_read_UBYTES (s, 32, modreader)) + return NULL; + + return DupStr (s, 28, 0); +} + +MLOADER load_gdm = +{ + NULL, + "GDM", + "GDM (General DigiMusic)", + GDM_Init, + GDM_Test, + GDM_Load, + GDM_Cleanup, + GDM_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_imf.c TiMidity++-2.9.0/libunimod/load_imf.c --- TiMidity++-2.8.2/libunimod/load_imf.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_imf.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,796 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_imf.c,v 1.12 1999/10/25 16:31:41 miod Exp $ + + Imago Orpheus (IMF) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +/* module header */ +typedef struct IMFHEADER + { + CHAR songname[32]; + UWORD ordnum; + UWORD patnum; + UWORD insnum; + UWORD flags; + UBYTE initspeed; + UBYTE inittempo; + UBYTE mastervol; + UBYTE mastermult; + UBYTE orders[256]; + } +IMFHEADER; + +/* channel settings */ +typedef struct IMFCHANNEL + { + CHAR name[12]; + UBYTE chorus; + UBYTE reverb; + UBYTE pan; + UBYTE status; + } +IMFCHANNEL; + +/* instrument header */ +#define IMFNOTECNT (10*OCTAVE) +#define IMFENVCNT (16*2) +typedef struct IMFINSTHEADER + { + CHAR name[32]; + UBYTE what[IMFNOTECNT]; + UWORD volenv[IMFENVCNT]; + UWORD panenv[IMFENVCNT]; + UWORD pitenv[IMFENVCNT]; + UBYTE volpts; + UBYTE volsus; + UBYTE volbeg; + UBYTE volend; + UBYTE volflg; + UBYTE panpts; + UBYTE pansus; + UBYTE panbeg; + UBYTE panend; + UBYTE panflg; + UBYTE pitpts; + UBYTE pitsus; + UBYTE pitbeg; + UBYTE pitend; + UBYTE pitflg; + UWORD volfade; + UWORD numsmp; + ULONG signature; + } +IMFINSTHEADER; + +/* sample header */ +typedef struct IMFWAVHEADER + { + CHAR samplename[13]; + ULONG length; + ULONG loopstart; + ULONG loopend; + ULONG samplerate; + UBYTE volume; + UBYTE pan; + UBYTE flags; + } +IMFWAVHEADER; + +typedef struct IMFNOTE + { + UBYTE note, ins, eff1, dat1, eff2, dat2; + } +IMFNOTE; + +/*========== Loader variables */ + +static CHAR IMF_Version[] = "Imago Orpheus"; + +static IMFNOTE *imfpat = NULL; +static IMFHEADER *mh = NULL; + +/*========== Loader code */ + +BOOL +IMF_Test (void) +{ + UBYTE id[4]; + + _mm_fseek (modreader, 0x3c, SEEK_SET); + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + if (!memcmp (id, "IM10", 4)) + return 1; + return 0; +} + +BOOL +IMF_Init (void) +{ + if (!(imfpat = (IMFNOTE *) _mm_malloc (32 * 256 * sizeof (IMFNOTE)))) + return 0; + if (!(mh = (IMFHEADER *) _mm_malloc (sizeof (IMFHEADER)))) + return 0; + + return 1; +} + +void +IMF_Cleanup (void) +{ + FreeLinear (); + + _mm_free (imfpat); + _mm_free (mh); +} + +static BOOL +IMF_ReadPattern (SLONG size, UWORD rows) +{ + int row = 0, flag, ch; + IMFNOTE *n, dummy; + + /* clear pattern data */ + memset (imfpat, 255, 32 * 256 * sizeof (IMFNOTE)); + + while ((size > 0) && (row < rows)) + { + flag = _mm_read_UBYTE (modreader); + size--; + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if (flag) + { + ch = remap[flag & 31]; + + if (ch != -1) + n = &imfpat[256 * ch + row]; + else + n = &dummy; + + if (flag & 32) + { + n->note = _mm_read_UBYTE (modreader); + if (n->note >= 0xa0) + n->note = 0xa0; /* note off */ + n->ins = _mm_read_UBYTE (modreader); + size -= 2; + } + if (flag & 64) + { + size -= 2; + n->eff2 = _mm_read_UBYTE (modreader); + n->dat2 = _mm_read_UBYTE (modreader); + } + if (flag & 128) + { + n->eff1 = _mm_read_UBYTE (modreader); + n->dat1 = _mm_read_UBYTE (modreader); + size -= 2; + } + } + else + row++; + } + if ((size) || (row != rows)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + return 1; +} + +static void +IMF_ProcessCmd (UBYTE eff, UBYTE inf) +{ + if ((eff) && (eff != 255)) + switch (eff) + { + case 0x01: /* set tempo */ + UniEffect (UNI_S3MEFFECTA, inf); + break; + case 0x02: /* set BPM */ + if (inf >= 0x20) + UniEffect (UNI_S3MEFFECTT, inf); + break; + case 0x03: /* tone portamento */ + UniEffect (UNI_ITEFFECTG, inf); + break; + case 0x04: /* porta + volslide */ + UniEffect (UNI_ITEFFECTG, inf); + UniEffect (UNI_S3MEFFECTD, 0); + break; + case 0x05: /* vibrato */ + UniPTEffect (0x4, inf); + break; + case 0x06: /* vibrato + volslide */ + UniPTEffect (0x4, inf); + UniEffect (UNI_S3MEFFECTD, 0); + break; + case 0x07: /* fine vibrato */ + UniEffect (UNI_ITEFFECTU, inf); + break; + case 0x08: /* tremolo */ + UniEffect (UNI_S3MEFFECTR, inf); + break; + case 0x09: /* arpeggio */ + UniPTEffect (0x0, inf); + break; + case 0x0a: /* panning */ + UniPTEffect (0x8, (inf >= 128) ? 255 : (inf << 1)); + break; + case 0x0b: /* pan slide */ + UniEffect (UNI_XMEFFECTP, inf); + break; + case 0x0c: /* set channel volume */ + if (inf <= 64) + UniPTEffect (0xc, inf); + break; + case 0x0d: /* volume slide */ + UniEffect (UNI_S3MEFFECTD, inf); + break; + case 0x0e: /* fine volume slide */ + if (inf) + { + if (inf >> 4) + UniEffect (UNI_S3MEFFECTD, 0x0f | inf); + else + UniEffect (UNI_S3MEFFECTD, 0xf0 | inf); + } + else + UniEffect (UNI_S3MEFFECTD, 0); + break; + case 0x0f: /* set finetune */ + UniPTEffect (0xe, 0x50 | (inf >> 4)); + break; +#ifdef MIKMOD_DEBUG + case 0x10: /* note slide up */ + case 0x11: /* not slide down */ + fprintf (stderr, "\rIMF effect 0x10/0x11 (note slide)" + " not implemented (eff=%2X inf=%2X)\n", eff, inf); + break; +#endif + case 0x12: /* slide up */ + UniEffect (UNI_S3MEFFECTF, inf); + break; + case 0x13: /* slide down */ + UniEffect (UNI_S3MEFFECTE, inf); + break; + case 0x14: /* fine slide up */ + if (inf) + { + if (inf < 0x40) + UniEffect (UNI_S3MEFFECTF, 0xe0 | (inf / 4)); + else + UniEffect (UNI_S3MEFFECTF, 0xf0 | (inf >> 4)); + } + else + UniEffect (UNI_S3MEFFECTF, 0); + break; + case 0x15: /* fine slide down */ + if (inf) + { + if (inf < 0x40) + UniEffect (UNI_S3MEFFECTE, 0xe0 | (inf / 4)); + else + UniEffect (UNI_S3MEFFECTE, 0xf0 | (inf >> 4)); + } + else + UniEffect (UNI_S3MEFFECTE, 0); + break; + /* 0x16 set filter cutoff (awe32) */ + /* 0x17 filter side + resonance (awe32) */ + case 0x18: /* sample offset */ + UniPTEffect (0x9, inf); + break; +#ifdef MIKMOD_DEBUG + case 0x19: /* set fine sample offset */ + fprintf (stderr, "\rIMF effect 0x19 (fine sample offset)" + " not implemented (inf=%2X)\n", inf); + break; +#endif + case 0x1a: /* keyoff */ + UniWriteByte (UNI_KEYOFF); + break; + case 0x1b: /* retrig */ + UniEffect (UNI_S3MEFFECTQ, inf); + break; + case 0x1c: /* tremor */ + UniEffect (UNI_S3MEFFECTI, inf); + break; + case 0x1d: /* position jump */ + UniPTEffect (0xb, inf); + break; + case 0x1e: /* pattern break */ + UniPTEffect (0xd, (inf >> 4) * 10 + (inf & 0xf)); + break; + case 0x1f: /* set master volume */ + if (inf <= 64) + UniEffect (UNI_XMEFFECTG, inf); + break; + case 0x20: /* master volume slide */ + UniEffect (UNI_XMEFFECTH, inf); + break; + case 0x21: /* extended effects */ + switch (inf >> 4) + { + case 0x1: /* set filter */ + case 0x5: /* vibrato waveform */ + case 0x8: /* tremolo waveform */ + UniPTEffect (0xe, inf - 0x10); + break; + case 0xa: /* pattern loop */ + UniPTEffect (0xe, 0x60 | (inf & 0xf)); + break; + case 0xb: /* pattern delay */ + UniPTEffect (0xe, 0xe0 | (inf & 0xf)); + break; + case 0x3: /* glissando */ + case 0xc: /* note cut */ + case 0xd: /* note delay */ + case 0xf: /* invert loop */ + UniPTEffect (0xe, inf); + break; + case 0xe: /* ignore envelope */ + UniEffect (UNI_ITEFFECTS0, 0x77); /* vol */ + UniEffect (UNI_ITEFFECTS0, 0x79); /* pan */ + UniEffect (UNI_ITEFFECTS0, 0x7b); /* pit */ + break; + } + break; + /* 0x22 chorus (awe32) */ + /* 0x23 reverb (awe32) */ + } +} + +static UBYTE * +IMF_ConvertTrack (IMFNOTE * tr, UWORD rows) +{ + int t; + UBYTE note, ins; + + UniReset (); + for (t = 0; t < rows; t++) + { + note = tr[t].note; + ins = tr[t].ins; + + if ((ins) && (ins != 255)) + UniInstrument (ins - 1); + if (note != 255) + { + if (note == 0xa0) + { + UniPTEffect (0xc, 0); /* Note cut */ + if (tr[t].eff1 == 0x0c) + tr[t].eff1 = 0; + if (tr[t].eff2 == 0x0c) + tr[t].eff2 = 0; + } + else + UniNote (((note >> 4) * OCTAVE) + (note & 0xf)); + } + + IMF_ProcessCmd (tr[t].eff1, tr[t].dat1); + IMF_ProcessCmd (tr[t].eff2, tr[t].dat2); + UniNewline (); + } + return UniDup (); +} + +BOOL +IMF_Load (BOOL curious) +{ +#define IMF_SMPINCR 64 + int t, u, track = 0; + IMFCHANNEL channels[32]; + INSTRUMENT *d; + SAMPLE *q; + IMFWAVHEADER *wh = NULL, *s = NULL; + ULONG *nextwav = NULL; + UWORD wavcnt = 0; + UBYTE id[4]; + + /* try to read the module header */ + _mm_read_string (mh->songname, 32, modreader); + mh->ordnum = _mm_read_I_UWORD (modreader); + mh->patnum = _mm_read_I_UWORD (modreader); + mh->insnum = _mm_read_I_UWORD (modreader); + mh->flags = _mm_read_I_UWORD (modreader); + _mm_fseek (modreader, 8, SEEK_CUR); + mh->initspeed = _mm_read_UBYTE (modreader); + mh->inittempo = _mm_read_UBYTE (modreader); + mh->mastervol = _mm_read_UBYTE (modreader); + mh->mastermult = _mm_read_UBYTE (modreader); + _mm_fseek (modreader, 64, SEEK_SET); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.songname = DupStr (mh->songname, 31, 1); + of.modtype = strdup (IMF_Version); + of.numpat = mh->patnum; + of.numins = mh->insnum; + of.reppos = 0; + of.initspeed = mh->initspeed; + of.inittempo = mh->inittempo; + of.initvolume = mh->mastervol << 1; + of.flags |= UF_INST; + if (mh->flags & 1) + of.flags |= UF_LINEAR; + + /* read channel information */ + of.numchn = 0; + memset (remap, -1, 32 * sizeof (UBYTE)); + for (t = 0; t < 32; t++) + { + _mm_read_string (channels[t].name, 12, modreader); + channels[t].chorus = _mm_read_UBYTE (modreader); + channels[t].reverb = _mm_read_UBYTE (modreader); + channels[t].pan = _mm_read_UBYTE (modreader); + channels[t].status = _mm_read_UBYTE (modreader); + } + /* bug in Imago Orpheus ? If only channel 1 is enabled, in fact we have to + enable 16 channels */ + if (!channels[0].status) + { + for (t = 1; t < 16; t++) + if (channels[t].status != 1) + break; + if (t == 16) + for (t = 1; t < 16; t++) + channels[t].status = 0; + } + for (t = 0; t < 32; t++) + { + if (channels[t].status != 2) + remap[t] = of.numchn++; + else + remap[t] = -1; + } + for (t = 0; t < 32; t++) + if (remap[t] != -1) + { + of.panning[remap[t]] = channels[t].pan; + of.chanvol[remap[t]] = channels[t].status ? 0 : 64; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* read order list */ + _mm_read_UBYTES (mh->orders, 256, modreader); + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + of.numpos = 0; + for (t = 0; t < mh->ordnum; t++) + if (mh->orders[t] != 0xff) + of.numpos++; + if (!AllocPositions (of.numpos)) + return 0; + for (t = u = 0; t < mh->ordnum; t++) + if (mh->orders[t] != 0xff) + of.positions[u++] = mh->orders[t]; + + /* load pattern info */ + of.numtrk = of.numpat * of.numchn; + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + for (t = 0; t < of.numpat; t++) + { + SLONG size; + UWORD rows; + + size = (SLONG) _mm_read_I_UWORD (modreader); + rows = _mm_read_I_UWORD (modreader); + if ((rows > 256) || (size < 4)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + of.pattrows[t] = rows; + if (!IMF_ReadPattern (size - 4, rows)) + return 0; + for (u = 0; u < of.numchn; u++) + if (!(of.tracks[track++] = IMF_ConvertTrack (&imfpat[u * 256], rows))) + return 0; + } + + /* load instruments */ + if (!AllocInstruments ()) + return 0; + d = of.instruments; + + for (t = 0; t < of.numins; t++) + { + IMFINSTHEADER ih; + + memset (d->samplenumber, 0xff, INSTNOTES * sizeof (UWORD)); + + /* read instrument header */ + _mm_read_string (ih.name, 32, modreader); + d->insname = DupStr (ih.name, 31, 1); + _mm_read_UBYTES (ih.what, IMFNOTECNT, modreader); + _mm_fseek (modreader, 8, SEEK_CUR); + _mm_read_I_UWORDS (ih.volenv, IMFENVCNT, modreader); + _mm_read_I_UWORDS (ih.panenv, IMFENVCNT, modreader); + _mm_read_I_UWORDS (ih.pitenv, IMFENVCNT, modreader); + +#define IMF_FinishLoadingEnvelope(name) \ + ih.##name##pts=_mm_read_UBYTE(modreader); \ + ih.##name##sus=_mm_read_UBYTE(modreader); \ + ih.##name##beg=_mm_read_UBYTE(modreader); \ + ih.##name##end=_mm_read_UBYTE(modreader); \ + ih.##name##flg=_mm_read_UBYTE(modreader); \ + _mm_read_UBYTE(modreader); \ + _mm_read_UBYTE(modreader); \ + _mm_read_UBYTE(modreader); + + IMF_FinishLoadingEnvelope (vol); + IMF_FinishLoadingEnvelope (pan); + IMF_FinishLoadingEnvelope (pit); + + ih.volfade = _mm_read_I_UWORD (modreader); + ih.numsmp = _mm_read_I_UWORD (modreader); + + _mm_read_UBYTES (id, 4, modreader); + if (memcmp (id, "II10", 4)) + { + if (nextwav) + free (nextwav); + if (wh) + free (wh); + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + if ((ih.numsmp > 16) || (ih.volpts > IMFENVCNT / 2) || (ih.panpts > IMFENVCNT / 2) || + (ih.pitpts > IMFENVCNT / 2) || (_mm_eof (modreader))) + { + if (nextwav) + free (nextwav); + if (wh) + free (wh); + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + for (u = 0; u < IMFNOTECNT; u++) + d->samplenumber[u] = ih.what[u] > ih.numsmp ? 0xffff : ih.what[u] + of.numsmp; + d->volfade = ih.volfade; + +#define IMF_ProcessEnvelope(name) \ + memcpy(d->##name##env,ih.##name##env,IMFENVCNT); \ + if (ih.##name##flg&1) d->##name##flg|=EF_ON; \ + if (ih.##name##flg&2) d->##name##flg|=EF_SUSTAIN; \ + if (ih.##name##flg&4) d->##name##flg|=EF_LOOP; \ + d->##name##susbeg=d->##name##susend=ih.##name##sus; \ + d->##name##beg=ih.##name##beg; \ + d->##name##end=ih.##name##end; \ + d->##name##pts=ih.##name##pts; \ + \ + if ((d->##name##flg&EF_ON)&&(d->##name##pts<2)) \ + d->##name##flg&=~EF_ON; + + IMF_ProcessEnvelope (vol); + IMF_ProcessEnvelope (pan); + IMF_ProcessEnvelope (pit); +#undef IMF_ProcessEnvelope + + if (ih.pitflg & 1) + { + d->pitflg &= ~EF_ON; +#ifdef MIKMOD_DEBUG + fputs ("\rFilter envelopes not supported yet\n", stderr); +#endif + } + + /* gather sample information */ + for (u = 0; u < ih.numsmp; u++, s++) + { + /* allocate more room for sample information if necessary */ + if (of.numsmp + u == wavcnt) + { + wavcnt += IMF_SMPINCR; + if (!(nextwav = realloc (nextwav, wavcnt * sizeof (ULONG)))) + { + if (wh) + free (wh); + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + if (!(wh = realloc (wh, wavcnt * sizeof (IMFWAVHEADER)))) + { + free (nextwav); + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + s = wh + (wavcnt - IMF_SMPINCR); + } + + _mm_read_string (s->samplename, 13, modreader); + _mm_read_UBYTE (modreader); + _mm_read_UBYTE (modreader); + _mm_read_UBYTE (modreader); + s->length = _mm_read_I_ULONG (modreader); + s->loopstart = _mm_read_I_ULONG (modreader); + s->loopend = _mm_read_I_ULONG (modreader); + s->samplerate = _mm_read_I_ULONG (modreader); + s->volume = _mm_read_UBYTE (modreader) & 0x7f; + s->pan = _mm_read_UBYTE (modreader); + _mm_fseek (modreader, 14, SEEK_CUR); + s->flags = _mm_read_UBYTE (modreader); + _mm_fseek (modreader, 11, SEEK_CUR); + _mm_read_UBYTES (id, 4, modreader); + if (((memcmp (id, "IS10", 4)) && (memcmp (id, "IW10", 4))) || + (_mm_eof (modreader))) + { + free (nextwav); + free (wh); + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + nextwav[of.numsmp + u] = _mm_ftell (modreader); + _mm_fseek (modreader, s->length, SEEK_CUR); + } + + of.numsmp += ih.numsmp; + d++; + } + + /* sanity check */ + if (!of.numsmp) + { + if (nextwav) + free (nextwav); + if (wh) + free (wh); + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + /* load samples */ + if (!AllocSamples ()) + { + free (nextwav); + free (wh); + return 0; + } + if (!AllocLinear ()) + { + free (nextwav); + free (wh); + return 0; + } + q = of.samples; + s = wh; + for (u = 0; u < of.numsmp; u++, s++, q++) + { + q->samplename = DupStr (s->samplename, 12, 1); + q->length = s->length; + q->loopstart = s->loopstart; + q->loopend = s->loopend; + q->volume = s->volume; + q->speed = s->samplerate; + if (of.flags & UF_LINEAR) + q->speed = speed_to_finetune (s->samplerate << 1, u); + q->panning = s->pan; + q->seekpos = nextwav[u]; + + q->flags |= SF_SIGNED; + if (s->flags & 0x1) + q->flags |= SF_LOOP; + if (s->flags & 0x2) + q->flags |= SF_BIDI; + if (s->flags & 0x8) + q->flags |= SF_OWNPAN; + if (s->flags & 0x4) + { + q->flags |= SF_16BITS; + q->length >>= 1; + q->loopstart >>= 1; + q->loopend >>= 1; + } + } + + d = of.instruments; + s = wh; + for (u = 0; u < of.numins; u++, d++) + { + for (t = 0; t < IMFNOTECNT; t++) + { + if (d->samplenumber[t] >= of.numsmp) + d->samplenote[t] = 255; + else if (of.flags & UF_LINEAR) + { + int note = (int) d->samplenote[u] + noteindex[d->samplenumber[u]]; + d->samplenote[u] = (note < 0) ? 0 : (note > 255 ? 255 : note); + } + else + d->samplenote[t] = t; + } + } + + free (wh); + free (nextwav); + return 1; +} + +CHAR * +IMF_LoadTitle (void) +{ + CHAR s[31]; + + _mm_fseek (modreader, 0, SEEK_SET); + if (!_mm_read_UBYTES (s, 31, modreader)) + return NULL; + + return (DupStr (s, 31, 1)); +} + +/*========== Loader information */ + +MLOADER load_imf = +{ + NULL, + "IMF", + "IMF (Imago Orpheus)", + IMF_Init, + IMF_Test, + IMF_Load, + IMF_Cleanup, + IMF_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_it.c TiMidity++-2.9.0/libunimod/load_it.c --- TiMidity++-2.8.2/libunimod/load_it.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_it.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,1130 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_it.c,v 1.39 1999/10/25 16:31:41 miod Exp $ + + Impulse tracker (IT) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +/* header */ +typedef struct ITHEADER + { + CHAR songname[26]; + UBYTE blank01[2]; + UWORD ordnum; + UWORD insnum; + UWORD smpnum; + UWORD patnum; + UWORD cwt; /* Created with tracker (y.xx = 0x0yxx) */ + UWORD cmwt; /* Compatible with tracker ver > than val. */ + UWORD flags; + UWORD special; /* bit 0 set = song message attached */ + UBYTE globvol; + UBYTE mixvol; /* mixing volume [ignored] */ + UBYTE initspeed; + UBYTE inittempo; + UBYTE pansep; /* panning separation between channels */ + UBYTE zerobyte; + UWORD msglength; + ULONG msgoffset; + UBYTE blank02[4]; + UBYTE pantable[64]; + UBYTE voltable[64]; + } +ITHEADER; + +/* sample information */ +typedef struct ITSAMPLE + { + CHAR filename[12]; + UBYTE zerobyte; + UBYTE globvol; + UBYTE flag; + UBYTE volume; + UBYTE panning; + CHAR sampname[28]; + UWORD convert; /* sample conversion flag */ + ULONG length; + ULONG loopbeg; + ULONG loopend; + ULONG c5spd; + ULONG susbegin; + ULONG susend; + ULONG sampoffset; + UBYTE vibspeed; + UBYTE vibdepth; + UBYTE vibrate; + UBYTE vibwave; /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */ + } +ITSAMPLE; + +/* instrument information */ + +#define ITENVCNT 25 +#define ITNOTECNT 120 +typedef struct ITINSTHEADER + { + ULONG size; /* (dword) Instrument size */ + CHAR filename[12]; /* (char) Instrument filename */ + UBYTE zerobyte; /* (byte) Instrument type (always 0) */ + UBYTE volflg; + UBYTE volpts; + UBYTE volbeg; /* (byte) Volume loop start (node) */ + UBYTE volend; /* (byte) Volume loop end (node) */ + UBYTE volsusbeg; /* (byte) Volume sustain begin (node) */ + UBYTE volsusend; /* (byte) Volume Sustain end (node) */ + UBYTE panflg; + UBYTE panpts; + UBYTE panbeg; /* (byte) channel loop start (node) */ + UBYTE panend; /* (byte) channel loop end (node) */ + UBYTE pansusbeg; /* (byte) channel sustain begin (node) */ + UBYTE pansusend; /* (byte) channel Sustain end (node) */ + UBYTE pitflg; + UBYTE pitpts; + UBYTE pitbeg; /* (byte) pitch loop start (node) */ + UBYTE pitend; /* (byte) pitch loop end (node) */ + UBYTE pitsusbeg; /* (byte) pitch sustain begin (node) */ + UBYTE pitsusend; /* (byte) pitch Sustain end (node) */ + UWORD blank; + UBYTE globvol; + UBYTE chanpan; + UWORD fadeout; /* Envelope end / NNA volume fadeout */ + UBYTE dnc; /* Duplicate note check */ + UBYTE dca; /* Duplicate check action */ + UBYTE dct; /* Duplicate check type */ + UBYTE nna; /* New Note Action [0,1,2,3] */ + UWORD trkvers; /* tracker version used to save [files only] */ + UBYTE ppsep; /* Pitch-pan Separation */ + UBYTE ppcenter; /* Pitch-pan Center */ + UBYTE rvolvar; /* random volume varations */ + UBYTE rpanvar; /* random panning varations */ + UWORD numsmp; /* Number of samples in instrument [files only] */ + CHAR name[26]; /* Instrument name */ + UBYTE blank01[6]; + UWORD samptable[ITNOTECNT]; /* sample for each note [note / samp pairs] */ + UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */ + UBYTE oldvoltick[ITENVCNT]; /* volume tick position (IT 1.x stuff) */ + UBYTE volnode[ITENVCNT]; /* amplitude of volume nodes */ + UWORD voltick[ITENVCNT]; /* tick value of volume nodes */ + SBYTE pannode[ITENVCNT]; /* panenv - node points */ + UWORD pantick[ITENVCNT]; /* tick value of panning nodes */ + SBYTE pitnode[ITENVCNT]; /* pitchenv - node points */ + UWORD pittick[ITENVCNT]; /* tick value of pitch nodes */ + } +ITINSTHEADER; + +/* unpacked note */ + +typedef struct ITNOTE + { + UBYTE note, ins, volpan, cmd, inf; + } +ITNOTE; + +/*========== Loader data */ + +static ULONG *paraptr = NULL; /* parapointer array (see IT docs) */ +static ITHEADER *mh = NULL; +static ITNOTE *itpat = NULL; /* allocate to space for one full pattern */ +static UBYTE *mask = NULL; /* arrays allocated to 64 elements and used for */ +static ITNOTE *last = NULL; /* uncompressing IT's pattern information */ +static int numtrk = 0; +static int old_effect; /* if set, use S3M old-effects stuffs */ + +static CHAR *IT_Version[] = +{ + "ImpulseTracker . ", + "Compressed ImpulseTracker . ", + "ImpulseTracker 2.14p3", + "Compressed ImpulseTracker 2.14p3", + "ImpulseTracker 2.14p4", + "Compressed ImpulseTracker 2.14p4", +}; + +/* table for porta-to-note command within volume/panning column */ +static UBYTE portatable[10] = +{0, 1, 4, 8, 16, 32, 64, 96, 128, 255}; + +/*========== Loader code */ + +BOOL +IT_Test (void) +{ + UBYTE id[4]; + + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + if (!memcmp (id, "IMPM", 4)) + return 1; + return 0; +} + +BOOL +IT_Init (void) +{ + if (!(mh = (ITHEADER *) _mm_malloc (sizeof (ITHEADER)))) + return 0; + if (!(poslookup = (UBYTE *) _mm_malloc (256 * sizeof (UBYTE)))) + return 0; + if (!(itpat = (ITNOTE *) _mm_malloc (200 * 64 * sizeof (ITNOTE)))) + return 0; + if (!(mask = (UBYTE *) _mm_malloc (64 * sizeof (UBYTE)))) + return 0; + if (!(last = (ITNOTE *) _mm_malloc (64 * sizeof (ITNOTE)))) + return 0; + + return 1; +} + +void +IT_Cleanup (void) +{ + FreeLinear (); + + _mm_free (mh); + _mm_free (poslookup); + _mm_free (itpat); + _mm_free (mask); + _mm_free (last); + _mm_free (paraptr); + _mm_free (origpositions); +} + +/* Because so many IT files have 64 channels as the set number used, but really + only use far less (usually from 8 to 24 still), I had to make this function, + which determines the number of channels that are actually USED by a pattern. + + NOTE: You must first seek to the file location of the pattern before calling + this procedure. + + Returns 1 on error + */ +static BOOL +IT_GetNumChannels (UWORD patrows) +{ + int row = 0, flag, ch; + + do + { + if ((flag = _mm_read_UBYTE (modreader)) == EOF) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 1; + } + if (!flag) + row++; + else + { + ch = (flag - 1) & 63; + remap[ch] = 0; + if (flag & 128) + mask[ch] = _mm_read_UBYTE (modreader); + if (mask[ch] & 1) + _mm_read_UBYTE (modreader); + if (mask[ch] & 2) + _mm_read_UBYTE (modreader); + if (mask[ch] & 4) + _mm_read_UBYTE (modreader); + if (mask[ch] & 8) + { + _mm_read_UBYTE (modreader); + _mm_read_UBYTE (modreader); + } + } + } + while (row < patrows); + + return 0; +} + +static UBYTE * +IT_ConvertTrack (ITNOTE * tr, UWORD numrows) +{ + int t; + UBYTE note, ins, volpan; + + UniReset (); + + for (t = 0; t < numrows; t++) + { + note = tr[t * of.numchn].note; + ins = tr[t * of.numchn].ins; + volpan = tr[t * of.numchn].volpan; + + if (note != 255) + { + if (note == 253) + UniWriteByte (UNI_KEYOFF); + else if (note == 254) + { + UniPTEffect (0xc, -1); /* note cut command */ + volpan = 255; + } + else + UniNote (note); + } + + if ((ins) && (ins < 100)) + UniInstrument (ins - 1); + else if (ins == 253) + UniWriteByte (UNI_KEYOFF); + else if (ins != 255) + { /* crap */ + _mm_errno = MMERR_LOADING_PATTERN; + return NULL; + } + + /* process volume / panning column + volume / panning effects do NOT all share the same memory address + yet. */ + if (volpan <= 64) + UniVolEffect (VOL_VOLUME, volpan); + else if (volpan <= 74) /* fine volume slide up (65-74) */ + UniVolEffect (VOL_VOLSLIDE, 0x0f + ((volpan - 65) << 4)); + else if (volpan <= 84) /* fine volume slide down (75-84) */ + UniVolEffect (VOL_VOLSLIDE, 0xf0 + (volpan - 75)); + else if (volpan <= 94) /* volume slide up (85-94) */ + UniVolEffect (VOL_VOLSLIDE, ((volpan - 85) << 4)); + else if (volpan <= 104) /* volume slide down (95-104) */ + UniVolEffect (VOL_VOLSLIDE, (volpan - 95)); + else if (volpan <= 114) /* pitch slide down (105-114) */ + UniVolEffect (VOL_PITCHSLIDEDN, (volpan - 105)); + else if (volpan <= 124) /* pitch slide up (115-124) */ + UniVolEffect (VOL_PITCHSLIDEUP, (volpan - 115)); + else if (volpan <= 127) + { /* crap */ + _mm_errno = MMERR_LOADING_PATTERN; + return NULL; + } + else if (volpan <= 192) + UniVolEffect (VOL_PANNING, ((volpan - 128) == 64) ? 255 : ((volpan - 128) << 2)); + else if (volpan <= 202) /* portamento to note */ + UniVolEffect (VOL_PORTAMENTO, portatable[volpan - 193]); + else if (volpan <= 212) /* vibrato */ + UniVolEffect (VOL_VIBRATO, (volpan - 203)); + else if ((volpan != 239) && (volpan != 255)) + { /* crap */ + _mm_errno = MMERR_LOADING_PATTERN; + return NULL; + } + + S3MIT_ProcessCmd (tr[t * of.numchn].cmd, tr[t * of.numchn].inf, old_effect | 2); + + UniNewline (); + } + return UniDup (); +} + +static BOOL +IT_ReadPattern (UWORD patrows) +{ + int row = 0, flag, ch, blah; + ITNOTE *itt = itpat, dummy, *n, *l; + + memset (itt, 255, 200 * 64 * sizeof (ITNOTE)); + + do + { + if ((flag = _mm_read_UBYTE (modreader)) == EOF) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + if (!flag) + { + itt = &itt[of.numchn]; + row++; + } + else + { + ch = remap[(flag - 1) & 63]; + if (ch != -1) + { + n = &itt[ch]; + l = &last[ch]; + } + else + n = l = &dummy; + + if (flag & 128) + mask[ch] = _mm_read_UBYTE (modreader); + if (mask[ch] & 1) + /* convert IT note off to internal note off */ + if ((l->note = n->note = _mm_read_UBYTE (modreader)) == 255) + l->note = n->note = 253; + if (mask[ch] & 2) + l->ins = n->ins = _mm_read_UBYTE (modreader); + if (mask[ch] & 4) + l->volpan = n->volpan = _mm_read_UBYTE (modreader); + if (mask[ch] & 8) + { + l->cmd = n->cmd = _mm_read_UBYTE (modreader); + l->inf = n->inf = _mm_read_UBYTE (modreader); + } + if (mask[ch] & 16) + n->note = l->note; + if (mask[ch] & 32) + n->ins = l->ins; + if (mask[ch] & 64) + n->volpan = l->volpan; + if (mask[ch] & 128) + { + n->cmd = l->cmd; + n->inf = l->inf; + } + } + } + while (row < patrows); + + for (blah = 0; blah < of.numchn; blah++) + { + if (!(of.tracks[numtrk++] = IT_ConvertTrack (&itpat[blah], patrows))) + return 0; + } + + return 1; +} + +static void +LoadMidiString (URL modreader, CHAR * dest) +{ + CHAR *cur, *last; + + _mm_read_UBYTES (dest, 32, modreader); + cur = last = dest; + /* remove blanks and uppercase all */ + while (*last) + { + if (isalnum ((int) *last)) + *(cur++) = toupper ((int) *last); + last++; + } + *cur = 0; +} + +/* Load embedded midi information for resonant filters */ +static void +IT_LoadMidiConfiguration (URL modreader) +{ + int i; + + memset (filtermacros, 0, sizeof (filtermacros)); + memset (filtersettings, 0, sizeof (filtersettings)); + + if (modreader) + { /* information is embedded in file */ + UWORD dat; + CHAR midiline[33]; + + dat = _mm_read_I_UWORD (modreader); + _mm_fseek (modreader, 8 * dat + 0x120, SEEK_CUR); + + /* read midi macros */ + for (i = 0; i < 16; i++) + { + LoadMidiString (modreader, midiline); + if ((!strncmp (midiline, "F0F00", 5)) && + ((midiline[5] == '0') || (midiline[5] == '1'))) + filtermacros[i] = (midiline[5] - '0') | 0x80; + } + + /* read standalone filters */ + for (i = 0x80; i < 0x100; i++) + { + LoadMidiString (modreader, midiline); + if ((!strncmp (midiline, "F0F00", 5)) && + ((midiline[5] == '0') || (midiline[5] == '1'))) + { + filtersettings[i].filter = (midiline[5] - '0') | 0x80; + dat = (midiline[6]) ? (midiline[6] - '0') : 0; + if (midiline[7]) + dat = (dat << 4) | (midiline[7] - '0'); + filtersettings[i].inf = dat; + } + } + } + else + { /* use default information */ + filtermacros[0] = FILT_CUT; + for (i = 0x80; i < 0x90; i++) + { + filtersettings[i].filter = FILT_RESONANT; + filtersettings[i].inf = (i & 0x7f) << 3; + } + } + activemacro = 0; + for (i = 0; i < 0x80; i++) + { + filtersettings[i].filter = filtermacros[0]; + filtersettings[i].inf = i; + } +} + +BOOL +IT_Load (BOOL curious) +{ + int t, u, lp; + INSTRUMENT *d; + SAMPLE *q; + BOOL compressed = 0; + + numtrk = 0; + filters = 0; + + /* try to read module header */ + _mm_read_I_ULONG (modreader); /* kill the 4 byte header */ + _mm_read_string (mh->songname, 26, modreader); + _mm_read_UBYTES (mh->blank01, 2, modreader); + mh->ordnum = _mm_read_I_UWORD (modreader); + mh->insnum = _mm_read_I_UWORD (modreader); + mh->smpnum = _mm_read_I_UWORD (modreader); + mh->patnum = _mm_read_I_UWORD (modreader); + mh->cwt = _mm_read_I_UWORD (modreader); + mh->cmwt = _mm_read_I_UWORD (modreader); + mh->flags = _mm_read_I_UWORD (modreader); + mh->special = _mm_read_I_UWORD (modreader); + mh->globvol = _mm_read_UBYTE (modreader); + mh->mixvol = _mm_read_UBYTE (modreader); + mh->initspeed = _mm_read_UBYTE (modreader); + mh->inittempo = _mm_read_UBYTE (modreader); + mh->pansep = _mm_read_UBYTE (modreader); + mh->zerobyte = _mm_read_UBYTE (modreader); + mh->msglength = _mm_read_I_UWORD (modreader); + mh->msgoffset = _mm_read_I_ULONG (modreader); + _mm_read_UBYTES (mh->blank02, 4, modreader); + _mm_read_UBYTES (mh->pantable, 64, modreader); + _mm_read_UBYTES (mh->voltable, 64, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.songname = DupStr (mh->songname, 26, 0); /* make a cstr of songname */ + of.reppos = 0; + of.numpat = mh->patnum; + of.numins = mh->insnum; + of.numsmp = mh->smpnum; + of.initspeed = mh->initspeed; + of.inittempo = mh->inittempo; + of.initvolume = mh->globvol; + of.flags |= UF_BGSLIDES | UF_ARPMEM; + + if (mh->songname[25]) + { + of.numvoices = 1 + mh->songname[25]; +#ifdef MIKMOD_DEBUG + fprintf (stderr, "Embedded IT limitation to %d voices\n", of.numvoices); +#endif + } + + /* set the module type */ + /* 2.17 : IT 2.14p4 */ + /* 2.16 : IT 2.14p3 with resonant filters */ + /* 2.15 : IT 2.14p3 (improved compression) */ + if ((mh->cwt <= 0x219) && (mh->cwt >= 0x217)) + of.modtype = strdup (IT_Version[mh->cmwt < 0x214 ? 4 : 5]); + else if (mh->cwt >= 0x215) + of.modtype = strdup (IT_Version[mh->cmwt < 0x214 ? 2 : 3]); + else + { + of.modtype = strdup (IT_Version[mh->cmwt < 0x214 ? 0 : 1]); + of.modtype[mh->cmwt < 0x214 ? 15 : 26] = (mh->cwt >> 8) + '0'; + of.modtype[mh->cmwt < 0x214 ? 17 : 28] = ((mh->cwt >> 4) & 0xf) + '0'; + of.modtype[mh->cmwt < 0x214 ? 18 : 29] = ((mh->cwt) & 0xf) + '0'; + } + + if (mh->flags & 8) + of.flags |= (UF_XMPERIODS | UF_LINEAR); + + if ((mh->cwt >= 0x106) && (mh->flags & 16)) + old_effect = 1; + else + old_effect = 0; + + /* set panning positions */ + for (t = 0; t < 64; t++) + { + mh->pantable[t] &= 0x7f; + if (mh->pantable[t] < 64) + of.panning[t] = mh->pantable[t] << 2; + else if (mh->pantable[t] == 64) + of.panning[t] = 255; + else if (mh->pantable[t] == 100) + of.panning[t] = PAN_SURROUND; + else if (mh->pantable[t] == 127) + of.panning[t] = PAN_CENTER; + else + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + } + + /* set channel volumes */ + memcpy (of.chanvol, mh->voltable, 64); + + /* read the order data */ + if (!AllocPositions (mh->ordnum)) + return 0; + if (!(origpositions = _mm_calloc (mh->ordnum, sizeof (UWORD)))) + return 0; + + for (t = 0; t < mh->ordnum; t++) + { + origpositions[t] = _mm_read_UBYTE (modreader); + if ((origpositions[t] > mh->patnum) && (origpositions[t] < 254)) + origpositions[t] = 255; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + poslookupcnt = mh->ordnum; + S3MIT_CreateOrders (curious); + + if (!(paraptr = (ULONG *) _mm_malloc ((mh->insnum + mh->smpnum + of.numpat) * + sizeof (ULONG)))) + return 0; + + /* read the instrument, sample, and pattern parapointers */ + _mm_read_I_ULONGS (paraptr, mh->insnum + mh->smpnum + of.numpat, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* Check for and load midi information for resonant filters */ + if (mh->cmwt >= 0x216) + { + if (mh->special & 8) + { + IT_LoadMidiConfiguration (modreader); + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + } + else + IT_LoadMidiConfiguration (NULL); + filters = 1; + } + + /* Check for and load song comment */ + if ((mh->special & 1) && (mh->cwt >= 0x104) && (mh->msglength)) + { + _mm_fseek (modreader, (long) (mh->msgoffset), SEEK_SET); + if (!ReadComment (mh->msglength)) + return 0; + } + + if (!(mh->flags & 4)) + of.numins = of.numsmp; + if (!AllocSamples ()) + return 0; + + if (!AllocLinear ()) + return 0; + + /* Load all samples */ + q = of.samples; + for (t = 0; t < mh->smpnum; t++) + { + ITSAMPLE s; + + /* seek to sample position */ + _mm_fseek (modreader, (long) (paraptr[mh->insnum + t] + 4), SEEK_SET); + + /* load sample info */ + _mm_read_string (s.filename, 12, modreader); + s.zerobyte = _mm_read_UBYTE (modreader); + s.globvol = _mm_read_UBYTE (modreader); + s.flag = _mm_read_UBYTE (modreader); + s.volume = _mm_read_UBYTE (modreader); + _mm_read_string (s.sampname, 26, modreader); + s.convert = _mm_read_UBYTE (modreader); + s.panning = _mm_read_UBYTE (modreader); + s.length = _mm_read_I_ULONG (modreader); + s.loopbeg = _mm_read_I_ULONG (modreader); + s.loopend = _mm_read_I_ULONG (modreader); + s.c5spd = _mm_read_I_ULONG (modreader); + s.susbegin = _mm_read_I_ULONG (modreader); + s.susend = _mm_read_I_ULONG (modreader); + s.sampoffset = _mm_read_I_ULONG (modreader); + s.vibspeed = _mm_read_UBYTE (modreader); + s.vibdepth = _mm_read_UBYTE (modreader); + s.vibrate = _mm_read_UBYTE (modreader); + s.vibwave = _mm_read_UBYTE (modreader); + + /* Generate an error if c5spd is > 512k, or samplelength > 256 megs + (nothing would EVER be that high) */ + + if (_mm_eof (modreader) || (s.c5spd > 0x7ffffL) || (s.length > 0xfffffffUL) || + (s.loopbeg > 0xfffffffUL) || (s.loopend > 0xfffffffUL)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr (s.sampname, 26, 0); + q->speed = s.c5spd / 2; + q->panning = ((s.panning & 127) == 64) ? 255 : (s.panning & 127) << 2; + q->length = s.length; + q->loopstart = s.loopbeg; + q->loopend = s.loopend; + q->volume = s.volume; + q->globvol = s.globvol; + q->seekpos = s.sampoffset; + + /* Convert speed to XM linear finetune */ + if (of.flags & UF_LINEAR) + q->speed = speed_to_finetune (s.c5spd, t); + + if (s.panning & 128) + q->flags |= SF_OWNPAN; + + if (s.vibrate) + { + q->vibflags |= AV_IT; + q->vibtype = s.vibwave; + q->vibsweep = s.vibrate * 2; + q->vibdepth = s.vibdepth; + q->vibrate = s.vibspeed; + } + + if (s.flag & 2) + q->flags |= SF_16BITS; + if ((s.flag & 8) && (mh->cwt >= 0x214)) + { + q->flags |= SF_ITPACKED; + compressed = 1; + } + if (s.flag & 16) + q->flags |= SF_LOOP; + if (s.flag & 64) + q->flags |= SF_BIDI; + + if (mh->cwt >= 0x200) + { + if (s.convert & 1) + q->flags |= SF_SIGNED; + if (s.convert & 4) + q->flags |= SF_DELTA; + } + + q++; + } + + /* Load instruments if instrument mode flag enabled */ + if (mh->flags & 4) + { + if (!AllocInstruments ()) + return 0; + d = of.instruments; + of.flags |= UF_NNA | UF_INST; + + for (t = 0; t < mh->insnum; t++) + { + ITINSTHEADER ih; + + /* seek to instrument position */ + _mm_fseek (modreader, paraptr[t] + 4, SEEK_SET); + + /* load instrument info */ + _mm_read_string (ih.filename, 12, modreader); + ih.zerobyte = _mm_read_UBYTE (modreader); + if (mh->cwt < 0x200) + { + /* load IT 1.xx inst header */ + ih.volflg = _mm_read_UBYTE (modreader); + ih.volbeg = _mm_read_UBYTE (modreader); + ih.volend = _mm_read_UBYTE (modreader); + ih.volsusbeg = _mm_read_UBYTE (modreader); + ih.volsusend = _mm_read_UBYTE (modreader); + _mm_read_I_UWORD (modreader); + ih.fadeout = _mm_read_I_UWORD (modreader); + ih.nna = _mm_read_UBYTE (modreader); + ih.dnc = _mm_read_UBYTE (modreader); + } + else + { + /* Read IT200+ header */ + ih.nna = _mm_read_UBYTE (modreader); + ih.dct = _mm_read_UBYTE (modreader); + ih.dca = _mm_read_UBYTE (modreader); + ih.fadeout = _mm_read_I_UWORD (modreader); + ih.ppsep = _mm_read_UBYTE (modreader); + ih.ppcenter = _mm_read_UBYTE (modreader); + ih.globvol = _mm_read_UBYTE (modreader); + ih.chanpan = _mm_read_UBYTE (modreader); + ih.rvolvar = _mm_read_UBYTE (modreader); + ih.rpanvar = _mm_read_UBYTE (modreader); + } + + ih.trkvers = _mm_read_I_UWORD (modreader); + ih.numsmp = _mm_read_UBYTE (modreader); + _mm_read_UBYTE (modreader); + _mm_read_string (ih.name, 26, modreader); + _mm_read_UBYTES (ih.blank01, 6, modreader); + _mm_read_I_UWORDS (ih.samptable, ITNOTECNT, modreader); + if (mh->cwt < 0x200) + { + /* load IT 1xx volume envelope */ + _mm_read_UBYTES (ih.volenv, 200, modreader); + for (lp = 0; lp < ITENVCNT; lp++) + { + ih.oldvoltick[lp] = _mm_read_UBYTE (modreader); + ih.volnode[lp] = _mm_read_UBYTE (modreader); + } + } + else + { + /* load IT 2xx volume, pan and pitch envelopes */ +#define IT_LoadEnvelope(name,type) \ + ih.##name##flg =_mm_read_UBYTE(modreader); \ + ih.##name##pts =_mm_read_UBYTE(modreader); \ + ih.##name##beg =_mm_read_UBYTE(modreader); \ + ih.##name##end =_mm_read_UBYTE(modreader); \ + ih.##name##susbeg=_mm_read_UBYTE(modreader); \ + ih.##name##susend=_mm_read_UBYTE(modreader); \ + for(lp=0;lpvolflg |= EF_VOLENV; + d->insname = DupStr (ih.name, 26, 0); + d->nnatype = ih.nna; + + if (mh->cwt < 0x200) + { + d->volfade = ih.fadeout << 6; + if (ih.dnc) + { + d->dct = DCT_NOTE; + d->dca = DCA_CUT; + } + + if (ih.volflg & 1) + d->volflg |= EF_ON; + if (ih.volflg & 2) + d->volflg |= EF_LOOP; + if (ih.volflg & 4) + d->volflg |= EF_SUSTAIN; + + /* XM conversion of IT envelope Array */ + d->volbeg = ih.volbeg; + d->volend = ih.volend; + d->volsusbeg = ih.volsusbeg; + d->volsusend = ih.volsusend; + + if (ih.volflg & 1) + { + for (u = 0; u < ITENVCNT; u++) + if (ih.oldvoltick[d->volpts] != 0xff) + { + d->volenv[d->volpts].val = (ih.volnode[d->volpts] << 2); + d->volenv[d->volpts].pos = ih.oldvoltick[d->volpts]; + d->volpts++; + } + else + break; + } + } + else + { + d->panning = ((ih.chanpan & 127) == 64) ? 255 : (ih.chanpan & 127) << 2; + if (!(ih.chanpan & 128)) + d->flags |= IF_OWNPAN; + + if (!(ih.ppsep & 128)) + { + d->pitpansep = ih.ppsep << 2; + d->pitpancenter = ih.ppcenter; + d->flags |= IF_PITCHPAN; + } + d->globvol = ih.globvol >> 1; + d->volfade = ih.fadeout << 5; + d->dct = ih.dct; + d->dca = ih.dca; + + if (mh->cwt >= 0x204) + { + d->rvolvar = ih.rvolvar; + d->rpanvar = ih.rpanvar; + } + +#define IT_ProcessEnvelope(name) \ + if(ih.##name##flg&1) d->##name##flg|=EF_ON; \ + if(ih.##name##flg&2) d->##name##flg|=EF_LOOP; \ + if(ih.##name##flg&4) d->##name##flg|=EF_SUSTAIN; \ + d->##name##pts=ih.##name##pts; \ + d->##name##beg=ih.##name##beg; \ + d->##name##end=ih.##name##end; \ + d->##name##susbeg=ih.##name##susbeg; \ + d->##name##susend=ih.##name##susend; \ + \ + for(u=0;u##name##env[u].pos=ih.##name##tick[u]; \ + \ + if((d->##name##flg&EF_ON)&&(d->##name##pts<2)) \ + d->##name##flg&=~EF_ON; + + IT_ProcessEnvelope (vol); + for (u = 0; u < ih.volpts; u++) + d->volenv[u].val = (ih.volnode[u] << 2); + + IT_ProcessEnvelope (pan); + for (u = 0; u < ih.panpts; u++) + d->panenv[u].val = + ih.pannode[u] == 32 ? 255 : (ih.pannode[u] + 32) << 2; + + IT_ProcessEnvelope (pit); + for (u = 0; u < ih.pitpts; u++) + d->pitenv[u].val = ih.pitnode[u] + 32; +#undef IT_ProcessEnvelope + + if (ih.pitflg & 0x80) + { + /* filter envelopes not supported yet */ + d->pitflg &= ~EF_ON; + ih.pitpts = ih.pitbeg = ih.pitend = 0; +#ifdef MIKMOD_DEBUG + { + static int warn = 0; + + if (!warn) + fputs ("\rFilter envelopes not supported yet\n", stderr); + warn = 1; + } +#endif + } + + d->volpts = ih.volpts; + d->volbeg = ih.volbeg; + d->volend = ih.volend; + d->volsusbeg = ih.volsusbeg; + d->volsusend = ih.volsusend; + + for (u = 0; u < ih.volpts; u++) + { + d->volenv[u].val = (ih.volnode[u] << 2); + d->volenv[u].pos = ih.voltick[u]; + } + + d->panpts = ih.panpts; + d->panbeg = ih.panbeg; + d->panend = ih.panend; + d->pansusbeg = ih.pansusbeg; + d->pansusend = ih.pansusend; + + for (u = 0; u < ih.panpts; u++) + { + d->panenv[u].val = ih.pannode[u] == 32 ? 255 : (ih.pannode[u] + 32) << 2; + d->panenv[u].pos = ih.pantick[u]; + } + + d->pitpts = ih.pitpts; + d->pitbeg = ih.pitbeg; + d->pitend = ih.pitend; + d->pitsusbeg = ih.pitsusbeg; + d->pitsusend = ih.pitsusend; + + for (u = 0; u < ih.pitpts; u++) + { + d->pitenv[u].val = ih.pitnode[u] + 32; + d->pitenv[u].pos = ih.pittick[u]; + } + } + + for (u = 0; u < ITNOTECNT; u++) + { + d->samplenote[u] = (ih.samptable[u] & 255); + d->samplenumber[u] = + (ih.samptable[u] >> 8) ? ((ih.samptable[u] >> 8) - 1) : 0xffff; + if (d->samplenumber[u] >= of.numsmp) + d->samplenote[u] = 255; + else if (of.flags & UF_LINEAR) + { + int note = (int) d->samplenote[u] + noteindex[d->samplenumber[u]]; + d->samplenote[u] = (note < 0) ? 0 : (note > 255 ? 255 : note); + } + } + + d++; + } + } + else if (of.flags & UF_LINEAR) + { + if (!AllocInstruments ()) + return 0; + d = of.instruments; + of.flags |= UF_INST; + + for (t = 0; t < mh->smpnum; t++, d++) + for (u = 0; u < ITNOTECNT; u++) + { + if (d->samplenumber[u] >= of.numsmp) + d->samplenote[u] = 255; + else + { + int note = (int) d->samplenote[u] + noteindex[d->samplenumber[u]]; + d->samplenote[u] = (note < 0) ? 0 : (note > 255 ? 255 : note); + } + } + } + + /* Figure out how many channels this song actually uses */ + of.numchn = 0; + memset (remap, -1, 64 * sizeof (UBYTE)); + for (t = 0; t < of.numpat; t++) + { + UWORD packlen; + + /* seek to pattern position */ + if (paraptr[mh->insnum + mh->smpnum + t]) + { /* 0 -> empty 64 row pattern */ + _mm_fseek (modreader, ((long) paraptr[mh->insnum + mh->smpnum + t]), SEEK_SET); + _mm_read_I_UWORD (modreader); + /* read pattern length (# of rows) + Impulse Tracker never creates patterns with less than 32 rows, + but some other trackers do, so we only check for more than 256 + rows */ + packlen = _mm_read_I_UWORD (modreader); + if (packlen > 256) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + _mm_read_I_ULONG (modreader); + if (IT_GetNumChannels (packlen)) + return 0; + } + } + + /* give each of them a different number */ + for (t = 0; t < 64; t++) + if (!remap[t]) + remap[t] = of.numchn++; + + of.numtrk = of.numpat * of.numchn; + if (of.numvoices) + if (of.numvoices < of.numchn) + of.numvoices = of.numchn; + + if (!AllocPatterns ()) + return 0; + if (!AllocTracks ()) + return 0; + + for (t = 0; t < of.numpat; t++) + { + UWORD packlen; + + /* seek to pattern position */ + if (!paraptr[mh->insnum + mh->smpnum + t]) + { /* 0 -> empty 64 row pattern */ + of.pattrows[t] = 64; + for (u = 0; u < of.numchn; u++) + { + int k; + + UniReset (); + for (k = 0; k < 64; k++) + UniNewline (); + of.tracks[numtrk++] = UniDup (); + } + } + else + { + _mm_fseek (modreader, ((long) paraptr[mh->insnum + mh->smpnum + t]), SEEK_SET); + packlen = _mm_read_I_UWORD (modreader); + of.pattrows[t] = _mm_read_I_UWORD (modreader); + _mm_read_I_ULONG (modreader); + if (!IT_ReadPattern (of.pattrows[t])) + return 0; + } + } + + return 1; +} + +CHAR * +IT_LoadTitle (void) +{ + CHAR s[26]; + + _mm_fseek (modreader, 4, SEEK_SET); + if (!_mm_read_UBYTES (s, 26, modreader)) + return NULL; + + return (DupStr (s, 26, 0)); +} + +/*========== Loader information */ + +MLOADER load_it = +{ + NULL, + "IT", + "IT (Impulse Tracker)", + IT_Init, + IT_Test, + IT_Load, + IT_Cleanup, + IT_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_m15.c TiMidity++-2.9.0/libunimod/load_m15.c --- TiMidity++-2.8.2/libunimod/load_m15.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_m15.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,577 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_m15.c,v 1.29 1999/10/25 16:31:41 miod Exp $ + + 15 instrument MOD loader + Also supports Ultimate Sound Tracker (old M15 format) + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module Structure */ + +typedef struct MSAMPINFO + { + CHAR samplename[23]; /* 22 in module, 23 in memory */ + UWORD length; + UBYTE finetune; + UBYTE volume; + UWORD reppos; + UWORD replen; + } +MSAMPINFO; + +typedef struct MODULEHEADER + { + CHAR songname[21]; /* the songname.., 20 in module, 21 in memory */ + MSAMPINFO samples[15]; /* all sampleinfo */ + UBYTE songlength; /* number of patterns used */ + UBYTE magic1; /* should be 127 */ + UBYTE positions[128]; /* which pattern to play at pos */ + } +MODULEHEADER; + +typedef struct MODNOTE + { + UBYTE a, b, c, d; + } +MODNOTE; + +/*========== Loader variables */ + +static MODULEHEADER *mh = NULL; +static MODNOTE *patbuf = NULL; +static BOOL ust_loader = 0; /* if TRUE, load as an ust module. */ + +/* known file formats which can confuse the loader */ +#define REJECT 2 +static char *signatures[REJECT] = +{ + "CAKEWALK", /* cakewalk midi files */ + "SZDD" /* Microsoft compressed files */ +}; +static int siglen[REJECT] = +{8, 4}; + +/*========== Loader code */ + +static BOOL +LoadModuleHeader (MODULEHEADER * mh) +{ + int t, u; + + _mm_read_string (mh->songname, 20, modreader); + mh->songname[20] = 0; /* just in case */ + + /* sanity check : title should contain printable characters and a bunch + of null chars */ + for (t = 0; t < 20; t++) + if ((mh->songname[t]) && (mh->songname[t] < 32)) + return 0; + for (t = 0; (mh->songname[t]) && (t < 20); t++); + if (t < 20) + for (; t < 20; t++) + if (mh->songname[t]) + return 0; + + for (t = 0; t < 15; t++) + { + MSAMPINFO *s = &mh->samples[t]; + + _mm_read_string (s->samplename, 22, modreader); + s->samplename[22] = 0; /* just in case */ + s->length = _mm_read_M_UWORD (modreader); + s->finetune = _mm_read_UBYTE (modreader); + s->volume = _mm_read_UBYTE (modreader); + s->reppos = _mm_read_M_UWORD (modreader); + s->replen = _mm_read_M_UWORD (modreader); + + /* sanity check : sample title should contain printable characters and + a bunch of null chars */ + for (u = 0; u < 20; u++) + if ((s->samplename[u]) && (s->samplename[u] < /*32 */ 14)) + return 0; + for (u = 0; (s->samplename[u]) && (u < 20); u++); + if (u < 20) + for (; u < 20; u++) + if (s->samplename[u]) + return 0; + + /* sanity check : finetune values */ + if (s->finetune >> 4) + return 0; + } + + mh->songlength = _mm_read_UBYTE (modreader); + mh->magic1 = _mm_read_UBYTE (modreader); /* should be 127 */ + + /* sanity check : no more than 128 positions, restart position in range */ + if ((!mh->songlength) || (mh->songlength > 128)) + return 0; + /* values encountered so far are 0x6a and 0x78 */ + if (((mh->magic1 & 0xf8) != 0x78) && (mh->magic1 != 0x6a) && (mh->magic1 > mh->songlength)) + return 0; + + _mm_read_UBYTES (mh->positions, 128, modreader); + + /* sanity check : pattern range is 0..63 */ + for (t = 0; t < 128; t++) + if (mh->positions[t] > 63) + return 0; + + return (!_mm_eof (modreader)); +} + +/* Checks the patterns in the modfile for UST / 15-inst indications. + For example, if an effect 3xx is found, it is assumed that the song + is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST. + + Returns: 0 indecisive; 1 = UST; 2 = 15-inst */ +static int +CheckPatternType (int numpat) +{ + int t; + UBYTE eff, dat; + + for (t = 0; t < numpat * (64U * 4); t++) + { + /* Load the pattern into the temp buffer and scan it */ + _mm_read_UBYTE (modreader); + _mm_read_UBYTE (modreader); + eff = _mm_read_UBYTE (modreader); + dat = _mm_read_UBYTE (modreader); + + switch (eff) + { + case 1: + if (dat > 0x1f) + return 1; + if (dat < 0x3) + return 2; + break; + case 2: + if (dat > 0x1f) + return 1; + return 2; + case 3: + if (dat) + return 2; + break; + default: + return 2; + } + } + return 0; +} + +static BOOL +M15_Test (void) +{ + int t, numpat; + MODULEHEADER mh; + + ust_loader = 0; + if (!LoadModuleHeader (&mh)) + return 0; + + /* reject other file types */ + for (t = 0; t < REJECT; t++) + if (!memcmp (mh.songname, signatures[t], siglen[t])) + return 0; + + if (mh.magic1 > 127) + return 0; + if ((!mh.songlength) || (mh.songlength > mh.magic1)) + return 0; + + for (t = 0; t < 15; t++) + { + /* all finetunes should be zero */ + if (mh.samples[t].finetune) + return 0; + + /* all volumes should be <= 64 */ + if (mh.samples[t].volume > 64) + return 0; + + /* all instrument names should begin with s, st-, or a number */ + if (mh.samples[t].samplename[0] == 's') + { + if ((memcmp (mh.samples[t].samplename, "st-", 3)) && + (memcmp (mh.samples[t].samplename, "ST-", 3)) && + (*mh.samples[t].samplename)) + ust_loader = 1; + } + else if ((mh.samples[t].samplename[0] < '0') || + (mh.samples[t].samplename[0] > '9')) + ust_loader = 1; + + if (mh.samples[t].length > 4999 || mh.samples[t].reppos > 9999) + { + ust_loader = 0; + if (mh.samples[t].length > 32768) + return 0; + } + + if (!ust_loader) + return 1; + + if ((mh.samples[t].reppos + mh.samples[t].replen) > (mh.samples[t].length + 10)) + { + ust_loader = 1; + return 1; + } + } + + for (numpat = 0, t = 0; t < mh.songlength; t++) + if (mh.positions[t] > numpat) + numpat = mh.positions[t]; + numpat++; + switch (CheckPatternType (numpat)) + { + case 0: /* indecisive, so check more clues... */ + break; + case 1: + ust_loader = 1; + break; + case 2: + ust_loader = 0; + break; + } + return 1; +} + +static BOOL +M15_Init (void) +{ + if (!(mh = (MODULEHEADER *) _mm_malloc (sizeof (MODULEHEADER)))) + return 0; + return 1; +} + +static void +M15_Cleanup (void) +{ + _mm_free (mh); + _mm_free (patbuf); +} + +/* + Old (amiga) noteinfo: + + _____byte 1_____ byte2_ _____byte 3_____ byte4_ + / \ / \ / \ / \ + 0000 0000-00000000 0000 0000-00000000 + + Upper four 12 bits for Lower four Effect command. + bits of sam- note period. bits of sam- + ple number. ple number. + */ + +static UWORD npertab[7 * OCTAVE] = +{ + /* -> Tuning 0 */ + 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906, + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56, + + 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28, + 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14 +}; + + +static void +M15_ConvertNote (MODNOTE * n) +{ + UBYTE instrument, effect, effdat, note; + UWORD period; + UBYTE lastnote = 0; + + /* decode the 4 bytes that make up a single note */ + instrument = n->c >> 4; + period = (((UWORD) n->a & 0xf) << 8) + n->b; + effect = n->c & 0xf; + effdat = n->d; + + /* Convert the period to a note number */ + note = 0; + if (period) + { + for (note = 0; note < 7 * OCTAVE; note++) + if (period >= npertab[note]) + break; + if (note == 7 * OCTAVE) + note = 0; + else + note++; + } + + if (instrument) + { + /* if instrument does not exist, note cut */ + if ((instrument > 15) || (!mh->samples[instrument - 1].length)) + { + UniPTEffect (0xc, 0); + if (effect == 0xc) + effect = effdat = 0; + } + else + { + /* if we had a note, then change instrument... */ + if (note) + UniInstrument (instrument - 1); + /* ...otherwise, only adjust volume... */ + else + { + /* ...unless an effect was specified, which forces a new note + to be played */ + if (effect || effdat) + { + UniInstrument (instrument - 1); + note = lastnote; + } + else + UniPTEffect (0xc, mh->samples[instrument - 1].volume & 0x7f); + } + } + } + if (note) + { + UniNote (note + 2 * OCTAVE - 1); + lastnote = note; + } + + /* Convert pattern jump from Dec to Hex */ + if (effect == 0xd) + effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf); + + /* Volume slide, up has priority */ + if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0)) + effdat &= 0xf0; + + if (ust_loader) + { + switch (effect) + { + case 0: + case 3: + break; + case 1: + UniPTEffect (0, effdat); + break; + case 2: + if (effdat & 0xf) + UniPTEffect (1, effdat & 0xf); + if (effdat >> 2) + UniPTEffect (2, effdat >> 2); + break; + default: + UniPTEffect (effect, effdat); + break; + } + } + else + UniPTEffect (effect, effdat); +} + +static UBYTE * +M15_ConvertTrack (MODNOTE * n) +{ + int t; + + UniReset (); + for (t = 0; t < 64; t++) + { + M15_ConvertNote (n); + UniNewline (); + n += 4; + } + return UniDup (); +} + +/* Loads all patterns of a modfile and converts them into the 3 byte format. */ +static BOOL +M15_LoadPatterns (void) +{ + int t, s, tracks = 0; + + if (!AllocPatterns ()) + return 0; + if (!AllocTracks ()) + return 0; + + /* Allocate temporary buffer for loading and converting the patterns */ + if (!(patbuf = (MODNOTE *) _mm_calloc (64U * 4, sizeof (MODNOTE)))) + return 0; + + for (t = 0; t < of.numpat; t++) + { + /* Load the pattern into the temp buffer and convert it */ + for (s = 0; s < (64U * 4); s++) + { + patbuf[s].a = _mm_read_UBYTE (modreader); + patbuf[s].b = _mm_read_UBYTE (modreader); + patbuf[s].c = _mm_read_UBYTE (modreader); + patbuf[s].d = _mm_read_UBYTE (modreader); + } + + for (s = 0; s < 4; s++) + if (!(of.tracks[tracks++] = M15_ConvertTrack (patbuf + s))) + return 0; + } + return 1; +} + +static BOOL +M15_Load (BOOL curious) +{ + int t, scan; + SAMPLE *q; + MSAMPINFO *s; + + /* try to read module header */ + if (!LoadModuleHeader (mh)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if (ust_loader) + of.modtype = strdup ("Ultimate Soundtracker"); + else + of.modtype = strdup ("Soundtracker"); + + /* set module variables */ + of.initspeed = 6; + of.inittempo = 125; + of.numchn = 4; + of.songname = DupStr (mh->songname, 21, 1); + of.numpos = mh->songlength; + of.reppos = 0; + + /* Count the number of patterns */ + of.numpat = 0; + for (t = 0; t < of.numpos; t++) + if (mh->positions[t] > of.numpat) + of.numpat = mh->positions[t]; + /* since some old modules embed extra patterns, we have to check the + whole list to get the samples' file offsets right - however we can find + garbage here, so check carefully */ + scan = 1; + for (t = of.numpos; t < 128; t++) + if (mh->positions[t] >= 0x80) + scan = 0; + if (scan) + for (t = of.numpos; t < 128; t++) + { + if (mh->positions[t] > of.numpat) + of.numpat = mh->positions[t]; + if ((curious) && (mh->positions[t])) + of.numpos = t + 1; + } + of.numpat++; + of.numtrk = of.numpat * of.numchn; + + if (!AllocPositions (of.numpos)) + return 0; + for (t = 0; t < of.numpos; t++) + of.positions[t] = mh->positions[t]; + + /* Finally, init the sampleinfo structures */ + of.numins = of.numsmp = 15; + if (!AllocSamples ()) + return 0; + + s = mh->samples; + q = of.samples; + + for (t = 0; t < of.numins; t++) + { + /* convert the samplename */ + q->samplename = DupStr (s->samplename, 23, 1); + + /* init the sampleinfo variables and convert the size pointers */ + q->speed = finetune[s->finetune & 0xf]; + q->volume = s->volume; + if (ust_loader) + q->loopstart = s->reppos; + else + q->loopstart = s->reppos << 1; + q->loopend = q->loopstart + (s->replen << 1); + q->length = s->length << 1; + + q->flags = SF_SIGNED | SF_UST_LOOP; + if (s->replen > 1) + q->flags |= SF_LOOP; + + /* fix replen if repend>length */ + if (q->loopend > q->length) + q->loopend = q->length; + + s++; + q++; + } + + if (!M15_LoadPatterns ()) + return 0; + ust_loader = 0; + + return 1; +} + +static CHAR * +M15_LoadTitle (void) +{ + CHAR s[21]; + + _mm_fseek (modreader, 0, SEEK_SET); + if (!_mm_read_UBYTES (s, 20, modreader)) + return NULL; + s[20] = 0; /* just in case */ + return (DupStr (s, 21, 1)); +} + +/*========== Loader information */ + +MLOADER load_m15 = +{ + NULL, + "15-instrument module", + "MOD (15 instrument)", + M15_Init, + M15_Test, + M15_Load, + M15_Cleanup, + M15_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_med.c TiMidity++-2.9.0/libunimod/load_med.c --- TiMidity++-2.8.2/libunimod/load_med.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_med.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,757 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_med.c,v 1.27 1999/10/25 16:31:41 miod Exp $ + + Amiga MED module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module information */ + +typedef struct MMD0 + { + ULONG id; + ULONG modlen; + ULONG MMD0songP; /* struct MMD0song *song; */ + UWORD psecnum; /* for the player routine, MMD2 only */ + UWORD pseq; /* " " " " */ + ULONG MMD0BlockPP; /* struct MMD0Block **blockarr; */ + ULONG reserved1; + ULONG InstrHdrPP; /* struct InstrHdr **smplarr; */ + ULONG reserved2; + ULONG MMD0expP; /* struct MMD0exp *expdata; */ + ULONG reserved3; + UWORD pstate; /* some data for the player routine */ + UWORD pblock; + UWORD pline; + UWORD pseqnum; + SWORD actplayline; + UBYTE counter; + UBYTE extra_songs; /* number of songs - 1 */ + } +MMD0; + +typedef struct MMD0sample + { + UWORD rep, replen; /* offs: 0(s), 2(s) */ + UBYTE midich; /* offs: 4(s) */ + UBYTE midipreset; /* offs: 5(s) */ + UBYTE svol; /* offs: 6(s) */ + SBYTE strans; /* offs: 7(s) */ + } +MMD0sample; + +typedef struct MMD0song + { + MMD0sample sample[63]; /* 63 * 8 bytes = 504 bytes */ + UWORD numblocks; /* offs: 504 */ + UWORD songlen; /* offs: 506 */ + UBYTE playseq[256]; /* offs: 508 */ + UWORD deftempo; /* offs: 764 */ + SBYTE playtransp; /* offs: 766 */ + UBYTE flags; /* offs: 767 */ + UBYTE flags2; /* offs: 768 */ + UBYTE tempo2; /* offs: 769 */ + UBYTE trkvol[16]; /* offs: 770 */ + UBYTE mastervol; /* offs: 786 */ + UBYTE numsamples; /* offs: 787 */ + } +MMD0song; + +typedef struct MMD0exp + { + ULONG nextmod; /* pointer to next module */ + ULONG exp_smp; /* pointer to InstrExt array */ + UWORD s_ext_entries; + UWORD s_ext_entrsz; + ULONG annotxt; /* pointer to annotation text */ + ULONG annolen; + ULONG iinfo; /* pointer to InstrInfo array */ + UWORD i_ext_entries; + UWORD i_ext_entrsz; + ULONG jumpmask; + ULONG rgbtable; + ULONG channelsplit; + ULONG n_info; + ULONG songname; /* pointer to songname */ + ULONG songnamelen; + ULONG dumps; + ULONG reserved2[7]; + } +MMD0exp; + +typedef struct MMD0NOTE + { + UBYTE a, b, c; + } +MMD0NOTE; + +typedef struct MMD1NOTE + { + UBYTE a, b, c, d; + } +MMD1NOTE; + +typedef struct InstrHdr + { + ULONG length; + SWORD type; + /* Followed by actual data */ + } +InstrHdr; + +typedef struct InstrExt + { + UBYTE hold; + UBYTE decay; + UBYTE suppress_midi_off; + SBYTE finetune; + } +InstrExt; + +typedef struct InstrInfo + { + UBYTE name[40]; + } +InstrInfo; + +/*========== Loader variables */ + +#define MMD0_string 0x4D4D4430 +#define MMD1_string 0x4D4D4431 + +static MMD0 *mh = NULL; +static MMD0song *ms = NULL; +static MMD0exp *me = NULL; +static ULONG *ba = NULL; +static MMD0NOTE *mmd0pat = NULL; +static MMD1NOTE *mmd1pat = NULL; + +static BOOL decimalvolumes; +static BOOL bpmtempos; + +#define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)] +#define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)] + +static CHAR MED_Version[] = "OctaMED (MMDx)"; + +/*========== Loader code */ + +BOOL +MED_Test (void) +{ + UBYTE id[4]; + + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + if ((!memcmp (id, "MMD0", 4)) || (!memcmp (id, "MMD1", 4))) + return 1; + return 0; +} + +BOOL +MED_Init (void) +{ + if (!(me = (MMD0exp *) _mm_malloc (sizeof (MMD0exp)))) + return 0; + if (!(mh = (MMD0 *) _mm_malloc (sizeof (MMD0)))) + return 0; + if (!(ms = (MMD0song *) _mm_malloc (sizeof (MMD0song)))) + return 0; + return 1; +} + +void +MED_Cleanup (void) +{ + _mm_free (me); + _mm_free (mh); + _mm_free (ms); + _mm_free (ba); + _mm_free (mmd0pat); + _mm_free (mmd1pat); +} + +static void +EffectCvt (UBYTE eff, UBYTE dat) +{ + switch (eff) + { + /* 0x0 0x1 0x2 0x3 0x4 PT effects */ + case 0x5: /* PT vibrato with speed/depth nibbles swapped */ + UniPTEffect (0x4, (dat >> 4) | ((dat & 0xf) << 4)); + break; + /* 0x6 0x7 not used */ + case 0x6: + case 0x7: + break; + case 0x8: /* midi hold/decay */ + break; + case 0x9: + if (bpmtempos) + { + if (!dat) + dat = of.initspeed; + UniEffect (UNI_S3MEFFECTA, dat); + } + else + { + if (dat <= 0x20) + { + if (!dat) + dat = of.initspeed; + else + dat /= 4; + UniPTEffect (0xf, dat); + } + else + UniEffect (UNI_MEDSPEED, ((UWORD) dat * 125) / (33 * 4)); + } + break; + /* 0xa 0xb PT effects */ + case 0xc: + if (decimalvolumes) + dat = (dat >> 4) * 10 + (dat & 0xf); + UniPTEffect (0xc, dat); + break; + case 0xd: /* same as PT volslide */ + UniPTEffect (0xa, dat); + break; + case 0xe: /* synth jmp - midi */ + break; + case 0xf: + switch (dat) + { + case 0: /* patternbreak */ + UniPTEffect (0xd, 0); + break; + case 0xf1: /* play note twice */ + UniWriteByte (UNI_MEDEFFECTF1); + break; + case 0xf2: /* delay note */ + UniWriteByte (UNI_MEDEFFECTF2); + break; + case 0xf3: /* play note three times */ + UniWriteByte (UNI_MEDEFFECTF3); + break; + case 0xfe: /* stop playing */ + UniPTEffect (0xb, of.numpat); + break; + case 0xff: /* note cut */ + UniPTEffect (0xc, 0); + break; + default: + if (dat <= 10) + UniPTEffect (0xf, dat); + else if (dat <= 240) + { + if (bpmtempos) + UniPTEffect (0xf, (dat < 32) ? 32 : dat); + else + UniEffect (UNI_MEDSPEED, ((UWORD) dat * 125) / 33); + } + } + break; + default: /* all normal PT effects are handled here */ + UniPTEffect (eff, dat); + break; + } +} + +static UBYTE * +MED_Convert1 (int count, int col) +{ + int t; + UBYTE inst, note, eff, dat; + MMD1NOTE *n; + + UniReset (); + for (t = 0; t < count; t++) + { + n = &d1note (t, col); + + note = n->a & 0x7f; + inst = n->b & 0x3f; + eff = n->c & 0xf; + dat = n->d; + + if (inst) + UniInstrument (inst - 1); + if (note) + UniNote (note + 3 * OCTAVE - 1); + EffectCvt (eff, dat); + UniNewline (); + } + return UniDup (); +} + +static UBYTE * +MED_Convert0 (int count, int col) +{ + int t; + UBYTE a, b, inst, note, eff, dat; + MMD0NOTE *n; + + UniReset (); + for (t = 0; t < count; t++) + { + n = &d0note (t, col); + a = n->a; + b = n->b; + + note = a & 0x3f; + a >>= 6; + a = ((a & 1) << 1) | (a >> 1); + inst = (b >> 4) | (a << 4); + eff = b & 0xf; + dat = n->c; + + if (inst) + UniInstrument (inst - 1); + if (note) + UniNote (note + 3 * OCTAVE - 1); + EffectCvt (eff, dat); + UniNewline (); + } + return UniDup (); +} + +static BOOL +LoadMMD0Patterns (void) +{ + int t, row, col; + UWORD numtracks, numlines, maxlines = 0, track = 0; + MMD0NOTE *mmdp; + + /* first, scan patterns to see how many channels are used */ + for (t = 0; t < of.numpat; t++) + { + _mm_fseek (modreader, ba[t], SEEK_SET); + numtracks = _mm_read_UBYTE (modreader); + numlines = _mm_read_UBYTE (modreader); + + if (numtracks > of.numchn) + of.numchn = numtracks; + if (numlines > maxlines) + maxlines = numlines; + } + + of.numtrk = of.numpat * of.numchn; + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + if (!(mmd0pat = (MMD0NOTE *) _mm_calloc (of.numchn * (maxlines + 1), sizeof (MMD0NOTE)))) + return 0; + + /* second read: read and convert patterns */ + for (t = 0; t < of.numpat; t++) + { + _mm_fseek (modreader, ba[t], SEEK_SET); + numtracks = _mm_read_UBYTE (modreader); + numlines = _mm_read_UBYTE (modreader); + + of.pattrows[t] = ++numlines; + memset (mmdp = mmd0pat, 0, of.numchn * maxlines * sizeof (MMD0NOTE)); + for (row = numlines; row; row--) + { + for (col = numtracks; col; col--, mmdp++) + { + mmdp->a = _mm_read_UBYTE (modreader); + mmdp->b = _mm_read_UBYTE (modreader); + mmdp->c = _mm_read_UBYTE (modreader); + } + } + + for (col = 0; col < of.numchn; col++) + of.tracks[track++] = MED_Convert0 (numlines, col); + } + return 1; +} + +static BOOL +LoadMMD1Patterns (void) +{ + int t, row, col; + UWORD numtracks, numlines, maxlines = 0, track = 0; + MMD1NOTE *mmdp; + + /* first, scan patterns to see how many channels are used */ + for (t = 0; t < of.numpat; t++) + { + _mm_fseek (modreader, ba[t], SEEK_SET); + numtracks = _mm_read_M_UWORD (modreader); + numlines = _mm_read_M_UWORD (modreader); + if (numtracks > of.numchn) + of.numchn = numtracks; + if (numlines > maxlines) + maxlines = numlines; + } + + of.numtrk = of.numpat * of.numchn; + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + if (!(mmd1pat = (MMD1NOTE *) _mm_calloc (of.numchn * (maxlines + 1), sizeof (MMD1NOTE)))) + return 0; + + /* second read: really read and convert patterns */ + for (t = 0; t < of.numpat; t++) + { + _mm_fseek (modreader, ba[t], SEEK_SET); + numtracks = _mm_read_M_UWORD (modreader); + numlines = _mm_read_M_UWORD (modreader); + + _mm_fseek (modreader, sizeof (ULONG), SEEK_CUR); + of.pattrows[t] = ++numlines; + memset (mmdp = mmd1pat, 0, of.numchn * maxlines * sizeof (MMD1NOTE)); + + for (row = numlines; row; row--) + { + for (col = numtracks; col; col--, mmdp++) + { + mmdp->a = _mm_read_UBYTE (modreader); + mmdp->b = _mm_read_UBYTE (modreader); + mmdp->c = _mm_read_UBYTE (modreader); + mmdp->d = _mm_read_UBYTE (modreader); + } + } + + for (col = 0; col < of.numchn; col++) + of.tracks[track++] = MED_Convert1 (numlines, col); + } + return 1; +} + +BOOL +MED_Load (BOOL curious) +{ + int t; + ULONG sa[64]; + InstrHdr s; + SAMPLE *q; + MMD0sample *mss; + + /* try to read module header */ + mh->id = _mm_read_M_ULONG (modreader); + mh->modlen = _mm_read_M_ULONG (modreader); + mh->MMD0songP = _mm_read_M_ULONG (modreader); + mh->psecnum = _mm_read_M_UWORD (modreader); + mh->pseq = _mm_read_M_UWORD (modreader); + mh->MMD0BlockPP = _mm_read_M_ULONG (modreader); + mh->reserved1 = _mm_read_M_ULONG (modreader); + mh->InstrHdrPP = _mm_read_M_ULONG (modreader); + mh->reserved2 = _mm_read_M_ULONG (modreader); + mh->MMD0expP = _mm_read_M_ULONG (modreader); + mh->reserved3 = _mm_read_M_ULONG (modreader); + mh->pstate = _mm_read_M_UWORD (modreader); + mh->pblock = _mm_read_M_UWORD (modreader); + mh->pline = _mm_read_M_UWORD (modreader); + mh->pseqnum = _mm_read_M_UWORD (modreader); + mh->actplayline = _mm_read_M_SWORD (modreader); + mh->counter = _mm_read_UBYTE (modreader); + mh->extra_songs = _mm_read_UBYTE (modreader); + + /* Seek to MMD0song struct */ + _mm_fseek (modreader, mh->MMD0songP, SEEK_SET); + + /* Load the MMD0 Song Header */ + mss = ms->sample; /* load the sample data first */ + for (t = 63; t; t--, mss++) + { + mss->rep = _mm_read_M_UWORD (modreader); + mss->replen = _mm_read_M_UWORD (modreader); + mss->midich = _mm_read_UBYTE (modreader); + mss->midipreset = _mm_read_UBYTE (modreader); + mss->svol = _mm_read_UBYTE (modreader); + mss->strans = _mm_read_SBYTE (modreader); + } + + ms->numblocks = _mm_read_M_UWORD (modreader); + ms->songlen = _mm_read_M_UWORD (modreader); + _mm_read_UBYTES (ms->playseq, 256, modreader); + ms->deftempo = _mm_read_M_UWORD (modreader); + ms->playtransp = _mm_read_SBYTE (modreader); + ms->flags = _mm_read_UBYTE (modreader); + ms->flags2 = _mm_read_UBYTE (modreader); + ms->tempo2 = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (ms->trkvol, 16, modreader); + ms->mastervol = _mm_read_UBYTE (modreader); + ms->numsamples = _mm_read_UBYTE (modreader); + + /* check for a bad header */ + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* load extension structure */ + if (mh->MMD0expP) + { + _mm_fseek (modreader, mh->MMD0expP, SEEK_SET); + me->nextmod = _mm_read_M_ULONG (modreader); + me->exp_smp = _mm_read_M_ULONG (modreader); + me->s_ext_entries = _mm_read_M_UWORD (modreader); + me->s_ext_entrsz = _mm_read_M_UWORD (modreader); + me->annotxt = _mm_read_M_ULONG (modreader); + me->annolen = _mm_read_M_ULONG (modreader); + me->iinfo = _mm_read_M_ULONG (modreader); + me->i_ext_entries = _mm_read_M_UWORD (modreader); + me->i_ext_entrsz = _mm_read_M_UWORD (modreader); + me->jumpmask = _mm_read_M_ULONG (modreader); + me->rgbtable = _mm_read_M_ULONG (modreader); + me->channelsplit = _mm_read_M_ULONG (modreader); + me->n_info = _mm_read_M_ULONG (modreader); + me->songname = _mm_read_M_ULONG (modreader); + me->songnamelen = _mm_read_M_ULONG (modreader); + me->dumps = _mm_read_M_ULONG (modreader); + } + + /* seek to and read the samplepointer array */ + _mm_fseek (modreader, mh->InstrHdrPP, SEEK_SET); + if (!_mm_read_M_ULONGS (sa, ms->numsamples, modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* alloc and read the blockpointer array */ + if (!(ba = (ULONG *) _mm_calloc (ms->numblocks, sizeof (ULONG)))) + return 0; + _mm_fseek (modreader, mh->MMD0BlockPP, SEEK_SET); + if (!_mm_read_M_ULONGS (ba, ms->numblocks, modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* copy song positions */ + if (!AllocPositions (ms->songlen)) + return 0; + for (t = 0; t < ms->songlen; t++) + of.positions[t] = ms->playseq[t]; + + decimalvolumes = (ms->flags & 0x10) ? 0 : 1; + bpmtempos = (ms->flags2 & 0x20) ? 1 : 0; + + if (bpmtempos) + { + int bpmlen = (ms->flags2 & 0x1f) + 1; + of.initspeed = ms->tempo2; + of.inittempo = ms->deftempo * bpmlen / 4; + + if (bpmlen != 4) + { + /* Let's do some math : compute GCD of BPM beat length and speed */ + int a, b; + + a = bpmlen; + b = ms->tempo2; + + if (a > b) + { + t = b; + b = a; + a = t; + } + while ((a != b) && (a)) + { + t = a; + a = b - a; + b = t; + if (a > b) + { + t = b; + b = a; + a = t; + } + } + + of.initspeed /= b; + of.inittempo = ms->deftempo * bpmlen / (4 * b); + } + } + else + { + of.initspeed = ms->tempo2; + of.inittempo = ms->deftempo ? ((UWORD) ms->deftempo * 125) / 33 : 128; + if ((ms->deftempo <= 10) && (ms->deftempo)) + of.inittempo = (of.inittempo * 33) / 6; + of.flags |= UF_HIGHBPM; + } + MED_Version[12] = mh->id; + of.modtype = strdup (MED_Version); + of.numchn = 0; /* will be counted later */ + of.numpat = ms->numblocks; + of.numpos = ms->songlen; + of.numins = ms->numsamples; + of.numsmp = of.numins; + of.reppos = 0; + if ((mh->MMD0expP) && (me->songname) && (me->songnamelen)) + { + char *name; + + _mm_fseek (modreader, me->songname, SEEK_SET); + name = _mm_malloc (me->songnamelen); + _mm_read_UBYTES (name, me->songnamelen, modreader); + of.songname = DupStr (name, me->songnamelen, 1); + free (name); + } + else + of.songname = DupStr (NULL, 0, 0); + if ((mh->MMD0expP) && (me->annotxt) && (me->annolen)) + { + _mm_fseek (modreader, me->annotxt, SEEK_SET); + ReadComment (me->annolen); + } + + if (!AllocSamples ()) + return 0; + q = of.samples; + for (t = 0; t < of.numins; t++) + { + q->flags = SF_SIGNED; + q->volume = 64; + if (sa[t]) + { + _mm_fseek (modreader, sa[t], SEEK_SET); + s.length = _mm_read_M_ULONG (modreader); + s.type = _mm_read_M_SWORD (modreader); + + if (s.type) + { +#ifdef MIKMOD_DEBUG + fputs ("\rNon-sample instruments not supported in MED loader yet\n", stderr); +#endif + if (!curious) + { + _mm_errno = MMERR_MED_SYNTHSAMPLES; + return 0; + } + s.length = 0; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->length = s.length; + q->seekpos = _mm_ftell (modreader); + q->loopstart = ms->sample[t].rep << 1; + q->loopend = q->loopstart + (ms->sample[t].replen << 1); + + if (ms->sample[t].replen > 1) + q->flags |= SF_LOOP; + + /* don't load sample if length>='MMD0'... + such kluges make libmikmod's code unique !!! */ + if (q->length >= MMD0_string) + q->length = 0; + } + else + q->length = 0; + + if ((mh->MMD0expP) && (me->exp_smp) && + (t < me->s_ext_entries) && (me->s_ext_entrsz >= 4)) + { + InstrExt ie; + + _mm_fseek (modreader, me->exp_smp + t * me->s_ext_entrsz, SEEK_SET); + ie.hold = _mm_read_UBYTE (modreader); + ie.decay = _mm_read_UBYTE (modreader); + ie.suppress_midi_off = _mm_read_UBYTE (modreader); + ie.finetune = _mm_read_SBYTE (modreader); + + q->speed = finetune[ie.finetune & 0xf]; + } + else + q->speed = 8363; + + if ((mh->MMD0expP) && (me->iinfo) && + (t < me->i_ext_entries) && (me->i_ext_entrsz >= 40)) + { + InstrInfo ii; + + _mm_fseek (modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET); + _mm_read_UBYTES (ii.name, 40, modreader); + q->samplename = DupStr (ii.name, 40, 1); + } + else + q->samplename = NULL; + + q++; + } + + if (mh->id == MMD0_string) + { + if (!LoadMMD0Patterns ()) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + } + else if (mh->id == MMD1_string) + { + if (!LoadMMD1Patterns ()) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + } + else + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + return 1; +} + +/*========== Loader information */ + +MLOADER load_med = +{ + NULL, + "MED", + "MED (OctaMED)", + MED_Init, + MED_Test, + MED_Load, + MED_Cleanup, + NULL +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_mod.c TiMidity++-2.9.0/libunimod/load_mod.c --- TiMidity++-2.8.2/libunimod/load_mod.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_mod.c Fri Feb 18 10:33:38 2000 @@ -0,0 +1,454 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_mod.c,v 1.28 1999/10/25 16:31:41 miod Exp $ + + Generic MOD loader (Protracker, StarTracker, FastTracker, etc) + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +typedef struct MSAMPINFO + { + CHAR samplename[23]; /* 22 in module, 23 in memory */ + UWORD length; + UBYTE finetune; + UBYTE volume; + UWORD reppos; + UWORD replen; + } +MSAMPINFO; + +typedef struct MODULEHEADER + { + CHAR songname[21]; /* the songname.. 20 in module, 21 in memory */ + MSAMPINFO samples[31]; /* all sampleinfo */ + UBYTE songlength; /* number of patterns used */ + UBYTE magic1; /* should be 127 */ + UBYTE positions[128]; /* which pattern to play at pos */ + UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */ + } +MODULEHEADER; + +typedef struct MODTYPE + { + CHAR id[5]; + UBYTE channels; + CHAR *name; + } +MODTYPE; + +typedef struct MODNOTE + { + UBYTE a, b, c, d; + } +MODNOTE; + +/*========== Loader variables */ + +#define MODULEHEADERSIZE 1084 + +static CHAR protracker[] = "Protracker"; +static CHAR startracker[] = "Startracker"; +static CHAR fasttracker[] = "Fasttracker"; +static CHAR ins15tracker[] = "15-instrument"; +static CHAR oktalyzer[] = "Oktalyzer"; +static CHAR taketracker[] = "TakeTracker"; +static CHAR orpheus[] = "Imago Orpheus (MOD format)"; + +#define MODTYPE_COUNT 24 +static MODTYPE modtypes[MODTYPE_COUNT + 1] = +{ + {"M.K.", 4, protracker}, /* protracker 4 channel */ + {"M!K!", 4, protracker}, /* protracker 4 channel */ + {"FLT4", 4, startracker}, /* startracker 4 channel */ + {"2CHN", 2, fasttracker}, /* fasttracker 2 channel */ + {"4CHN", 4, fasttracker}, /* fasttracker 4 channel */ + {"6CHN", 6, fasttracker}, /* fasttracker 6 channel */ + {"8CHN", 8, fasttracker}, /* fasttracker 8 channel */ + {"10CH", 10, fasttracker}, /* fasttracker 10 channel */ + {"12CH", 12, fasttracker}, /* fasttracker 12 channel */ + {"14CH", 14, fasttracker}, /* fasttracker 14 channel */ + {"15CH", 15, fasttracker}, /* fasttracker 15 channel */ + {"16CH", 16, fasttracker}, /* fasttracker 16 channel */ + {"18CH", 18, fasttracker}, /* fasttracker 18 channel */ + {"20CH", 20, fasttracker}, /* fasttracker 20 channel */ + {"22CH", 22, fasttracker}, /* fasttracker 22 channel */ + {"24CH", 24, fasttracker}, /* fasttracker 24 channel */ + {"26CH", 26, fasttracker}, /* fasttracker 26 channel */ + {"28CH", 28, fasttracker}, /* fasttracker 28 channel */ + {"30CH", 30, fasttracker}, /* fasttracker 30 channel */ + {"32CH", 32, fasttracker}, /* fasttracker 32 channel */ + {"CD81", 8, oktalyzer}, /* atari oktalyzer 8 channel */ + {"OKTA", 8, oktalyzer}, /* atari oktalyzer 8 channel */ + {"16CN", 16, taketracker}, /* taketracker 16 channel */ + {"32CN", 32, taketracker}, /* taketracker 32 channel */ + {" ", 4, ins15tracker} /* 15-instrument 4 channel */ +}; + +static MODULEHEADER *mh = NULL; +static MODNOTE *patbuf = NULL; +static int modtype = 0; + +/*========== Loader code */ + +static BOOL +MOD_Test (void) +{ + UBYTE id[4]; + + _mm_fseek (modreader, MODULEHEADERSIZE - 4, SEEK_SET); + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + + /* find out which ID string */ + for (modtype = 0; modtype < MODTYPE_COUNT; modtype++) + if (!memcmp (id, modtypes[modtype].id, 4)) + return 1; + + return 0; +} + +static BOOL +MOD_Init (void) +{ + if (!(mh = (MODULEHEADER *) _mm_malloc (sizeof (MODULEHEADER)))) + return 0; + return 1; +} + +static void +MOD_Cleanup (void) +{ + _mm_free (mh); + _mm_free (patbuf); +} + +/* + Old (amiga) noteinfo: + + _____byte 1_____ byte2_ _____byte 3_____ byte4_ + / \ / \ / \ / \ + 0000 0000-00000000 0000 0000-00000000 + + Upper four 12 bits for Lower four Effect command. + bits of sam- note period. bits of sam- + ple number. ple number. + + */ + +static UWORD npertab[7 * OCTAVE] = +{ + /* -> Tuning 0 */ + 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906, + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56, + + 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28, + 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14 +}; + + +static void +ConvertNote (MODNOTE * n) +{ + UBYTE instrument, effect, effdat, note; + UWORD period; + UBYTE lastnote = 0; + + /* extract the various information from the 4 bytes that make up a note */ + instrument = (n->a & 0x10) | (n->c >> 4); + period = (((UWORD) n->a & 0xf) << 8) + n->b; + effect = n->c & 0xf; + effdat = n->d; + + /* Convert the period to a note number */ + note = 0; + if (period) + { + for (note = 0; note < 7 * OCTAVE; note++) + if (period >= npertab[note]) + break; + if (note == 7 * OCTAVE) + note = 0; + else + note++; + } + + if (instrument) + { + /* if instrument does not exist, note cut */ + if ((instrument > 31) || (!mh->samples[instrument - 1].length)) + { + UniPTEffect (0xc, 0); + if (effect == 0xc) + effect = effdat = 0; + } + else + { + /* Protracker handling */ + if (modtype <= 2) + { + /* if we had a note, then change instrument... */ + if (note) + UniInstrument (instrument - 1); + /* ...otherwise, only adjust volume... */ + else + { + /* ...unless an effect was specified, which forces a new + note to be played */ + if (effect || effdat) + { + UniInstrument (instrument - 1); + note = lastnote; + } + else + UniPTEffect (0xc, mh->samples[instrument - 1].volume & 0x7f); + } + } + else + { + /* Fasttracker handling */ + UniInstrument (instrument - 1); + if (!note) + note = lastnote; + } + } + } + if (note) + { + UniNote (note + 2 * OCTAVE - 1); + lastnote = note; + } + + /* Convert pattern jump from Dec to Hex */ + if (effect == 0xd) + effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf); + + /* Volume slide, up has priority */ + if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0)) + effdat &= 0xf0; + + UniPTEffect (effect, effdat); +} + +static UBYTE * +ConvertTrack (MODNOTE * n) +{ + int t; + + UniReset (); + for (t = 0; t < 64; t++) + { + ConvertNote (n); + UniNewline (); + n += of.numchn; + } + return UniDup (); +} + +/* Loads all patterns of a modfile and converts them into the 3 byte format. */ +static BOOL +ML_LoadPatterns (void) +{ + int t, s, tracks = 0; + + if (!AllocPatterns ()) + return 0; + if (!AllocTracks ()) + return 0; + + /* Allocate temporary buffer for loading and converting the patterns */ + if (!(patbuf = (MODNOTE *) _mm_calloc (64U * of.numchn, sizeof (MODNOTE)))) + return 0; + + for (t = 0; t < of.numpat; t++) + { + /* Load the pattern into the temp buffer and convert it */ + for (s = 0; s < (64U * of.numchn); s++) + { + patbuf[s].a = _mm_read_UBYTE (modreader); + patbuf[s].b = _mm_read_UBYTE (modreader); + patbuf[s].c = _mm_read_UBYTE (modreader); + patbuf[s].d = _mm_read_UBYTE (modreader); + } + for (s = 0; s < of.numchn; s++) + if (!(of.tracks[tracks++] = ConvertTrack (patbuf + s))) + return 0; + } + return 1; +} + +static BOOL +MOD_Load (BOOL curious) +{ + int t, scan; + SAMPLE *q; + MSAMPINFO *s; + BOOL is_orpheus = 0; + + /* try to read module header */ + _mm_read_string ((CHAR *) mh->songname, 20, modreader); + mh->songname[20] = 0; /* just in case */ + + for (t = 0; t < 31; t++) + { + s = &mh->samples[t]; + _mm_read_string (s->samplename, 22, modreader); + s->samplename[22] = 0; /* just in case */ + s->length = _mm_read_M_UWORD (modreader); + s->finetune = _mm_read_UBYTE (modreader); + s->volume = _mm_read_UBYTE (modreader); + s->reppos = _mm_read_M_UWORD (modreader); + s->replen = _mm_read_M_UWORD (modreader); + } + + mh->songlength = _mm_read_UBYTE (modreader); + mh->magic1 = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->positions, 128, modreader); + _mm_read_UBYTES (mh->magic2, 4, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.initspeed = 6; + of.inittempo = 125; + of.numchn = modtypes[modtype].channels; + of.songname = DupStr (mh->songname, 21, 1); + of.numpos = mh->songlength; + of.reppos = 0; + + /* Count the number of patterns */ + of.numpat = 0; + for (t = 0; t < of.numpos; t++) + if (mh->positions[t] > of.numpat) + of.numpat = mh->positions[t]; + /* since some old modules embed extra patterns, we have to check the + whole list to get the samples' file offsets right - however we can find + garbage here, so check carefully */ + scan = 1; + for (t = of.numpos; t < 128; t++) + if (mh->positions[t] >= 0x80) + scan = 0; + if (scan) + for (t = of.numpos; t < 128; t++) + { + if (mh->positions[t] > of.numpat) + of.numpat = mh->positions[t]; + if ((curious) && (mh->positions[t])) + of.numpos = t + 1; + } + of.numpat++; + of.numtrk = of.numpat * of.numchn; + + if (!AllocPositions (of.numpos)) + return 0; + for (t = 0; t < of.numpos; t++) + of.positions[t] = mh->positions[t]; + + /* Finally, init the sampleinfo structures */ + of.numins = of.numsmp = 31; + if (!AllocSamples ()) + return 0; + s = mh->samples; + q = of.samples; + for (t = 0; t < of.numins; t++) + { + /* convert the samplename */ + q->samplename = DupStr (s->samplename, 23, 1); + /* init the sampleinfo variables and convert the size pointers */ + q->speed = finetune[s->finetune & 0xf]; + q->volume = s->volume & 0x7f; + q->loopstart = (ULONG) s->reppos << 1; + q->loopend = q->loopstart + ((ULONG) s->replen << 1); + q->length = (ULONG) s->length << 1; + q->flags = SF_SIGNED; + /* Imago Orpheus creates MODs with 16 bit samples, check */ + if ((modtypes[modtype].name == fasttracker) && (s->volume & 0x80)) + { + q->flags |= SF_16BITS; + is_orpheus = 1; + } + + if (s->replen > 1) + q->flags |= SF_LOOP; + /* fix replen if repend > length */ + if (q->loopend > q->length) + q->loopend = q->length; + + s++; + q++; + } + + if (is_orpheus) + of.modtype = strdup (orpheus); + else + of.modtype = strdup (modtypes[modtype].name); + + if (!ML_LoadPatterns ()) + return 0; + return 1; +} + +static CHAR * +MOD_LoadTitle (void) +{ + CHAR s[21]; + + _mm_fseek (modreader, 0, SEEK_SET); + if (!_mm_read_UBYTES (s, 20, modreader)) + return NULL; + s[20] = 0; /* just in case */ + + return (DupStr (s, 21, 1)); +} + +/*========== Loader information */ + +MLOADER load_mod = +{ + NULL, + "Standard module", + "MOD (31 instrument)", + MOD_Init, + MOD_Test, + MOD_Load, + MOD_Cleanup, + MOD_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_mtm.c TiMidity++-2.9.0/libunimod/load_mtm.c --- TiMidity++-2.8.2/libunimod/load_mtm.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_mtm.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,313 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_mtm.c,v 1.27 1999/10/25 16:31:41 miod Exp $ + + MTM module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +typedef struct MTMHEADER + { + UBYTE id[3]; /* MTM file marker */ + UBYTE version; /* upper major, lower nibble minor version number */ + CHAR songname[20]; /* ASCIIZ songname */ + UWORD numtracks; /* number of tracks saved */ + UBYTE lastpattern; /* last pattern number saved */ + UBYTE lastorder; /* last order number to play (songlength-1) */ + UWORD commentsize; /* length of comment field */ + UBYTE numsamples; /* number of samples saved */ + UBYTE attribute; /* attribute byte (unused) */ + UBYTE beatspertrack; + UBYTE numchannels; /* number of channels used */ + UBYTE panpos[32]; /* voice pan positions */ + } +MTMHEADER; + +typedef struct MTMSAMPLE + { + CHAR samplename[22]; + ULONG length; + ULONG reppos; + ULONG repend; + UBYTE finetune; + UBYTE volume; + UBYTE attribute; + } +MTMSAMPLE; + +typedef struct MTMNOTE + { + UBYTE a, b, c; + } +MTMNOTE; + +/*========== Loader variables */ + +static MTMHEADER *mh = NULL; +static MTMNOTE *mtmtrk = NULL; +static UWORD pat[32]; + +static CHAR MTM_Version[] = "MTM"; + +/*========== Loader code */ + +BOOL +MTM_Test (void) +{ + UBYTE id[3]; + + if (!_mm_read_UBYTES (id, 3, modreader)) + return 0; + if (!memcmp (id, "MTM", 3)) + return 1; + return 0; +} + +BOOL +MTM_Init (void) +{ + if (!(mtmtrk = (MTMNOTE *) _mm_calloc (64, sizeof (MTMNOTE)))) + return 0; + if (!(mh = (MTMHEADER *) _mm_malloc (sizeof (MTMHEADER)))) + return 0; + + return 1; +} + +void +MTM_Cleanup (void) +{ + _mm_free (mtmtrk); + _mm_free (mh); +} + +static UBYTE * +MTM_Convert (void) +{ + int t; + UBYTE a, b, inst, note, eff, dat; + + UniReset (); + for (t = 0; t < 64; t++) + { + a = mtmtrk[t].a; + b = mtmtrk[t].b; + inst = ((a & 0x3) << 4) | (b >> 4); + note = a >> 2; + eff = b & 0xf; + dat = mtmtrk[t].c; + + if (inst) + UniInstrument (inst - 1); + if (note) + UniNote (note + 2 * OCTAVE); + + /* MTM bug workaround : when the effect is volslide, slide-up *always* + overrides slide-down. */ + if (eff == 0xa && (dat & 0xf0)) + dat &= 0xf0; + + /* Convert pattern jump from Dec to Hex */ + if (eff == 0xd) + dat = (((dat & 0xf0) >> 4) * 10) + (dat & 0xf); + UniPTEffect (eff, dat); + UniNewline (); + } + return UniDup (); +} + +BOOL +MTM_Load (BOOL curious) +{ + int t, u; + MTMSAMPLE s; + SAMPLE *q; + + /* try to read module header */ + _mm_read_UBYTES (mh->id, 3, modreader); + mh->version = _mm_read_UBYTE (modreader); + _mm_read_string (mh->songname, 20, modreader); + mh->numtracks = _mm_read_I_UWORD (modreader); + mh->lastpattern = _mm_read_UBYTE (modreader); + mh->lastorder = _mm_read_UBYTE (modreader); + mh->commentsize = _mm_read_I_UWORD (modreader); + mh->numsamples = _mm_read_UBYTE (modreader); + mh->attribute = _mm_read_UBYTE (modreader); + mh->beatspertrack = _mm_read_UBYTE (modreader); + mh->numchannels = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->panpos, 32, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.initspeed = 6; + of.inittempo = 125; + of.modtype = strdup (MTM_Version); + of.numchn = mh->numchannels; + of.numtrk = mh->numtracks + 1; /* get number of channels */ + of.songname = DupStr (mh->songname, 20, 1); /* make a cstr of songname */ + of.numpos = mh->lastorder + 1; /* copy the songlength */ + of.numpat = mh->lastpattern + 1; + of.reppos = 0; + for (t = 0; t < 32; t++) + of.panning[t] = mh->panpos[t] << 4; + of.numins = of.numsmp = mh->numsamples; + + if (!AllocSamples ()) + return 0; + q = of.samples; + for (t = 0; t < of.numins; t++) + { + /* try to read sample info */ + _mm_read_string (s.samplename, 22, modreader); + s.length = _mm_read_I_ULONG (modreader); + s.reppos = _mm_read_I_ULONG (modreader); + s.repend = _mm_read_I_ULONG (modreader); + s.finetune = _mm_read_UBYTE (modreader); + s.volume = _mm_read_UBYTE (modreader); + s.attribute = _mm_read_UBYTE (modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr (s.samplename, 22, 1); + q->seekpos = 0; + q->speed = finetune[s.finetune]; + q->length = s.length; + q->loopstart = s.reppos; + q->loopend = s.repend; + q->volume = s.volume; + if ((s.repend - s.reppos) > 2) + q->flags |= SF_LOOP; + + if (s.attribute & 1) + { + /* If the sample is 16-bits, convert the length and replen + byte-values into sample-values */ + q->flags |= SF_16BITS; + q->length >>= 1; + q->loopstart >>= 1; + q->loopend >>= 1; + } + + q++; + } + + if (!AllocPositions (of.numpos)) + return 0; + for (t = 0; t < of.numpos; t++) + of.positions[t] = _mm_read_UBYTE (modreader); + for (; t < 128; t++) + _mm_read_UBYTE (modreader); + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + of.tracks[0] = MTM_Convert (); /* track 0 is empty */ + for (t = 1; t < of.numtrk; t++) + { + int s; + + for (s = 0; s < 64; s++) + { + mtmtrk[s].a = _mm_read_UBYTE (modreader); + mtmtrk[s].b = _mm_read_UBYTE (modreader); + mtmtrk[s].c = _mm_read_UBYTE (modreader); + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_TRACK; + return 0; + } + + if (!(of.tracks[t] = MTM_Convert ())) + return 0; + } + + for (t = 0; t < of.numpat; t++) + { + _mm_read_I_UWORDS (pat, 32, modreader); + for (u = 0; u < of.numchn; u++) + of.patterns[((long) t * of.numchn) + u] = pat[u]; + } + + /* read comment field */ + if (mh->commentsize) + if (!ReadLinedComment (mh->commentsize / 40, 40)) + return 0; + + return 1; +} + +CHAR * +MTM_LoadTitle (void) +{ + CHAR s[20]; + + _mm_fseek (modreader, 4, SEEK_SET); + if (!_mm_read_UBYTES (s, 20, modreader)) + return NULL; + + return (DupStr (s, 20, 1)); +} + +/*========== Loader information */ + +MLOADER load_mtm = +{ + NULL, + "MTM", + "MTM (MultiTracker Module editor)", + MTM_Init, + MTM_Test, + MTM_Load, + MTM_Cleanup, + MTM_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_s3m.c TiMidity++-2.9.0/libunimod/load_s3m.c --- TiMidity++-2.8.2/libunimod/load_s3m.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_s3m.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,525 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_s3m.c,v 1.32 1999/10/25 16:31:41 miod Exp $ + + Screamtracker (S3M) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +/* header */ +typedef struct S3MHEADER + { + CHAR songname[28]; + UBYTE t1a; + UBYTE type; + UBYTE unused1[2]; + UWORD ordnum; + UWORD insnum; + UWORD patnum; + UWORD flags; + UWORD tracker; + UWORD fileformat; + CHAR scrm[4]; + UBYTE mastervol; + UBYTE initspeed; + UBYTE inittempo; + UBYTE mastermult; + UBYTE ultraclick; + UBYTE pantable; + UBYTE unused2[8]; + UWORD special; + UBYTE channels[32]; + } +S3MHEADER; + +/* sample information */ +typedef struct S3MSAMPLE + { + UBYTE type; + CHAR filename[12]; + UBYTE memsegh; + UWORD memsegl; + ULONG length; + ULONG loopbeg; + ULONG loopend; + UBYTE volume; + UBYTE dsk; + UBYTE pack; + UBYTE flags; + ULONG c2spd; + UBYTE unused[12]; + CHAR sampname[28]; + CHAR scrs[4]; + } +S3MSAMPLE; + +typedef struct S3MNOTE + { + UBYTE note, ins, vol, cmd, inf; + } +S3MNOTE; + +/*========== Loader variables */ + +static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */ +static S3MHEADER *mh = NULL; +static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */ + +/* tracker identifiers */ +#define NUMTRACKERS 4 +static CHAR *S3M_Version[] = +{ + "Screamtracker x.xx", + "Imago Orpheus x.xx (S3M format)", + "Impulse Tracker x.xx (S3M format)", + "Unknown tracker x.xx (S3M format)", + "Impulse Tracker 2.14p3 (S3M format)", + "Impulse Tracker 2.14p4 (S3M format)" +}; +/* version number position in above array */ +static int numeric[NUMTRACKERS] = +{14, 14, 16, 16}; + +/*========== Loader code */ + +BOOL +S3M_Test (void) +{ + UBYTE id[4]; + + _mm_fseek (modreader, 0x2c, SEEK_SET); + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + if (!memcmp (id, "SCRM", 4)) + return 1; + return 0; +} + +BOOL +S3M_Init (void) +{ + if (!(s3mbuf = (S3MNOTE *) _mm_malloc (32 * 64 * sizeof (S3MNOTE)))) + return 0; + if (!(mh = (S3MHEADER *) _mm_malloc (sizeof (S3MHEADER)))) + return 0; + if (!(poslookup = (UBYTE *) _mm_malloc (sizeof (UBYTE) * 256))) + return 0; + memset (poslookup, -1, 256); + + return 1; +} + +void +S3M_Cleanup (void) +{ + _mm_free (s3mbuf); + _mm_free (paraptr); + _mm_free (poslookup); + _mm_free (mh); + _mm_free (origpositions); +} + +/* Because so many s3m files have 16 channels as the set number used, but really + only use far less (usually 8 to 12 still), I had to make this function, which + determines the number of channels that are actually USED by a pattern. + + For every channel that's used, it sets the appropriate array entry of the + global variable 'remap' + + NOTE: You must first seek to the file location of the pattern before calling + this procedure. + + Returns 1 on fail. */ +static BOOL +S3M_GetNumChannels (void) +{ + int row = 0, flag, ch; + + while (row < 64) + { + flag = _mm_read_UBYTE (modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 1; + } + + if (flag) + { + ch = flag & 31; + if (mh->channels[ch] < 32) + remap[ch] = 0; + if (flag & 32) + { + _mm_read_UBYTE (modreader); + _mm_read_UBYTE (modreader); + } + if (flag & 64) + _mm_read_UBYTE (modreader); + if (flag & 128) + { + _mm_read_UBYTE (modreader); + _mm_read_UBYTE (modreader); + } + } + else + row++; + } + return 0; +} + +static BOOL +S3M_ReadPattern (void) +{ + int row = 0, flag, ch; + S3MNOTE *n, dummy; + + /* clear pattern data */ + memset (s3mbuf, 255, 32 * 64 * sizeof (S3MNOTE)); + + while (row < 64) + { + flag = _mm_read_UBYTE (modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if (flag) + { + ch = remap[flag & 31]; + + if (ch != -1) + n = &s3mbuf[(64U * ch) + row]; + else + n = &dummy; + + if (flag & 32) + { + n->note = _mm_read_UBYTE (modreader); + n->ins = _mm_read_UBYTE (modreader); + } + if (flag & 64) + n->vol = _mm_read_UBYTE (modreader); + if (flag & 128) + { + n->cmd = _mm_read_UBYTE (modreader); + n->inf = _mm_read_UBYTE (modreader); + } + } + else + row++; + } + return 1; +} + +static UBYTE * +S3M_ConvertTrack (S3MNOTE * tr) +{ + int t; + + UniReset (); + for (t = 0; t < 64; t++) + { + UBYTE note, ins, vol; + + note = tr[t].note; + ins = tr[t].ins; + vol = tr[t].vol; + + if ((ins) && (ins != 255)) + UniInstrument (ins - 1); + if (note != 255) + { + if (note == 254) + { + UniPTEffect (0xc, 0); /* note cut command */ + vol = 255; + } + else + UniNote (((note >> 4) * OCTAVE) + (note & 0xf)); /* normal note */ + } + if (vol < 255) + UniPTEffect (0xc, vol); + + S3MIT_ProcessCmd (tr[t].cmd, tr[t].inf, 1); + UniNewline (); + } + return UniDup (); +} + +BOOL +S3M_Load (BOOL curious) +{ + int t, u, track = 0; + SAMPLE *q; + UBYTE pan[32]; + + /* try to read module header */ + _mm_read_string (mh->songname, 28, modreader); + mh->t1a = _mm_read_UBYTE (modreader); + mh->type = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->unused1, 2, modreader); + mh->ordnum = _mm_read_I_UWORD (modreader); + mh->insnum = _mm_read_I_UWORD (modreader); + mh->patnum = _mm_read_I_UWORD (modreader); + mh->flags = _mm_read_I_UWORD (modreader); + mh->tracker = _mm_read_I_UWORD (modreader); + mh->fileformat = _mm_read_I_UWORD (modreader); + _mm_read_string (mh->scrm, 4, modreader); + mh->mastervol = _mm_read_UBYTE (modreader); + mh->initspeed = _mm_read_UBYTE (modreader); + mh->inittempo = _mm_read_UBYTE (modreader); + mh->mastermult = _mm_read_UBYTE (modreader); + mh->ultraclick = _mm_read_UBYTE (modreader); + mh->pantable = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->unused2, 8, modreader); + mh->special = _mm_read_I_UWORD (modreader); + _mm_read_UBYTES (mh->channels, 32, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.songname = DupStr (mh->songname, 28, 0); + of.numpat = mh->patnum; + of.reppos = 0; + of.numins = of.numsmp = mh->insnum; + of.initspeed = mh->initspeed; + of.inittempo = mh->inittempo; + of.initvolume = mh->mastervol << 1; + of.flags |= UF_ARPMEM; + if ((mh->tracker == 0x1300) || (mh->flags & 64)) + of.flags |= UF_S3MSLIDES; + + /* read the order data */ + if (!AllocPositions (mh->ordnum)) + return 0; + if (!(origpositions = _mm_calloc (mh->ordnum, sizeof (UWORD)))) + return 0; + + for (t = 0; t < mh->ordnum; t++) + { + origpositions[t] = _mm_read_UBYTE (modreader); + if ((origpositions[t] >= mh->patnum) && (origpositions[t] < 254)) + origpositions[t] = 255 /*mh->patnum-1 */ ; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + poslookupcnt = mh->ordnum; + S3MIT_CreateOrders (curious); + + if (!(paraptr = (UWORD *) _mm_malloc ((of.numins + of.numpat) * sizeof (UWORD)))) + return 0; + + /* read the instrument+pattern parapointers */ + _mm_read_I_UWORDS (paraptr, of.numins + of.numpat, modreader); + + if (mh->pantable == 252) + { + /* read the panning table (ST 3.2 addition. See below for further + portions of channel panning [past reampper]). */ + _mm_read_UBYTES (pan, 32, modreader); + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* load samples */ + if (!AllocSamples ()) + return 0; + q = of.samples; + for (t = 0; t < of.numins; t++) + { + S3MSAMPLE s; + + /* seek to instrument position */ + _mm_fseek (modreader, ((long) paraptr[t]) << 4, SEEK_SET); + /* and load sample info */ + s.type = _mm_read_UBYTE (modreader); + _mm_read_string (s.filename, 12, modreader); + s.memsegh = _mm_read_UBYTE (modreader); + s.memsegl = _mm_read_I_UWORD (modreader); + s.length = _mm_read_I_ULONG (modreader); + s.loopbeg = _mm_read_I_ULONG (modreader); + s.loopend = _mm_read_I_ULONG (modreader); + s.volume = _mm_read_UBYTE (modreader); + s.dsk = _mm_read_UBYTE (modreader); + s.pack = _mm_read_UBYTE (modreader); + s.flags = _mm_read_UBYTE (modreader); + s.c2spd = _mm_read_I_ULONG (modreader); + _mm_read_UBYTES (s.unused, 12, modreader); + _mm_read_string (s.sampname, 28, modreader); + _mm_read_string (s.scrs, 4, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr (s.sampname, 28, 0); + q->speed = s.c2spd; + q->length = s.length; + q->loopstart = s.loopbeg > s.length ? s.length : s.loopbeg; + q->loopend = s.loopend > s.length ? s.length : s.loopend; + q->volume = s.volume; + q->seekpos = (((long) s.memsegh) << 16 | s.memsegl) << 4; + + if (s.flags & 1) + q->flags |= SF_LOOP; + if (s.flags & 4) + q->flags |= SF_16BITS; + if (mh->fileformat == 1) + q->flags |= SF_SIGNED; + + /* don't load sample if it doesn't have the SCRS tag */ + if (memcmp (s.scrs, "SCRS", 4)) + q->length = 0; + + q++; + } + + /* determine the number of channels actually used. */ + of.numchn = 0; + memset (remap, -1, 32 * sizeof (UBYTE)); + for (t = 0; t < of.numpat; t++) + { + /* seek to pattern position (+2 skip pattern length) */ + _mm_fseek (modreader, (long) ((paraptr[of.numins + t]) << 4) + 2, SEEK_SET); + if (S3M_GetNumChannels ()) + return 0; + } + /* then we can decide the module type */ + t = mh->tracker >> 12; + if ((!t) || (t > 3)) + t = NUMTRACKERS - 1; /* unknown tracker */ + else + { + if (mh->tracker >= 0x3217) + t = NUMTRACKERS + 1; /* IT 2.14p4 */ + else if (mh->tracker >= 0x3216) + t = NUMTRACKERS; /* IT 2.14p3 */ + else + t--; + } + of.modtype = strdup (S3M_Version[t]); + if (t < NUMTRACKERS) + { + of.modtype[numeric[t]] = ((mh->tracker >> 8) & 0xf) + '0'; + of.modtype[numeric[t] + 2] = ((mh->tracker >> 4) & 0xf) + '0'; + of.modtype[numeric[t] + 3] = ((mh->tracker) & 0xf) + '0'; + } + + /* build the remap array */ + for (t = 0; t < 32; t++) + if (!remap[t]) + remap[t] = of.numchn++; + + /* set panning positions after building remap chart! */ + for (t = 0; t < 32; t++) + if ((mh->channels[t] < 32) && (remap[t] != -1)) + { + if (mh->channels[t] < 8) + of.panning[remap[t]] = 0x20; /* 0x30 = std s3m val */ + else + of.panning[remap[t]] = 0xd0; /* 0xc0 = std s3m val */ + } + if (mh->pantable == 252) + /* set panning positions according to panning table (new for st3.2) */ + for (t = 0; t < 32; t++) + if ((pan[t] & 0x20) && (mh->channels[t] < 32) && (remap[t] != -1)) + of.panning[remap[t]] = (pan[t] & 0xf) << 4; + + /* load pattern info */ + of.numtrk = of.numpat * of.numchn; + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + for (t = 0; t < of.numpat; t++) + { + /* seek to pattern position (+2 skip pattern length) */ + _mm_fseek (modreader, (((long) paraptr[of.numins + t]) << 4) + 2, SEEK_SET); + if (!S3M_ReadPattern ()) + return 0; + for (u = 0; u < of.numchn; u++) + if (!(of.tracks[track++] = S3M_ConvertTrack (&s3mbuf[u * 64]))) + return 0; + } + + return 1; +} + +CHAR * +S3M_LoadTitle (void) +{ + CHAR s[28]; + + _mm_fseek (modreader, 0, SEEK_SET); + if (!_mm_read_UBYTES (s, 28, modreader)) + return NULL; + + return (DupStr (s, 28, 0)); +} + +/*========== Loader information */ + +MLOADER load_s3m = +{ + NULL, + "S3M", + "S3M (Scream Tracker 3)", + S3M_Init, + S3M_Test, + S3M_Load, + S3M_Cleanup, + S3M_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_stm.c TiMidity++-2.9.0/libunimod/load_stm.c --- TiMidity++-2.8.2/libunimod/load_stm.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_stm.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,419 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_stm.c,v 1.30 1999/10/25 16:31:41 miod Exp $ + + Screamtracker 2 (STM) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +/* sample information */ +typedef struct STMSAMPLE + { + CHAR filename[12]; + UBYTE unused; /* 0x00 */ + UBYTE instdisk; /* Instrument disk */ + UWORD reserved; + UWORD length; /* Sample length */ + UWORD loopbeg; /* Loop start point */ + UWORD loopend; /* Loop end point */ + UBYTE volume; /* Volume */ + UBYTE reserved2; + UWORD c2spd; /* Good old c2spd */ + ULONG reserved3; + UWORD isa; + } +STMSAMPLE; + +/* header */ +typedef struct STMHEADER + { + CHAR songname[20]; + CHAR trackername[8]; /* !Scream! for ST 2.xx */ + UBYTE unused; /* 0x1A */ + UBYTE filetype; /* 1=song, 2=module */ + UBYTE ver_major; + UBYTE ver_minor; + UBYTE inittempo; /* initspeed= stm inittempo>>4 */ + UBYTE numpat; /* number of patterns */ + UBYTE globalvol; + UBYTE reserved[13]; + STMSAMPLE sample[31]; /* STM sample data */ + UBYTE patorder[128]; /* Docs say 64 - actually 128 */ + } +STMHEADER; + +typedef struct STMNOTE + { + UBYTE note, insvol, volcmd, cmdinf; + } +STMNOTE; + +/*========== Loader variables */ + +static STMNOTE *stmbuf = NULL; +static STMHEADER *mh = NULL; + +/* tracker identifiers */ +#define NUMTRACKERS 3 +static CHAR mod2stm_sig[] = "BMOD2STM"; +static CHAR scream_sig[] = "!Scream!"; +static CHAR wuzamod_sig[] = "WUZAMOD!"; +static CHAR *STM_Signatures[NUMTRACKERS] = +{ + scream_sig, + mod2stm_sig, + wuzamod_sig +}; +static CHAR *STM_Version[NUMTRACKERS] = +{ + "Screamtracker 2", + "Converted by MOD2STM (STM format)", + "Wuzamod (STM format)" +}; + +/*========== Loader code */ + +BOOL +STM_Test (void) +{ + UBYTE str[44]; + + _mm_fseek (modreader, 20, SEEK_SET); + _mm_read_UBYTES (str, 44, modreader); + if (str[9] != 2) + return 0; /* STM Module = filetype 2 */ + + if (!memcmp (str, mod2stm_sig, 8)) + return 1; + + if ((!memcmp (str, scream_sig, 8)) && (memcmp (str + 40, "SCRM", 4))) + return 1; + + return 0; +} + +BOOL +STM_Init (void) +{ + if (!(mh = (STMHEADER *) _mm_malloc (sizeof (STMHEADER)))) + return 0; + if (!(stmbuf = (STMNOTE *) _mm_calloc (64U * 4, sizeof (STMNOTE)))) + return 0; + + return 1; +} + +static void +STM_Cleanup (void) +{ + _mm_free (mh); + _mm_free (stmbuf); +} + +static void +STM_ConvertNote (STMNOTE * n) +{ + UBYTE note, ins, vol, cmd, inf; + + /* extract the various information from the 4 bytes that make up a note */ + note = n->note; + ins = n->insvol >> 3; + vol = (n->insvol & 7) + ((n->volcmd & 0x70) >> 1); + cmd = n->volcmd & 15; + inf = n->cmdinf; + + if ((ins) && (ins < 32)) + UniInstrument (ins - 1); + + /* special values of [SBYTE0] are handled here + we have no idea if these strange values will ever be encountered. + but it appears as those stms sound correct. */ + if ((note == 254) || (note == 252)) + { + UniPTEffect (0xc, 0); /* note cut */ + n->volcmd |= 0x80; + } + else + /* if note < 251, then all three bytes are stored in the file */ + if (note < 251) + UniNote ((((note >> 4) + 2) * OCTAVE) + (note & 0xf)); + + if ((!(n->volcmd & 0x80)) && (vol < 65)) + UniPTEffect (0xc, vol); + if (cmd != 255) + switch (cmd) + { + case 1: /* Axx set speed to xx */ + UniPTEffect (0xf, inf >> 4); + break; + case 2: /* Bxx position jump */ + UniPTEffect (0xb, inf); + break; + case 3: /* Cxx patternbreak to row xx */ + UniPTEffect (0xd, (((inf & 0xf0) >> 4) * 10) + (inf & 0xf)); + break; + case 4: /* Dxy volumeslide */ + UniEffect (UNI_S3MEFFECTD, inf); + break; + case 5: /* Exy toneslide down */ + UniEffect (UNI_S3MEFFECTE, inf); + break; + case 6: /* Fxy toneslide up */ + UniEffect (UNI_S3MEFFECTF, inf); + break; + case 7: /* Gxx Tone portamento,speed xx */ + UniPTEffect (0x3, inf); + break; + case 8: /* Hxy vibrato */ + UniPTEffect (0x4, inf); + break; + case 9: /* Ixy tremor, ontime x, offtime y */ + UniEffect (UNI_S3MEFFECTI, inf); + break; + case 0: /* protracker arpeggio */ + if (!inf) + break; + /* fall through */ + case 0xa: /* Jxy arpeggio */ + UniPTEffect (0x0, inf); + break; + case 0xb: /* Kxy Dual command H00 & Dxy */ + UniPTEffect (0x4, 0); + UniEffect (UNI_S3MEFFECTD, inf); + break; + case 0xc: /* Lxy Dual command G00 & Dxy */ + UniPTEffect (0x3, 0); + UniEffect (UNI_S3MEFFECTD, inf); + break; + /* Support all these above, since ST2 can LOAD these values but can + actually only play up to J - and J is only half-way implemented + in ST2 */ + case 0x18: /* Xxx amiga panning command 8xx */ + UniPTEffect (0x8, inf); + break; + } +} + +static UBYTE * +STM_ConvertTrack (STMNOTE * n) +{ + int t; + + UniReset (); + for (t = 0; t < 64; t++) + { + STM_ConvertNote (n); + UniNewline (); + n += of.numchn; + } + return UniDup (); +} + +static BOOL +STM_LoadPatterns (void) +{ + int t, s, tracks = 0; + + if (!AllocPatterns ()) + return 0; + if (!AllocTracks ()) + return 0; + + /* Allocate temporary buffer for loading and converting the patterns */ + for (t = 0; t < of.numpat; t++) + { + for (s = 0; s < (64U * of.numchn); s++) + { + stmbuf[s].note = _mm_read_UBYTE (modreader); + stmbuf[s].insvol = _mm_read_UBYTE (modreader); + stmbuf[s].volcmd = _mm_read_UBYTE (modreader); + stmbuf[s].cmdinf = _mm_read_UBYTE (modreader); + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + for (s = 0; s < of.numchn; s++) + if (!(of.tracks[tracks++] = STM_ConvertTrack (stmbuf + s))) + return 0; + } + return 1; +} + +BOOL +STM_Load (BOOL curious) +{ + int t; + ULONG ourISA; /* We must generate our own ISA, it's not stored in stm */ + SAMPLE *q; + + /* try to read stm header */ + _mm_read_string (mh->songname, 20, modreader); + _mm_read_string (mh->trackername, 8, modreader); + mh->unused = _mm_read_UBYTE (modreader); + mh->filetype = _mm_read_UBYTE (modreader); + mh->ver_major = _mm_read_UBYTE (modreader); + mh->ver_minor = _mm_read_UBYTE (modreader); + mh->inittempo = _mm_read_UBYTE (modreader); + if (!mh->inittempo) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + mh->numpat = _mm_read_UBYTE (modreader); + mh->globalvol = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh->reserved, 13, modreader); + + for (t = 0; t < 31; t++) + { + STMSAMPLE *s = &mh->sample[t]; /* STM sample data */ + + _mm_read_string (s->filename, 12, modreader); + s->unused = _mm_read_UBYTE (modreader); + s->instdisk = _mm_read_UBYTE (modreader); + s->reserved = _mm_read_I_UWORD (modreader); + s->length = _mm_read_I_UWORD (modreader); + s->loopbeg = _mm_read_I_UWORD (modreader); + s->loopend = _mm_read_I_UWORD (modreader); + s->volume = _mm_read_UBYTE (modreader); + s->reserved2 = _mm_read_UBYTE (modreader); + s->c2spd = _mm_read_I_UWORD (modreader); + s->reserved3 = _mm_read_I_ULONG (modreader); + s->isa = _mm_read_I_UWORD (modreader); + } + _mm_read_UBYTES (mh->patorder, 128, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + for (t = 0; t < NUMTRACKERS; t++) + if (!memcmp (mh->trackername, STM_Signatures[t], 8)) + break; + of.modtype = strdup (STM_Version[t]); + of.songname = DupStr (mh->songname, 20, 1); /* make a cstr of songname */ + of.numpat = mh->numpat; + of.inittempo = 125; /* mh->inittempo+0x1c; */ + of.initspeed = mh->inittempo >> 4; + of.numchn = 4; /* get number of channels */ + of.reppos = 0; + of.flags |= UF_S3MSLIDES; + + t = 0; + if (!AllocPositions (0x80)) + return 0; + /* 99 terminates the patorder list */ + while ((mh->patorder[t] != 99) && (mh->patorder[t] < mh->numpat)) + { + of.positions[t] = mh->patorder[t]; + t++; + } + if (mh->patorder[t] != 99) + t++; + of.numpos = t; + of.numtrk = of.numpat * of.numchn; + of.numins = of.numsmp = 31; + + if (!AllocSamples ()) + return 0; + if (!STM_LoadPatterns ()) + return 0; + ourISA = _mm_ftell (modreader); + ourISA = (ourISA + 15) & 0xfffffff0; /* normalize */ + + for (q = of.samples, t = 0; t < of.numsmp; t++, q++) + { + /* load sample info */ + q->samplename = DupStr (mh->sample[t].filename, 12, 1); + q->speed = mh->sample[t].c2spd; + q->volume = mh->sample[t].volume; + q->length = mh->sample[t].length; + if ( /*(!mh->sample[t].volume)|| */ (q->length == 1)) + q->length = 0; + q->loopstart = mh->sample[t].loopbeg; + q->loopend = mh->sample[t].loopend; + q->seekpos = ourISA; + + ourISA += q->length; + ourISA = (ourISA + 15) & 0xfffffff0; /* normalize */ + + /* contrary to the STM specs, sample data is signed */ + q->flags = SF_SIGNED; + + /* fix for bad STMs */ + if (q->loopstart >= q->length) + q->loopstart = q->loopend = 0; + + if ((q->loopend > 0) && (q->loopend != 0xffff)) + q->flags |= SF_LOOP; + /* fix replen if repend>length */ + if (q->loopend > q->length) + q->loopend = q->length; + } + return 1; +} + +CHAR * +STM_LoadTitle (void) +{ + CHAR s[20]; + + _mm_fseek (modreader, 0, SEEK_SET); + if (!_mm_read_UBYTES (s, 20, modreader)) + return NULL; + + return (DupStr (s, 20, 1)); +} + +/*========== Loader information */ + +MLOADER load_stm = +{ + NULL, + "STM", + "STM (Scream Tracker)", + STM_Init, + STM_Test, + STM_Load, + STM_Cleanup, + STM_LoadTitle +}; + + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_stx.c TiMidity++-2.9.0/libunimod/load_stx.c --- TiMidity++-2.8.2/libunimod/load_stx.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_stx.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,489 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_stx.c,v 1.12 1999/10/25 16:31:41 miod Exp $ + + STMIK 0.2 (STX) module loader + +==============================================================================*/ + +/* + + Written by Claudio Matsuoka + + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +/* header */ +typedef struct STXHEADER + { + CHAR songname[20]; + CHAR scream[8]; + UWORD patsize; + UWORD unknown1; + UWORD patptr; + UWORD insptr; + UWORD chnptr; /* not sure */ + UWORD unknown2; + UWORD unknown3; + UBYTE mastermult; + UBYTE initspeed; + UWORD unknown4; + UWORD unknown5; + UWORD patnum; + UWORD insnum; + UWORD ordnum; + UWORD unknown6; + UWORD unknown7; + UWORD unknown8; + CHAR scrm[4]; + } +STXHEADER; + +/* sample information */ +typedef struct STXSAMPLE + { + UBYTE type; + CHAR filename[12]; + UBYTE memsegh; + UWORD memsegl; + ULONG length; + ULONG loopbeg; + ULONG loopend; + UBYTE volume; + UBYTE dsk; + UBYTE pack; + UBYTE flags; + ULONG c2spd; + UBYTE unused[12]; + CHAR sampname[28]; + CHAR scrs[4]; + } +STXSAMPLE; + +typedef struct STXNOTE + { + UBYTE note, ins, vol, cmd, inf; + } +STXNOTE; + +/*========== Loader variables */ + +static STXNOTE *stxbuf = NULL; /* pointer to a complete STX pattern */ +static STXHEADER *mh = NULL; +static UWORD *paraptr = NULL; /* parapointer array (see STX docs) */ + +/*========== Loader code */ + +static BOOL +STX_Test (void) +{ + UBYTE id[8]; + + _mm_fseek (modreader, 0x14, SEEK_SET); + if (!_mm_read_UBYTES (id, 8, modreader)) + return 0; + if (memcmp (id, "!Scream!", 8)) + return 0; + + _mm_fseek (modreader, 0x20, SEEK_CUR); + if (!_mm_read_UBYTES (id, 4, modreader)) + return 0; + if (memcmp (id, "SCRM", 4)) + return 0; + + return 1; +} + +static BOOL +STX_Init (void) +{ + if (!(stxbuf = (STXNOTE *) _mm_malloc (4 * 64 * sizeof (STXNOTE)))) + return 0; + if (!(mh = (STXHEADER *) _mm_malloc (sizeof (STXHEADER)))) + return 0; + if (!(poslookup = (UBYTE *) _mm_malloc (sizeof (UBYTE) * 256))) + return 0; + memset (poslookup, -1, 256); + + return 1; +} + +static void +STX_Cleanup (void) +{ + _mm_free (stxbuf); + _mm_free (paraptr); + _mm_free (poslookup); + _mm_free (mh); +} + +static BOOL +STX_ReadPattern (void) +{ + int row = 0, flag, ch; + STXNOTE *n, dummy; + + /* clear pattern data */ + memset (stxbuf, 255, 4 * 64 * sizeof (STXNOTE)); + + while (row < 64) + { + flag = _mm_read_UBYTE (modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if (flag) + { + ch = flag & 31; + + if ((ch >= 0) && (ch < 4)) + n = &stxbuf[(64U * ch) + row]; + else + n = &dummy; + + if (flag & 32) + { + n->note = _mm_read_UBYTE (modreader); + n->ins = _mm_read_UBYTE (modreader); + } + if (flag & 64) + n->vol = _mm_read_UBYTE (modreader); + if (flag & 128) + { + n->cmd = _mm_read_UBYTE (modreader); + n->inf = _mm_read_UBYTE (modreader); + } + } + else + row++; + } + return 1; +} + +static UBYTE * +STX_ConvertTrack (STXNOTE * tr) +{ + int t; + + UniReset (); + for (t = 0; t < 64; t++) + { + UBYTE note, ins, vol, cmd, inf; + + note = tr[t].note; + ins = tr[t].ins; + vol = tr[t].vol; + cmd = tr[t].cmd; + inf = tr[t].inf; + + if ((ins) && (ins != 255)) + UniInstrument (ins - 1); + if ((note) && (note != 255)) + { + if (note == 254) + { + UniPTEffect (0xc, 0); /* note cut command */ + vol = 255; + } + else + UniNote (24 + ((note >> 4) * OCTAVE) + (note & 0xf)); /* normal note */ + } + + if (vol < 255) + UniPTEffect (0xc, vol); + + if (cmd < 255) + switch (cmd) + { + case 1: /* Axx set speed to xx */ + UniPTEffect (0xf, inf >> 4); + break; + case 2: /* Bxx position jump */ + UniPTEffect (0xb, inf); + break; + case 3: /* Cxx patternbreak to row xx */ + UniPTEffect (0xd, (((inf & 0xf0) >> 4) * 10) + (inf & 0xf)); + break; + case 4: /* Dxy volumeslide */ + UniEffect (UNI_S3MEFFECTD, inf); + break; + case 5: /* Exy toneslide down */ + UniEffect (UNI_S3MEFFECTE, inf); + break; + case 6: /* Fxy toneslide up */ + UniEffect (UNI_S3MEFFECTF, inf); + break; + case 7: /* Gxx Tone portamento,speed xx */ + UniPTEffect (0x3, inf); + break; + case 8: /* Hxy vibrato */ + UniPTEffect (0x4, inf); + break; + case 9: /* Ixy tremor, ontime x, offtime y */ + UniEffect (UNI_S3MEFFECTI, inf); + break; + case 0: /* protracker arpeggio */ + if (!inf) + break; + /* fall through */ + case 0xa: /* Jxy arpeggio */ + UniPTEffect (0x0, inf); + break; + case 0xb: /* Kxy Dual command H00 & Dxy */ + UniPTEffect (0x4, 0); + UniEffect (UNI_S3MEFFECTD, inf); + break; + case 0xc: /* Lxy Dual command G00 & Dxy */ + UniPTEffect (0x3, 0); + UniEffect (UNI_S3MEFFECTD, inf); + break; + /* Support all these above, since ST2 can LOAD these values but can + actually only play up to J - and J is only half-way implemented + in ST2 */ + case 0x18: /* Xxx amiga panning command 8xx */ + UniPTEffect (0x8, inf); + break; + } + UniNewline (); + } + return UniDup (); +} + +static BOOL +STX_Load (BOOL curious) +{ + int t, u, track = 0; + int version = 0; + SAMPLE *q; + + /* try to read module header */ + _mm_read_string (mh->songname, 20, modreader); + _mm_read_string (mh->scream, 8, modreader); + mh->patsize = _mm_read_I_UWORD (modreader); + mh->unknown1 = _mm_read_I_UWORD (modreader); + mh->patptr = _mm_read_I_UWORD (modreader); + mh->insptr = _mm_read_I_UWORD (modreader); + mh->chnptr = _mm_read_I_UWORD (modreader); + mh->unknown2 = _mm_read_I_UWORD (modreader); + mh->unknown3 = _mm_read_I_UWORD (modreader); + mh->mastermult = _mm_read_UBYTE (modreader); + mh->initspeed = _mm_read_UBYTE (modreader) >> 4; + mh->unknown4 = _mm_read_I_UWORD (modreader); + mh->unknown5 = _mm_read_I_UWORD (modreader); + mh->patnum = _mm_read_I_UWORD (modreader); + mh->insnum = _mm_read_I_UWORD (modreader); + mh->ordnum = _mm_read_I_UWORD (modreader); + mh->unknown6 = _mm_read_I_UWORD (modreader); + mh->unknown7 = _mm_read_I_UWORD (modreader); + mh->unknown8 = _mm_read_I_UWORD (modreader); + _mm_read_string (mh->scrm, 4, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.songname = DupStr (mh->songname, 20, 1); + of.numpat = mh->patnum; + of.reppos = 0; + of.numins = of.numsmp = mh->insnum; + of.initspeed = mh->initspeed; + of.inittempo = 125; + of.numchn = 4; + of.flags |= UF_S3MSLIDES; + + if (!(paraptr = (UWORD *) _mm_malloc ((of.numins + of.numpat) * sizeof (UWORD)))) + return 0; + + /* read the instrument+pattern parapointers */ + _mm_fseek (modreader, mh->insptr << 4, SEEK_SET); + _mm_read_I_UWORDS (paraptr, of.numins, modreader); + _mm_fseek (modreader, mh->patptr << 4, SEEK_SET); + _mm_read_I_UWORDS (paraptr + of.numins, of.numpat, modreader); + + /* check module version */ + _mm_fseek (modreader, paraptr[of.numins] << 4, SEEK_SET); + version = _mm_read_I_UWORD (modreader); + if (version == mh->patsize) + { + version = 0x10; + of.modtype = strdup ("STMIK 0.2 (STM2STX 1.0)"); + } + else + { + version = 0x11; + of.modtype = strdup ("STMIK 0.2 (STM2STX 1.1)"); + } + + /* read the order data */ + _mm_fseek (modreader, (mh->chnptr << 4) + 32, SEEK_SET); + if (!AllocPositions (mh->ordnum)) + return 0; + for (t = 0; t < mh->ordnum; t++) + { + of.positions[t] = _mm_read_UBYTE (modreader); + _mm_fseek (modreader, 4, SEEK_CUR); + } + + of.numpos = 0; + poslookupcnt = mh->ordnum; + for (t = 0; t < mh->ordnum; t++) + { + of.positions[of.numpos] = of.positions[t]; + poslookup[t] = of.numpos; /* bug fix for freaky S3Ms */ + if (of.positions[t] < 254) + of.numpos++; + else + /* special end of song pattern */ + if ((of.positions[t] == 255) && (!curious)) + break; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* load samples */ + if (!AllocSamples ()) + return 0; + for (q = of.samples, t = 0; t < of.numins; t++, q++) + { + STXSAMPLE s; + + /* seek to instrument position */ + _mm_fseek (modreader, ((long) paraptr[t]) << 4, SEEK_SET); + /* and load sample info */ + s.type = _mm_read_UBYTE (modreader); + _mm_read_string (s.filename, 12, modreader); + s.memsegh = _mm_read_UBYTE (modreader); + s.memsegl = _mm_read_I_UWORD (modreader); + s.length = _mm_read_I_ULONG (modreader); + s.loopbeg = _mm_read_I_ULONG (modreader); + s.loopend = _mm_read_I_ULONG (modreader); + s.volume = _mm_read_UBYTE (modreader); + s.dsk = _mm_read_UBYTE (modreader); + s.pack = _mm_read_UBYTE (modreader); + s.flags = _mm_read_UBYTE (modreader); + s.c2spd = _mm_read_I_ULONG (modreader); + _mm_read_UBYTES (s.unused, 12, modreader); + _mm_read_string (s.sampname, 28, modreader); + _mm_read_string (s.scrs, 4, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr (s.sampname, 28, 1); + q->speed = s.c2spd; + q->length = s.length; + q->loopstart = s.loopbeg; + q->loopend = s.loopend; + q->volume = s.volume; + q->seekpos = (((long) s.memsegh) << 16 | s.memsegl) << 4; + q->flags |= SF_SIGNED; + + /* fix for bad converted STMs */ + if (q->loopstart >= q->length) + { + q->loopstart = q->loopend = 0; + s.flags &= ~1; + } + + if (s.flags & 1) + { + q->flags |= SF_LOOP; + if (q->loopend > q->length) + q->loopend = q->length; + } + if (s.flags & 4) + q->flags |= SF_16BITS; + } + + /* load pattern info */ + of.numtrk = of.numpat * of.numchn; + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + for (t = 0; t < of.numpat; t++) + { + /* seek to pattern position (+2 skip pattern length) */ + _mm_fseek (modreader, (((long) paraptr[of.numins + t]) << 4) + + (version == 0x10 ? 2 : 0), SEEK_SET); + if (!STX_ReadPattern ()) + return 0; + for (u = 0; u < of.numchn; u++) + if (!(of.tracks[track++] = STX_ConvertTrack (&stxbuf[u * 64]))) + return 0; + } + + return 1; +} + +static CHAR * +STX_LoadTitle (void) +{ + CHAR s[28]; + + _mm_fseek (modreader, 0, SEEK_SET); + if (!_mm_read_UBYTES (s, 20, modreader)) + return NULL; + + return (DupStr (s, 28, 1)); +} + +/*========== Loader information */ + +MLOADER load_stx = +{ + NULL, + "STX", + "STX (Scream Tracker Music Interface Kit)", + STX_Init, + STX_Test, + STX_Load, + STX_Cleanup, + STX_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_ult.c TiMidity++-2.9.0/libunimod/load_ult.c --- TiMidity++-2.8.2/libunimod/load_ult.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_ult.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,357 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_ult.c,v 1.27 1999/10/25 16:31:41 miod Exp $ + + Ultratracker (ULT) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +/* header */ +typedef struct ULTHEADER + { + CHAR id[16]; + CHAR songtitle[32]; + UBYTE reserved; + } +ULTHEADER; + +/* sample information */ +typedef struct ULTSAMPLE + { + CHAR samplename[32]; + CHAR dosname[12]; + SLONG loopstart; + SLONG loopend; + SLONG sizestart; + SLONG sizeend; + UBYTE volume; + UBYTE flags; + UWORD speed; + SWORD finetune; + } +ULTSAMPLE; + +typedef struct ULTEVENT + { + UBYTE note, sample, eff, dat1, dat2; + } +ULTEVENT; + +/*========== Loader variables */ + +#define ULTS_16BITS 4 +#define ULTS_LOOP 8 +#define ULTS_REVERSE 16 + +#define ULT_VERSION_LEN 18 +static CHAR ULT_Version[ULT_VERSION_LEN] = "Ultra Tracker v1.x"; + +static ULTEVENT ev; + +/*========== Loader code */ + +BOOL +ULT_Test (void) +{ + CHAR id[16]; + + if (!_mm_read_string (id, 15, modreader)) + return 0; + if (strncmp (id, "MAS_UTrack_V00", 14)) + return 0; + if ((id[14] < '1') || (id[14] > '4')) + return 0; + return 1; +} + +BOOL +ULT_Init (void) +{ + return 1; +} + +void +ULT_Cleanup (void) +{ +} + +static UBYTE +ReadUltEvent (ULTEVENT * event) +{ + UBYTE flag, rep = 1; + + flag = _mm_read_UBYTE (modreader); + if (flag == 0xfc) + { + rep = _mm_read_UBYTE (modreader); + event->note = _mm_read_UBYTE (modreader); + } + else + event->note = flag; + + event->sample = _mm_read_UBYTE (modreader); + event->eff = _mm_read_UBYTE (modreader); + event->dat1 = _mm_read_UBYTE (modreader); + event->dat2 = _mm_read_UBYTE (modreader); + + return rep; +} + +BOOL +ULT_Load (BOOL curious) +{ + int t, u, tracks = 0; + SAMPLE *q; + ULTSAMPLE s; + ULTHEADER mh; + UBYTE nos, noc, nop; + + /* try to read module header */ + _mm_read_string (mh.id, 15, modreader); + _mm_read_string (mh.songtitle, 32, modreader); + mh.reserved = _mm_read_UBYTE (modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + ULT_Version[ULT_VERSION_LEN - 1] = '3' + (mh.id[14] - '1'); + of.modtype = DupStr (ULT_Version, ULT_VERSION_LEN, 1); + of.initspeed = 6; + of.inittempo = 125; + of.reppos = 0; + + /* read songtext */ + if ((mh.id[14] > '1') && (mh.reserved)) + if (!ReadLinedComment (mh.reserved, 32)) + return 0; + + nos = _mm_read_UBYTE (modreader); + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + of.songname = DupStr (mh.songtitle, 32, 1); + of.numins = of.numsmp = nos; + + if (!AllocSamples ()) + return 0; + q = of.samples; + for (t = 0; t < nos; t++) + { + /* try to read sample info */ + _mm_read_string (s.samplename, 32, modreader); + _mm_read_string (s.dosname, 12, modreader); + s.loopstart = _mm_read_I_ULONG (modreader); + s.loopend = _mm_read_I_ULONG (modreader); + s.sizestart = _mm_read_I_ULONG (modreader); + s.sizeend = _mm_read_I_ULONG (modreader); + s.volume = _mm_read_UBYTE (modreader); + s.flags = _mm_read_UBYTE (modreader); + s.speed = (mh.id[14] >= '4') ? _mm_read_I_UWORD (modreader) : 8363; + s.finetune = _mm_read_I_SWORD (modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr (s.samplename, 32, 1); + /* The correct formula for the coefficient would be + pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point + here, we'll use a first order approximation here. + 1/567290 == Ln(2)/OCTAVE/32768 */ + q->speed = s.speed + s.speed * (((SLONG) s.speed * (SLONG) s.finetune) / 567290); + q->length = s.sizeend - s.sizestart; + q->volume = s.volume >> 2; + q->loopstart = s.loopstart; + q->loopend = s.loopend; + q->flags = SF_SIGNED; + if (s.flags & ULTS_LOOP) + q->flags |= SF_LOOP; + if (s.flags & ULTS_16BITS) + { + s.sizeend += (s.sizeend - s.sizestart); + s.sizestart <<= 1; + q->flags |= SF_16BITS; + q->loopstart >>= 1; + q->loopend >>= 1; + } + q++; + } + + if (!AllocPositions (256)) + return 0; + for (t = 0; t < 256; t++) + of.positions[t] = _mm_read_UBYTE (modreader); + for (t = 0; t < 256; t++) + if (of.positions[t] == 255) + break; + of.numpos = t; + + noc = _mm_read_UBYTE (modreader); + nop = _mm_read_UBYTE (modreader); + + of.numchn = ++noc; + of.numpat = ++nop; + of.numtrk = of.numchn * of.numpat; + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + for (u = 0; u < of.numchn; u++) + for (t = 0; t < of.numpat; t++) + of.patterns[(t * of.numchn) + u] = tracks++; + + /* read pan position table for v1.5 and higher */ + if (mh.id[14] >= '3') + for (t = 0; t < of.numchn; t++) + of.panning[t] = _mm_read_UBYTE (modreader) << 4; + + for (t = 0; t < of.numtrk; t++) + { + int rep, row = 0; + + UniReset (); + while (row < 64) + { + rep = ReadUltEvent (&ev); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_TRACK; + return 0; + } + + while (rep--) + { + UBYTE eff; + int offset; + + if (ev.sample) + UniInstrument (ev.sample - 1); + if (ev.note) + UniNote (ev.note + 2 * OCTAVE - 1); + + /* first effect - various fixes by Alexander Kerkhove and + Thomas Neumann */ + eff = ev.eff >> 4; + switch (eff) + { + case 0x3: /* tone portamento */ + UniEffect (UNI_ITEFFECTG, ev.dat2); + break; + case 0x5: + break; + case 0x9: /* sample offset */ + offset = (ev.dat2 << 8) | ((ev.eff & 0xf) == 9 ? ev.dat1 : 0); + UniEffect (UNI_ULTEFFECT9, offset); + break; + case 0xb: /* panning */ + UniPTEffect (8, ev.dat2 * 0xf); + break; + case 0xc: /* volume */ + UniPTEffect (eff, ev.dat2 >> 2); + break; + default: + UniPTEffect (eff, ev.dat2); + break; + } + + /* second effect */ + eff = ev.eff & 0xf; + switch (eff) + { + case 0x3: /* tone portamento */ + UniEffect (UNI_ITEFFECTG, ev.dat1); + break; + case 0x5: + break; + case 0x9: /* sample offset */ + if ((ev.eff >> 4) != 9) + UniEffect (UNI_ULTEFFECT9, ((UWORD) ev.dat1) << 8); + break; + case 0xb: /* panning */ + UniPTEffect (8, ev.dat1 * 0xf); + break; + case 0xc: /* volume */ + UniPTEffect (eff, ev.dat1 >> 2); + break; + default: + UniPTEffect (eff, ev.dat1); + break; + } + + UniNewline (); + row++; + } + } + if (!(of.tracks[t] = UniDup ())) + return 0; + } + return 1; +} + +CHAR * +ULT_LoadTitle (void) +{ + CHAR s[32]; + + _mm_fseek (modreader, 15, SEEK_SET); + if (!_mm_read_UBYTES (s, 32, modreader)) + return NULL; + + return (DupStr (s, 32, 1)); +} + +/*========== Loader information */ + +MLOADER load_ult = +{ + NULL, + "ULT", + "ULT (UltraTracker)", + ULT_Init, + ULT_Test, + ULT_Load, + ULT_Cleanup, + ULT_LoadTitle +}; + + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_uni.c TiMidity++-2.9.0/libunimod/load_uni.c --- TiMidity++-2.8.2/libunimod/load_uni.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_uni.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,782 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_uni.c,v 1.13 1999/10/25 16:31:41 miod Exp $ + + UNIMOD (libmikmod's and APlayer's internal module format) loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +typedef struct UNIHEADER + { + CHAR id[4]; + UBYTE numchn; + UWORD numpos; + UWORD reppos; + UWORD numpat; + UWORD numtrk; + UWORD numins; + UWORD numsmp; + UBYTE initspeed; + UBYTE inittempo; + UBYTE initvolume; + UBYTE flags; + UBYTE numvoices; + + UBYTE positions[256]; + UBYTE panning[32]; + } +UNIHEADER; + +typedef struct UNISMP05 + { + UWORD c2spd; + UWORD transpose; + UBYTE volume; + UBYTE panning; + ULONG length; + ULONG loopstart; + ULONG loopend; + UWORD flags; + CHAR *samplename; + UBYTE vibtype; + UBYTE vibsweep; + UBYTE vibdepth; + UBYTE vibrate; + } +UNISMP05; + +/*========== Loader variables */ + +static UWORD universion; +static UNIHEADER mh; + +#define UNI_SMPINCR 64 +static UNISMP05 *wh = NULL, *s = NULL; + +/*========== Loader code */ + +static char * +readstring (void) +{ + char *s = NULL; + UWORD len; + + len = _mm_read_I_UWORD (modreader); + if (len) + { + s = _mm_malloc (len + 1); + _mm_read_UBYTES (s, len, modreader); + s[len] = 0; + } + return s; +} + +BOOL +UNI_Test (void) +{ + char id[6]; + + if (!_mm_read_UBYTES (id, 6, modreader)) + return 0; + + /* UNIMod created by MikCvt */ + if (!(memcmp (id, "UN0", 3))) + { + if ((id[3] >= '4') && (id[3] <= '6')) + return 1; + } + /* UNIMod created by APlayer */ + if (!(memcmp (id, "APUN\01", 5))) + { + if ((id[5] >= 1) && (id[5] <= 3)) + return 1; + } + return 0; +} + +BOOL +UNI_Init (void) +{ + return 1; +} + +void +UNI_Cleanup (void) +{ + _mm_free (wh); + s = NULL; +} + +static UBYTE * +readtrack (void) +{ + UBYTE *t; + UWORD len; + int cur = 0, chunk; + + if (universion >= 6) + len = _mm_read_M_UWORD (modreader); + else + len = _mm_read_I_UWORD (modreader); + + if (!len) + return NULL; + if (!(t = _mm_malloc (len))) + return NULL; + _mm_read_UBYTES (t, len, modreader); + + /* Check if the track is correct */ + while (1) + { + chunk = t[cur++]; + if (!chunk) + break; + chunk = (chunk & 0x1f) - 1; + while (chunk > 0) + { + int opcode, oplen; + + if (cur >= len) + { + free (t); + return NULL; + } + opcode = t[cur]; + + /* Remap opcodes */ + if (universion <= 5) + { + if (opcode > 29) + { + free (t); + return NULL; + } + switch (opcode) + { + /* UNI_NOTE .. UNI_S3MEFFECTQ are the same */ + case 25: + opcode = UNI_S3MEFFECTT; + break; + case 26: + opcode = UNI_XMEFFECTA; + break; + case 27: + opcode = UNI_XMEFFECTG; + break; + case 28: + opcode = UNI_XMEFFECTH; + break; + case 29: + opcode = UNI_XMEFFECTP; + break; + } + } + else + { + if (opcode > UNI_ITEFFECTP) + { + /* APlayer < 1.03 does not have ITEFFECTT */ + if (universion < 0x103) + opcode++; + /* APlayer < 1.02 does not have ITEFFECTZ */ + if ((opcode > UNI_ITEFFECTY) && (universion < 0x102)) + opcode++; + } + } + + if ((!opcode) || (opcode >= UNI_LAST)) + { + free (t); + return NULL; + } + oplen = unioperands[opcode] + 1; + cur += oplen; + chunk -= oplen; + } + if ((chunk < 0) || (cur >= len)) + { + free (t); + return NULL; + } + } + return t; +} + +static BOOL +loadsmp6 (void) +{ + int t; + SAMPLE *s; + + s = of.samples; + for (t = 0; t < of.numsmp; t++, s++) + { + int flags; + + flags = _mm_read_M_UWORD (modreader); + s->flags = 0; + if (flags & 0x0100) + s->flags |= SF_REVERSE; + if (flags & 0x0004) + s->flags |= SF_STEREO; + if (flags & 0x0002) + s->flags |= SF_SIGNED; + if (flags & 0x0001) + s->flags |= SF_16BITS; + /* convert flags */ + if (universion >= 0x102) + { + if (flags & 0x0800) + s->flags |= SF_UST_LOOP; + if (flags & 0x0400) + s->flags |= SF_OWNPAN; + if (flags & 0x0200) + s->flags |= SF_SUSTAIN; + if (flags & 0x0080) + s->flags |= SF_BIDI; + if (flags & 0x0040) + s->flags |= SF_LOOP; + if (flags & 0x0020) + s->flags |= SF_ITPACKED; + if (flags & 0x0010) + s->flags |= SF_DELTA; + if (flags & 0x0008) + s->flags |= SF_BIG_ENDIAN; + } + else + { + if (flags & 0x400) + s->flags |= SF_UST_LOOP; + if (flags & 0x200) + s->flags |= SF_OWNPAN; + if (flags & 0x080) + s->flags |= SF_SUSTAIN; + if (flags & 0x040) + s->flags |= SF_BIDI; + if (flags & 0x020) + s->flags |= SF_LOOP; + if (flags & 0x010) + s->flags |= SF_BIG_ENDIAN; + if (flags & 0x008) + s->flags |= SF_DELTA; + } + + s->speed = _mm_read_M_ULONG (modreader); + s->volume = _mm_read_UBYTE (modreader); + s->panning = _mm_read_M_UWORD (modreader); + s->length = _mm_read_M_ULONG (modreader); + s->loopstart = _mm_read_M_ULONG (modreader); + s->loopend = _mm_read_M_ULONG (modreader); + s->susbegin = _mm_read_M_ULONG (modreader); + s->susend = _mm_read_M_ULONG (modreader); + s->globvol = _mm_read_UBYTE (modreader); + s->vibflags = _mm_read_UBYTE (modreader); + s->vibtype = _mm_read_UBYTE (modreader); + s->vibsweep = _mm_read_UBYTE (modreader); + s->vibdepth = _mm_read_UBYTE (modreader); + s->vibrate = _mm_read_UBYTE (modreader); + + s->samplename = readstring (); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + } + return 1; +} + +static BOOL +loadinstr6 (void) +{ + int t, w; + INSTRUMENT *i; + + i = of.instruments; + for (t = 0; t < of.numins; t++, i++) + { + i->flags = _mm_read_UBYTE (modreader); + i->nnatype = _mm_read_UBYTE (modreader); + i->dca = _mm_read_UBYTE (modreader); + i->dct = _mm_read_UBYTE (modreader); + i->globvol = _mm_read_UBYTE (modreader); + i->panning = _mm_read_M_UWORD (modreader); + i->pitpansep = _mm_read_UBYTE (modreader); + i->pitpancenter = _mm_read_UBYTE (modreader); + i->rvolvar = _mm_read_UBYTE (modreader); + i->rpanvar = _mm_read_UBYTE (modreader); + i->volfade = _mm_read_M_UWORD (modreader); + +#define UNI_LoadEnvelope6(name) \ + i->##name##flg=_mm_read_UBYTE(modreader); \ + i->##name##pts=_mm_read_UBYTE(modreader); \ + i->##name##susbeg=_mm_read_UBYTE(modreader); \ + i->##name##susend=_mm_read_UBYTE(modreader); \ + i->##name##beg=_mm_read_UBYTE(modreader); \ + i->##name##end=_mm_read_UBYTE(modreader); \ + for(w=0;w<(universion>=0x100?32:i->##name##pts);w++) { \ + i->##name##env[w].pos=_mm_read_M_SWORD(modreader); \ + i->##name##env[w].val=_mm_read_M_SWORD(modreader); \ + } + + UNI_LoadEnvelope6 (vol); + UNI_LoadEnvelope6 (pan); + UNI_LoadEnvelope6 (pit); +#undef UNI_LoadEnvelope6 + + if (universion == 0x103) + _mm_read_M_UWORDS (i->samplenumber, 120, modreader); + else + for (w = 0; w < 120; w++) + i->samplenumber[w] = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (i->samplenote, 120, modreader); + + i->insname = readstring (); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + } + return 1; +} + +static BOOL +loadinstr5 (void) +{ + INSTRUMENT *i; + int t; + UWORD wavcnt = 0; + UBYTE vibtype, vibsweep, vibdepth, vibrate; + + i = of.instruments; + for (of.numsmp = t = 0; t < of.numins; t++, i++) + { + int u, numsmp; + + numsmp = _mm_read_UBYTE (modreader); + + memset (i->samplenumber, 0xff, INSTNOTES * sizeof (UWORD)); + for (u = 0; u < 96; u++) + i->samplenumber[u] = of.numsmp + _mm_read_UBYTE (modreader); + +#define UNI_LoadEnvelope5(name) \ + i->##name##flg=_mm_read_UBYTE(modreader); \ + i->##name##pts=_mm_read_UBYTE(modreader); \ + i->##name##susbeg=_mm_read_UBYTE(modreader); \ + i->##name##susend=i->##name##susbeg; \ + i->##name##beg=_mm_read_UBYTE(modreader); \ + i->##name##end=_mm_read_UBYTE(modreader); \ + for(u=0;u<12;u++) { \ + i->##name##env[u].pos=_mm_read_I_SWORD(modreader); \ + i->##name##env[u].val=_mm_read_I_SWORD(modreader); \ + } + + UNI_LoadEnvelope5 (vol); + UNI_LoadEnvelope5 (pan); +#undef UNI_LoadEnvelope5 + + vibtype = _mm_read_UBYTE (modreader); + vibsweep = _mm_read_UBYTE (modreader); + vibdepth = _mm_read_UBYTE (modreader); + vibrate = _mm_read_UBYTE (modreader); + + i->volfade = _mm_read_I_UWORD (modreader); + i->insname = readstring (); + + for (u = 0; u < numsmp; u++, s++, of.numsmp++) + { + /* Allocate more room for sample information if necessary */ + if (of.numsmp + u == wavcnt) + { + wavcnt += UNI_SMPINCR; + if (!(wh = realloc (wh, wavcnt * sizeof (UNISMP05)))) + { + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + s = wh + (wavcnt - UNI_SMPINCR); + } + + s->c2spd = _mm_read_I_UWORD (modreader); + s->transpose = _mm_read_SBYTE (modreader); + s->volume = _mm_read_UBYTE (modreader); + s->panning = _mm_read_UBYTE (modreader); + s->length = _mm_read_I_ULONG (modreader); + s->loopstart = _mm_read_I_ULONG (modreader); + s->loopend = _mm_read_I_ULONG (modreader); + s->flags = _mm_read_I_UWORD (modreader); + s->samplename = readstring (); + + s->vibtype = vibtype; + s->vibsweep = vibsweep; + s->vibdepth = vibdepth; + s->vibrate = vibrate; + + if (_mm_eof (modreader)) + { + free (wh); + wh = NULL; + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + } + } + + /* sanity check */ + if (!of.numsmp) + { + if (wh) + { + free (wh); + wh = NULL; + } + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + return 1; +} + +static BOOL +loadsmp5 (void) +{ + int t, u; + SAMPLE *q; + INSTRUMENT *d; + + q = of.samples; + s = wh; + for (u = 0; u < of.numsmp; u++, q++, s++) + { + q->samplename = s->samplename; + + q->length = s->length; + q->loopstart = s->loopstart; + q->loopend = s->loopend; + q->volume = s->volume; + q->speed = s->c2spd; + q->panning = s->panning; + q->vibtype = s->vibtype; + q->vibsweep = s->vibsweep; + q->vibdepth = s->vibdepth; + q->vibrate = s->vibrate; + + /* convert flags */ + q->flags = 0; + if (s->flags & 128) + q->flags |= SF_REVERSE; + if (s->flags & 64) + q->flags |= SF_SUSTAIN; + if (s->flags & 32) + q->flags |= SF_BIDI; + if (s->flags & 16) + q->flags |= SF_LOOP; + if (s->flags & 8) + q->flags |= SF_BIG_ENDIAN; + if (s->flags & 4) + q->flags |= SF_DELTA; + if (s->flags & 2) + q->flags |= SF_SIGNED; + if (s->flags & 1) + q->flags |= SF_16BITS; + } + + d = of.instruments; + s = wh; + for (u = 0; u < of.numins; u++, d++) + for (t = 0; t < INSTNOTES; t++) + d->samplenote[t] = (d->samplenumber[t] >= of.numsmp) ? + 255 : (t + s[d->samplenumber[t]].transpose); + + free (wh); + wh = NULL; + + return 1; +} + +BOOL +UNI_Load (BOOL curious) +{ + int t; + char *modtype, *oldtype = NULL; + INSTRUMENT *d; + SAMPLE *q; + + /* read module header */ + _mm_read_UBYTES (mh.id, 4, modreader); + if (mh.id[3] != 'N') + universion = mh.id[3] - '0'; + else + universion = 0x100; + + if (universion >= 6) + { + if (universion == 6) + _mm_read_UBYTE (modreader); + else + universion = _mm_read_M_UWORD (modreader); + + mh.flags = _mm_read_M_UWORD (modreader); + mh.numchn = _mm_read_UBYTE (modreader); + mh.numvoices = _mm_read_UBYTE (modreader); + mh.numpos = _mm_read_M_UWORD (modreader); + mh.numpat = _mm_read_M_UWORD (modreader); + mh.numtrk = _mm_read_M_UWORD (modreader); + mh.numins = _mm_read_M_UWORD (modreader); + mh.numsmp = _mm_read_M_UWORD (modreader); + mh.reppos = _mm_read_M_UWORD (modreader); + mh.initspeed = _mm_read_UBYTE (modreader); + mh.inittempo = _mm_read_UBYTE (modreader); + mh.initvolume = _mm_read_UBYTE (modreader); + + mh.flags &= (UF_XMPERIODS | UF_LINEAR | UF_INST | UF_NNA); + } + else + { + mh.numchn = _mm_read_UBYTE (modreader); + mh.numpos = _mm_read_I_UWORD (modreader); + mh.reppos = (universion == 5) ? _mm_read_I_UWORD (modreader) : 0; + mh.numpat = _mm_read_I_UWORD (modreader); + mh.numtrk = _mm_read_I_UWORD (modreader); + mh.numins = _mm_read_I_UWORD (modreader); + mh.initspeed = _mm_read_UBYTE (modreader); + mh.inittempo = _mm_read_UBYTE (modreader); + _mm_read_UBYTES (mh.positions, 256, modreader); + _mm_read_UBYTES (mh.panning, 32, modreader); + mh.flags = _mm_read_UBYTE (modreader); + + mh.flags &= (UF_XMPERIODS | UF_LINEAR); + mh.flags |= UF_INST | UF_NOWRAP; + } + + /* set module parameters */ + of.flags = mh.flags; + of.numchn = mh.numchn; + of.numpos = mh.numpos; + of.numpat = mh.numpat; + of.numtrk = mh.numtrk; + of.numins = mh.numins; + of.reppos = mh.reppos; + of.initspeed = mh.initspeed; + of.inittempo = mh.inittempo; + + of.songname = readstring (); + if (universion < 0x102) + oldtype = readstring (); + if (oldtype) + { + int len = strlen (oldtype) + 20; + if (!(modtype = _mm_malloc (len))) + return 0; +#ifdef HAVE_SNPRINTF + snprintf (modtype, len, "%s (was %s)", (universion >= 0x100) ? "APlayer" : "MikCvt2", oldtype); +#else + sprintf (modtype, "%s (was %s)", (universion >= 0x100) ? "APlayer" : "MikCvt2", oldtype); +#endif + } + else + { + if (!(modtype = _mm_malloc (10))) + return 0; +#ifdef HAVE_SNPRINTF + snprintf (modtype, 10, "%s", (universion >= 0x100) ? "APlayer" : "MikCvt3"); +#else + sprintf (modtype, "%s", (universion >= 0x100) ? "APlayer" : "MikCvt3"); +#endif + } + of.modtype = strdup (modtype); + free (modtype); + free (oldtype); + of.comment = readstring (); + + if (universion >= 6) + { + of.numvoices = mh.numvoices; + of.initvolume = mh.initvolume; + } + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* positions */ + if (!AllocPositions (of.numpos)) + return 0; + if (universion >= 6) + { + if (universion >= 0x100) + _mm_read_M_UWORDS (of.positions, of.numpos, modreader); + else + for (t = 0; t < of.numpos; t++) + of.positions[t] = _mm_read_UBYTE (modreader); + _mm_read_M_UWORDS (of.panning, of.numchn, modreader); + _mm_read_UBYTES (of.chanvol, of.numchn, modreader); + } + else + { + if ((mh.numpos > 256) || (mh.numchn > 32)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + for (t = 0; t < of.numpos; t++) + of.positions[t] = mh.positions[t]; + for (t = 0; t < of.numchn; t++) + of.panning[t] = mh.panning[t]; + } + + /* instruments and samples */ + if (universion >= 6) + { + of.numsmp = mh.numsmp; + if (!AllocSamples ()) + return 0; + if (!loadsmp6 ()) + return 0; + + if (of.flags & UF_INST) + { + if (!AllocInstruments ()) + return 0; + if (!loadinstr6 ()) + return 0; + } + } + else + { + if (!AllocInstruments ()) + return 0; + if (!loadinstr5 ()) + return 0; + if (!AllocSamples ()) + { + if (wh) + { + free (wh); + wh = NULL; + } + return 0; + } + if (!loadsmp5 ()) + return 0; + + /* check if the original file had no instruments */ + if (of.numsmp == of.numins) + { + for (t = 0, d = of.instruments; t < of.numins; t++, d++) + { + int u; + + if ((d->volpts) || (d->panpts) || (d->globvol != 64)) + break; + for (u = 0; u < 96; u++) + if ((d->samplenumber[u] != t) || (d->samplenote[u] != u)) + break; + if (u != 96) + break; + } + if (t == of.numins) + { + of.flags &= ~UF_INST; + of.flags &= ~UF_NOWRAP; + for (t = 0, d = of.instruments, q = of.samples; t < of.numins; t++, d++, q++) + { + q->samplename = d->insname; + d->insname = NULL; + } + } + } + } + + /* patterns */ + if (!AllocPatterns ()) + return 0; + if (universion >= 6) + { + _mm_read_M_UWORDS (of.pattrows, of.numpat, modreader); + _mm_read_M_UWORDS (of.patterns, of.numpat * of.numchn, modreader); + } + else + { + _mm_read_I_UWORDS (of.pattrows, of.numpat, modreader); + _mm_read_I_UWORDS (of.patterns, of.numpat * of.numchn, modreader); + } + + /* tracks */ + if (!AllocTracks ()) + return 0; + for (t = 0; t < of.numtrk; t++) + if (!(of.tracks[t] = readtrack ())) + { + _mm_errno = MMERR_LOADING_TRACK; + return 0; + } + + return 1; +} + +CHAR * +UNI_LoadTitle (void) +{ + UBYTE ver; + int posit[3] = + {304, 306, 26}; + + _mm_fseek (modreader, 3, SEEK_SET); + ver = _mm_read_UBYTE (modreader); + if (ver == 'N') + ver = '6'; + + _mm_fseek (modreader, posit[ver - '4'], SEEK_SET); + return readstring (); +} + +/*========== Loader information */ + +MLOADER load_uni = +{ + NULL, + "UNI", + "APUN (APlayer) and UNI (MikMod)", + UNI_Init, + UNI_Test, + UNI_Load, + UNI_Cleanup, + UNI_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/load_xm.c TiMidity++-2.9.0/libunimod/load_xm.c --- TiMidity++-2.8.2/libunimod/load_xm.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/load_xm.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,883 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: load_xm.c,v 1.32 1999/10/25 16:31:41 miod Exp $ + + Fasttracker (XM) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "unimod_priv.h" + +/*========== Module structure */ + +typedef struct XMHEADER + { + CHAR id[17]; /* ID text: 'Extended module: ' */ + CHAR songname[21]; /* Module name */ + CHAR trackername[20]; /* Tracker name */ + UWORD version; /* Version number */ + ULONG headersize; /* Header size */ + UWORD songlength; /* Song length (in patten order table) */ + UWORD restart; /* Restart position */ + UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */ + UWORD numpat; /* Number of patterns (max 256) */ + UWORD numins; /* Number of instruments (max 128) */ + UWORD flags; + UWORD tempo; /* Default tempo */ + UWORD bpm; /* Default BPM */ + UBYTE orders[256]; /* Pattern order table */ + } +XMHEADER; + +typedef struct XMINSTHEADER + { + ULONG size; /* Instrument size */ + CHAR name[22]; /* Instrument name */ + UBYTE type; /* Instrument type (always 0) */ + UWORD numsmp; /* Number of samples in instrument */ + ULONG ssize; + } +XMINSTHEADER; + +#define XMENVCNT (12*2) +#define XMNOTECNT (8*OCTAVE) +typedef struct XMPATCHHEADER + { + UBYTE what[XMNOTECNT]; /* Sample number for all notes */ + UWORD volenv[XMENVCNT]; /* Points for volume envelope */ + UWORD panenv[XMENVCNT]; /* Points for panning envelope */ + UBYTE volpts; /* Number of volume points */ + UBYTE panpts; /* Number of panning points */ + UBYTE volsus; /* Volume sustain point */ + UBYTE volbeg; /* Volume loop start point */ + UBYTE volend; /* Volume loop end point */ + UBYTE pansus; /* Panning sustain point */ + UBYTE panbeg; /* Panning loop start point */ + UBYTE panend; /* Panning loop end point */ + UBYTE volflg; /* Volume type: bit 0: On; 1: Sustain; 2: Loop */ + UBYTE panflg; /* Panning type: bit 0: On; 1: Sustain; 2: Loop */ + UBYTE vibflg; /* Vibrato type */ + UBYTE vibsweep; /* Vibrato sweep */ + UBYTE vibdepth; /* Vibrato depth */ + UBYTE vibrate; /* Vibrato rate */ + UWORD volfade; /* Volume fadeout */ + } +XMPATCHHEADER; + +typedef struct XMWAVHEADER + { + ULONG length; /* Sample length */ + ULONG loopstart; /* Sample loop start */ + ULONG looplength; /* Sample loop length */ + UBYTE volume; /* Volume */ + SBYTE finetune; /* Finetune (signed byte -128..+127) */ + UBYTE type; /* Loop type */ + UBYTE panning; /* Panning (0-255) */ + SBYTE relnote; /* Relative note number (signed byte) */ + UBYTE reserved; + CHAR samplename[22]; /* Sample name */ + UBYTE vibtype; /* Vibrato type */ + UBYTE vibsweep; /* Vibrato sweep */ + UBYTE vibdepth; /* Vibrato depth */ + UBYTE vibrate; /* Vibrato rate */ + } +XMWAVHEADER; + +typedef struct XMPATHEADER + { + ULONG size; /* Pattern header length */ + UBYTE packing; /* Packing type (always 0) */ + UWORD numrows; /* Number of rows in pattern (1..256) */ + SWORD packsize; /* Packed patterndata size */ + } +XMPATHEADER; + +typedef struct XMNOTE + { + UBYTE note, ins, vol, eff, dat; + } +XMNOTE; + +/*========== Loader variables */ + +static XMNOTE *xmpat = NULL; +static XMHEADER *mh = NULL; + +/* increment unit for sample array reallocation */ +#define XM_SMPINCR 64 +static ULONG *nextwav = NULL; +static XMWAVHEADER *wh = NULL, *s = NULL; + +/*========== Loader code */ + +BOOL +XM_Test (void) +{ + UBYTE id[38]; + + if (!_mm_read_UBYTES (id, 38, modreader)) + return 0; + if (memcmp (id, "Extended Module: ", 17)) + return 0; + if (id[37] == 0x1a) + return 1; + return 0; +} + +BOOL +XM_Init (void) +{ + if (!(mh = (XMHEADER *) _mm_malloc (sizeof (XMHEADER)))) + return 0; + return 1; +} + +void +XM_Cleanup (void) +{ + _mm_free (mh); +} + +static int +XM_ReadNote (XMNOTE * n) +{ + UBYTE cmp, result = 1; + + memset (n, 0, sizeof (XMNOTE)); + cmp = _mm_read_UBYTE (modreader); + + if (cmp & 0x80) + { + if (cmp & 1) + { + result++; + n->note = _mm_read_UBYTE (modreader); + } + if (cmp & 2) + { + result++; + n->ins = _mm_read_UBYTE (modreader); + } + if (cmp & 4) + { + result++; + n->vol = _mm_read_UBYTE (modreader); + } + if (cmp & 8) + { + result++; + n->eff = _mm_read_UBYTE (modreader); + } + if (cmp & 16) + { + result++; + n->dat = _mm_read_UBYTE (modreader); + } + } + else + { + n->note = cmp; + n->ins = _mm_read_UBYTE (modreader); + n->vol = _mm_read_UBYTE (modreader); + n->eff = _mm_read_UBYTE (modreader); + n->dat = _mm_read_UBYTE (modreader); + result += 4; + } + return result; +} + +static UBYTE * +XM_Convert (XMNOTE * xmtrack, UWORD rows) +{ + int t; + UBYTE note, ins, vol, eff, dat; + + UniReset (); + for (t = 0; t < rows; t++) + { + note = xmtrack->note; + ins = xmtrack->ins; + vol = xmtrack->vol; + eff = xmtrack->eff; + dat = xmtrack->dat; + + if (note) + { + if (note > XMNOTECNT) + UniEffect (UNI_KEYFADE, 0); + else + UniNote (note - 1); + } + if (ins) + UniInstrument (ins - 1); + + switch (vol >> 4) + { + case 0x6: /* volslide down */ + if (vol & 0xf) + UniEffect (UNI_XMEFFECTA, vol & 0xf); + break; + case 0x7: /* volslide up */ + if (vol & 0xf) + UniEffect (UNI_XMEFFECTA, vol << 4); + break; + + /* volume-row fine volume slide is compatible with protracker + EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as + opposed to 'take the last sliding value'. */ + case 0x8: /* finevol down */ + UniPTEffect (0xe, 0xb0 | (vol & 0xf)); + break; + case 0x9: /* finevol up */ + UniPTEffect (0xe, 0xa0 | (vol & 0xf)); + break; + case 0xa: /* set vibrato speed */ + UniPTEffect (0x4, vol << 4); + break; + case 0xb: /* vibrato */ + UniPTEffect (0x4, vol & 0xf); + break; + case 0xc: /* set panning */ + UniPTEffect (0x8, vol << 4); + break; + case 0xd: /* panning slide left (only slide when data not zero) */ + if (vol & 0xf) + UniEffect (UNI_XMEFFECTP, vol & 0xf); + break; + case 0xe: /* panning slide right (only slide when data not zero) */ + if (vol & 0xf) + UniEffect (UNI_XMEFFECTP, vol << 4); + break; + case 0xf: /* tone porta */ + UniPTEffect (0x3, vol << 4); + break; + default: + if ((vol >= 0x10) && (vol <= 0x50)) + UniPTEffect (0xc, vol - 0x10); + } + + switch (eff) + { + case 0x4: + UniEffect (UNI_XMEFFECT4, dat); + break; + case 0xa: + UniEffect (UNI_XMEFFECTA, dat); + break; + case 0xe: /* Extended effects */ + switch (dat >> 4) + { + case 0x1: /* XM fine porta up */ + UniEffect (UNI_XMEFFECTE1, dat & 0xf); + break; + case 0x2: /* XM fine porta down */ + UniEffect (UNI_XMEFFECTE2, dat & 0xf); + break; + case 0xa: /* XM fine volume up */ + UniEffect (UNI_XMEFFECTEA, dat & 0xf); + break; + case 0xb: /* XM fine volume down */ + UniEffect (UNI_XMEFFECTEB, dat & 0xf); + break; + default: + UniPTEffect (eff, dat); + } + break; + case 'G' - 55: /* G - set global volume */ + UniEffect (UNI_XMEFFECTG, dat > 64 ? 64 : dat); + break; + case 'H' - 55: /* H - global volume slide */ + UniEffect (UNI_XMEFFECTH, dat); + break; + case 'K' - 55: /* K - keyOff and KeyFade */ + UniEffect (UNI_KEYFADE, dat); + break; + case 'L' - 55: /* L - set envelope position */ + UniEffect (UNI_XMEFFECTL, dat); + break; + case 'P' - 55: /* P - panning slide */ + UniEffect (UNI_XMEFFECTP, dat); + break; + case 'R' - 55: /* R - multi retrig note */ + UniEffect (UNI_S3MEFFECTQ, dat); + break; + case 'T' - 55: /* T - Tremor */ + UniEffect (UNI_S3MEFFECTI, dat); + break; + case 'X' - 55: + switch (dat >> 4) + { + case 1: /* X1 - Extra Fine Porta up */ + UniEffect (UNI_XMEFFECTX1, dat & 0xf); + break; + case 2: /* X2 - Extra Fine Porta down */ + UniEffect (UNI_XMEFFECTX2, dat & 0xf); + break; + } + break; + default: + if (eff <= 0xf) + { + /* the pattern jump destination is written in decimal, + but it seems some poor tracker software writes them + in hexadecimal... (sigh) */ + if (eff == 0xd) + /* don't change anything if we're sure it's in hexa */ + if ((((dat & 0xf0) >> 4) <= 9) && ((dat & 0xf) <= 9)) + /* otherwise, convert from dec to hex */ + dat = (((dat & 0xf0) >> 4) * 10) + (dat & 0xf); + UniPTEffect (eff, dat); + } + break; + } + UniNewline (); + xmtrack++; + } + return UniDup (); +} + +static BOOL +LoadPatterns (BOOL dummypat) +{ + int t, u, v, numtrk; + + if (!AllocTracks ()) + return 0; + if (!AllocPatterns ()) + return 0; + + numtrk = 0; + for (t = 0; t < mh->numpat; t++) + { + XMPATHEADER ph; + + ph.size = _mm_read_I_ULONG (modreader); + if (ph.size < (mh->version == 0x0102 ? 8 : 9)) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + ph.packing = _mm_read_UBYTE (modreader); + if (ph.packing) + { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + if (mh->version == 0x0102) + ph.numrows = _mm_read_UBYTE (modreader) + 1; + else + ph.numrows = _mm_read_I_UWORD (modreader); + ph.packsize = _mm_read_I_UWORD (modreader); + + ph.size -= (mh->version == 0x0102 ? 8 : 9); + if (ph.size) + _mm_fseek (modreader, ph.size, SEEK_CUR); + + of.pattrows[t] = ph.numrows; + + if (ph.numrows) + { + if (!(xmpat = (XMNOTE *) _mm_calloc (ph.numrows * of.numchn, sizeof (XMNOTE)))) + return 0; + + /* when packsize is 0, don't try to load a pattern.. it's empty. */ + if (ph.packsize) + for (u = 0; u < ph.numrows; u++) + for (v = 0; v < of.numchn; v++) + { + if (!ph.packsize) + break; + + ph.packsize -= XM_ReadNote (&xmpat[(v * ph.numrows) + u]); + if (ph.packsize < 0) + { + free (xmpat); + xmpat = NULL; + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + } + + if (ph.packsize) + { + _mm_fseek (modreader, ph.packsize, SEEK_CUR); + } + + if (_mm_eof (modreader)) + { + free (xmpat); + xmpat = NULL; + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + for (v = 0; v < of.numchn; v++) + of.tracks[numtrk++] = XM_Convert (&xmpat[v * ph.numrows], ph.numrows); + + free (xmpat); + xmpat = NULL; + } + else + { + for (v = 0; v < of.numchn; v++) + of.tracks[numtrk++] = XM_Convert (NULL, ph.numrows); + } + } + + if (dummypat) + { + of.pattrows[t] = 64; + if (!(xmpat = (XMNOTE *) _mm_calloc (64 * of.numchn, sizeof (XMNOTE)))) + return 0; + for (v = 0; v < of.numchn; v++) + of.tracks[numtrk++] = XM_Convert (&xmpat[v * 64], 64); + free (xmpat); + xmpat = NULL; + } + + return 1; +} + +static BOOL +LoadInstruments (void) +{ + int t, u; + INSTRUMENT *d; + long next = 0; + UWORD wavcnt = 0; + + if (!AllocInstruments ()) + return 0; + d = of.instruments; + for (t = 0; t < of.numins; t++, d++) + { + XMINSTHEADER ih; + long headend; + + memset (d->samplenumber, 0xff, INSTNOTES * sizeof (UWORD)); + + /* read instrument header */ + headend = _mm_ftell (modreader); + ih.size = _mm_read_I_ULONG (modreader); + headend += ih.size; + _mm_read_string (ih.name, 22, modreader); + ih.type = _mm_read_UBYTE (modreader); + ih.numsmp = _mm_read_I_UWORD (modreader); + + d->insname = DupStr (ih.name, 22, 1); + + if ((SWORD) ih.size > 29) + { + ih.ssize = _mm_read_I_ULONG (modreader); + if (((SWORD) ih.numsmp > 0) && (ih.numsmp <= XMNOTECNT)) + { + XMPATCHHEADER pth; + int p; + + _mm_read_UBYTES (pth.what, XMNOTECNT, modreader); + _mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader); + _mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader); + pth.volpts = _mm_read_UBYTE (modreader); + pth.panpts = _mm_read_UBYTE (modreader); + pth.volsus = _mm_read_UBYTE (modreader); + pth.volbeg = _mm_read_UBYTE (modreader); + pth.volend = _mm_read_UBYTE (modreader); + pth.pansus = _mm_read_UBYTE (modreader); + pth.panbeg = _mm_read_UBYTE (modreader); + pth.panend = _mm_read_UBYTE (modreader); + pth.volflg = _mm_read_UBYTE (modreader); + pth.panflg = _mm_read_UBYTE (modreader); + pth.vibflg = _mm_read_UBYTE (modreader); + pth.vibsweep = _mm_read_UBYTE (modreader); + pth.vibdepth = _mm_read_UBYTE (modreader); + pth.vibrate = _mm_read_UBYTE (modreader); + pth.volfade = _mm_read_I_UWORD (modreader); + + /* read the remainder of the header + (2 bytes for 1.03, 22 for 1.04) */ + for (u = headend - _mm_ftell (modreader); u; u--) + _mm_read_UBYTE (modreader); + + /* #@!$&% fix for K_OSPACE.XM */ + if (pth.volpts == 32) + pth.volpts = XMENVCNT / 2; + + if ((_mm_eof (modreader)) || (pth.volpts > XMENVCNT / 2) || (pth.panpts > XMENVCNT / 2)) + { + if (nextwav) + { + free (nextwav); + nextwav = NULL; + } + if (wh) + { + free (wh); + wh = NULL; + } + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + for (u = 0; u < XMNOTECNT; u++) + d->samplenumber[u] = pth.what[u] + of.numsmp; + d->volfade = pth.volfade; + +#define XM_ProcessEnvelope(name) \ + memcpy(d->##name##env,pth.##name##env,XMENVCNT); \ + if (pth.##name##flg&1) d->##name##flg|=EF_ON; \ + if (pth.##name##flg&2) d->##name##flg|=EF_SUSTAIN; \ + if (pth.##name##flg&4) d->##name##flg|=EF_LOOP; \ + d->##name##susbeg=d->##name##susend=pth.##name##sus; \ + d->##name##beg=pth.##name##beg; \ + d->##name##end=pth.##name##end; \ + d->##name##pts=pth.##name##pts; \ + \ + /* scale envelope */ \ + for (p=0;p##name##env[p].val<<=2; \ + \ + if ((d->##name##flg&EF_ON)&&(d->##name##pts<2)) \ + d->##name##flg&=~EF_ON; + + XM_ProcessEnvelope (vol); + XM_ProcessEnvelope (pan); +#undef XM_ProcessEnvelope + + /* Samples are stored outside the instrument struct now, so we + have to load them all into a temp area, count the of.numsmp + along the way and then do an AllocSamples() and move + everything over */ + if (mh->version > 0x0103) + next = 0; + for (u = 0; u < ih.numsmp; u++, s++) + { + /* Allocate more room for sample information if necessary */ + if (of.numsmp + u == wavcnt) + { + wavcnt += XM_SMPINCR; + if (!(nextwav = realloc (nextwav, wavcnt * sizeof (ULONG)))) + { + if (wh) + { + free (wh); + wh = NULL; + } + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + if (!(wh = realloc (wh, wavcnt * sizeof (XMWAVHEADER)))) + { + free (nextwav); + nextwav = NULL; + _mm_errno = MMERR_OUT_OF_MEMORY; + return 0; + } + s = wh + (wavcnt - XM_SMPINCR); + } + + s->length = _mm_read_I_ULONG (modreader); + s->loopstart = _mm_read_I_ULONG (modreader); + s->looplength = _mm_read_I_ULONG (modreader); + s->volume = _mm_read_UBYTE (modreader); + s->finetune = _mm_read_SBYTE (modreader); + s->type = _mm_read_UBYTE (modreader); + s->panning = _mm_read_UBYTE (modreader); + s->relnote = _mm_read_SBYTE (modreader); + s->vibtype = pth.vibflg; + s->vibsweep = pth.vibsweep; + s->vibdepth = pth.vibdepth * 4; + s->vibrate = pth.vibrate; + s->reserved = _mm_read_UBYTE (modreader); + _mm_read_string (s->samplename, 22, modreader); + + nextwav[of.numsmp + u] = next; + next += s->length; + + if (_mm_eof (modreader)) + { + free (nextwav); + free (wh); + nextwav = NULL; + wh = NULL; + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + } + + if (mh->version > 0x0103) + { + for (u = 0; u < ih.numsmp; u++) + nextwav[of.numsmp++] += _mm_ftell (modreader); + _mm_fseek (modreader, next, SEEK_CUR); + } + else + of.numsmp += ih.numsmp; + } + else + { + /* read the remainder of the header */ + for (u = headend - _mm_ftell (modreader); u; u--) + _mm_read_UBYTE (modreader); + + if (_mm_eof (modreader)) + { + free (nextwav); + free (wh); + nextwav = NULL; + wh = NULL; + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + } + } + } + + /* sanity check */ + if (!of.numsmp) + { + if (nextwav) + { + free (nextwav); + nextwav = NULL; + } + if (wh) + { + free (wh); + wh = NULL; + } + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + return 1; +} + +BOOL +XM_Load (BOOL curious) +{ + INSTRUMENT *d; + SAMPLE *q; + int t, u; + BOOL dummypat = 0; + char tracker[21], modtype[60]; + + /* try to read module header */ + _mm_read_string (mh->id, 17, modreader); + _mm_read_string (mh->songname, 21, modreader); + _mm_read_string (mh->trackername, 20, modreader); + mh->version = _mm_read_I_UWORD (modreader); + if ((mh->version < 0x102) || (mh->version > 0x104)) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + mh->headersize = _mm_read_I_ULONG (modreader); + mh->songlength = _mm_read_I_UWORD (modreader); + mh->restart = _mm_read_I_UWORD (modreader); + mh->numchn = _mm_read_I_UWORD (modreader); + mh->numpat = _mm_read_I_UWORD (modreader); + mh->numins = _mm_read_I_UWORD (modreader); + mh->flags = _mm_read_I_UWORD (modreader); + mh->tempo = _mm_read_I_UWORD (modreader); + mh->bpm = _mm_read_I_UWORD (modreader); + if (!mh->bpm) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + _mm_read_UBYTES (mh->orders, 256, modreader); + + if (_mm_eof (modreader)) + { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.initspeed = mh->tempo; + of.inittempo = mh->bpm; + strncpy (tracker, mh->trackername, 20); + tracker[20] = 0; + for (t = 20; (tracker[t] <= ' ') && (t >= 0); t--) + tracker[t] = 0; + + /* some modules have the tracker name empty */ + if (!tracker[0]) + strcpy (tracker, "Unknown tracker"); + +#ifdef HAVE_SNPRINTF + snprintf (modtype, 60, "%s (XM format %d.%02d)", + tracker, mh->version >> 8, mh->version & 0xff); +#else + sprintf (modtype, "%s (XM format %d.%02d)", + tracker, mh->version >> 8, mh->version & 0xff); +#endif + of.modtype = strdup (modtype); + of.numchn = mh->numchn; + of.numpat = mh->numpat; + of.numtrk = (UWORD) of.numpat * of.numchn; /* get number of channels */ + of.songname = DupStr (mh->songname, 20, 1); + of.numpos = mh->songlength; /* copy the songlength */ + of.reppos = mh->restart < mh->songlength ? mh->restart : 0; + of.numins = mh->numins; + of.flags |= UF_XMPERIODS | UF_INST | UF_BGSLIDES | UF_NOWRAP | UF_FT2QUIRKS; + if (mh->flags & 1) + of.flags |= UF_LINEAR; + + memset (of.chanvol, 64, of.numchn); /* store channel volumes */ + + if (!AllocPositions (of.numpos + 1)) + return 0; + for (t = 0; t < of.numpos; t++) + of.positions[t] = mh->orders[t]; + + /* We have to check for any pattern numbers in the order list greater than + the number of patterns total. If one or more is found, we set it equal to + the pattern total and make a dummy pattern to workaround the problem */ + for (t = 0; t < of.numpos; t++) + { + if (of.positions[t] >= of.numpat) + { + of.positions[t] = of.numpat; + dummypat = 1; + } + } + if (dummypat) + { + of.numpat++; + of.numtrk += of.numchn; + } + + if (mh->version < 0x0104) + { + if (!LoadInstruments ()) + return 0; + if (!LoadPatterns (dummypat)) + return 0; + for (t = 0; t < of.numsmp; t++) + nextwav[t] += _mm_ftell (modreader); + } + else + { + if (!LoadPatterns (dummypat)) + return 0; + if (!LoadInstruments ()) + return 0; + } + + if (!AllocSamples ()) + { + free (nextwav); + free (wh); + nextwav = NULL; + wh = NULL; + return 0; + } + q = of.samples; + s = wh; + for (u = 0; u < of.numsmp; u++, q++, s++) + { + q->samplename = DupStr (s->samplename, 22, 1); + q->length = s->length; + q->loopstart = s->loopstart; + q->loopend = s->loopstart + s->looplength; + q->volume = s->volume; + q->speed = s->finetune + 128; + q->panning = s->panning; + q->seekpos = nextwav[u]; + q->vibtype = s->vibtype; + q->vibsweep = s->vibsweep; + q->vibdepth = s->vibdepth; + q->vibrate = s->vibrate; + + if (s->type & 0x10) + { + q->length >>= 1; + q->loopstart >>= 1; + q->loopend >>= 1; + } + + q->flags |= SF_OWNPAN; + if (s->type & 0x3) + q->flags |= SF_LOOP; + if (s->type & 0x2) + q->flags |= SF_BIDI; + if (s->type & 0x10) + q->flags |= SF_16BITS; + q->flags |= SF_DELTA | SF_SIGNED; + } + + d = of.instruments; + s = wh; + for (u = 0; u < of.numins; u++, d++) + for (t = 0; t < XMNOTECNT; t++) + { + if (d->samplenumber[t] >= of.numsmp) + d->samplenote[t] = 255; + else + { + int note = t + s[d->samplenumber[t]].relnote; + d->samplenote[t] = (note < 0) ? 0 : note; + } + } + + free (wh); + free (nextwav); + wh = NULL; + nextwav = NULL; + return 1; +} + +CHAR * +XM_LoadTitle (void) +{ + CHAR s[21]; + + _mm_fseek (modreader, 17, SEEK_SET); + if (!_mm_read_UBYTES (s, 21, modreader)) + return NULL; + + return (DupStr (s, 21, 1)); +} + +/*========== Loader information */ + +MLOADER load_xm = +{ + NULL, + "XM", + "XM (FastTracker 2)", + XM_Init, + XM_Test, + XM_Load, + XM_Cleanup, + XM_LoadTitle +}; + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/mloader.c TiMidity++-2.9.0/libunimod/mloader.c --- TiMidity++-2.8.2/libunimod/mloader.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/mloader.c Sat Feb 19 20:49:54 2000 @@ -0,0 +1,1192 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: mloader.c,v 1.33 1999/10/25 16:31:41 miod Exp $ + + These routines are used to access the available module loaders + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MEMORY_H +#include +#endif + +#include "unimod_priv.h" + +#include + +URL modreader; +MODULE of; +BOOL ML_8bitsamples; +BOOL ML_monosamples; + +static MLOADER *firstloader = NULL; + +UWORD finetune[16] = +{ + 8363, 8413, 8463, 8529, 8581, 8651, 8723, 8757, + 7895, 7941, 7985, 8046, 8107, 8169, 8232, 8280 +}; + +/* This is a handle of sorts attached to any sample registered with + SL_RegisterSample. */ +typedef struct SAMPLOAD + { + struct SAMPLOAD *next; + + ULONG length; /* length of sample (in samples!) */ + ULONG loopstart; /* repeat position (relative to start, in samples) */ + ULONG loopend; /* repeat end */ + UWORD infmt, outfmt; + int scalefactor; + SAMPLE *sample; + URL reader; + } +SAMPLOAD; + +static int sl_rlength; +static SWORD sl_old; +static SWORD *sl_buffer = NULL; +static SAMPLOAD *musiclist = NULL; + +/* size of the loader buffer in words */ +#define SLBUFSIZE 2048 + +/* max # of KB to be devoted to samples */ +/* #define MAX_SAMPLESPACE 1024 */ + +/* IT-Compressed status structure */ +typedef struct ITPACK + { + UWORD bits; /* current number of bits */ + UWORD bufbits; /* bits in buffer */ + SWORD last; /* last output */ + UBYTE buf; /* bit buffer */ + } +ITPACK; + +static void SL_HalveSample (SAMPLOAD *); +static void SL_Sample8to16 (SAMPLOAD *); +static void SL_Sample16to8 (SAMPLOAD *); +static void SL_SampleSigned (SAMPLOAD *); +static void SL_SampleUnsigned (SAMPLOAD *); +static SAMPLOAD *SL_RegisterSample (SAMPLE *, URL); +static SWORD *SL_Load (SAMPLOAD *); +static BOOL SL_Init (SAMPLOAD *); +static void SL_Exit (SAMPLOAD *); + +BOOL +SL_Init (SAMPLOAD * s) +{ + if (!sl_buffer) + if (!(sl_buffer = _mm_malloc (SLBUFSIZE * sizeof (SWORD)))) + return 0; + + sl_rlength = s->length; + if (s->infmt & SF_16BITS) + sl_rlength >>= 1; + sl_old = 0; + + return 1; +} + +void +SL_Exit (SAMPLOAD * s) +{ + if (sl_rlength > 0) + _mm_fseek (s->reader, sl_rlength, SEEK_CUR); + if (sl_buffer) + { + free (sl_buffer); + sl_buffer = NULL; + } +} + +/* unpack a 8bit IT packed sample */ +static BOOL +read_itcompr8 (ITPACK * status, URL reader, SWORD * sl_buffer, UWORD count, UWORD * incnt) +{ + SWORD *dest = sl_buffer, *end = sl_buffer + count; + UWORD x, y, needbits, havebits, new_count = 0; + UWORD bits = status->bits; + UWORD bufbits = status->bufbits; + SBYTE last = status->last; + UBYTE buf = status->buf; + + while (dest < end) + { + needbits = new_count ? 3 : bits; + x = havebits = 0; + while (needbits) + { + /* feed buffer */ + if (!bufbits) + { + if ((*incnt)--) + buf = _mm_read_UBYTE (reader); + else + buf = 0; + bufbits = 8; + } + /* get as many bits as necessary */ + y = needbits < bufbits ? needbits : bufbits; + x |= (buf & ((1 << y) - 1)) << havebits; + buf >>= y; + bufbits -= y; + needbits -= y; + havebits += y; + } + if (new_count) + { + new_count = 0; + if (++x >= bits) + x++; + bits = x; + continue; + } + if (bits < 7) + { + if (x == (1 << (bits - 1))) + { + new_count = 1; + continue; + } + } + else if (bits < 9) + { + y = (0xff >> (9 - bits)) - 4; + if ((x > y) && (x <= y + 8)) + { + if ((x -= y) >= bits) + x++; + bits = x; + continue; + } + } + else if (bits < 10) + { + if (x >= 0x100) + { + bits = x - 0x100 + 1; + continue; + } + } + else + { + /* error in compressed data... */ + _mm_errno = MMERR_ITPACK_INVALID_DATA; + return 0; + } + + if (bits < 8) /* extend sign */ + x = ((SBYTE) (x << (8 - bits))) >> (8 - bits); + *(dest++) = (last += x) << 8; /* convert to 16 bit */ + } + status->bits = bits; + status->bufbits = bufbits; + status->last = last; + status->buf = buf; + return dest - sl_buffer; +} + +/* unpack a 16bit IT packed sample */ +static BOOL +read_itcompr16 (ITPACK * status, URL reader, SWORD * sl_buffer, UWORD count, UWORD * incnt) +{ + SWORD *dest = sl_buffer, *end = sl_buffer + count; + SLONG x, y, needbits, havebits, new_count = 0; + UWORD bits = status->bits; + UWORD bufbits = status->bufbits; + SWORD last = status->last; + UBYTE buf = status->buf; + + while (dest < end) + { + needbits = new_count ? 4 : bits; + x = havebits = 0; + while (needbits) + { + /* feed buffer */ + if (!bufbits) + { + if ((*incnt)--) + buf = _mm_read_UBYTE (reader); + else + buf = 0; + bufbits = 8; + } + /* get as many bits as necessary */ + y = needbits < bufbits ? needbits : bufbits; + x |= (buf & ((1 << y) - 1)) << havebits; + buf >>= y; + bufbits -= y; + needbits -= y; + havebits += y; + } + if (new_count) + { + new_count = 0; + if (++x >= bits) + x++; + bits = x; + continue; + } + if (bits < 7) + { + if (x == (1 << (bits - 1))) + { + new_count = 1; + continue; + } + } + else if (bits < 17) + { + y = (0xffff >> (17 - bits)) - 8; + if ((x > y) && (x <= y + 16)) + { + if ((x -= y) >= bits) + x++; + bits = x; + continue; + } + } + else if (bits < 18) + { + if (x >= 0x10000) + { + bits = x - 0x10000 + 1; + continue; + } + } + else + { + /* error in compressed data... */ + _mm_errno = MMERR_ITPACK_INVALID_DATA; + return 0; + } + + if (bits < 16) /* extend sign */ + x = ((SWORD) (x << (16 - bits))) >> (16 - bits); + *(dest++) = (last += x); + } + status->bits = bits; + status->bufbits = bufbits; + status->last = last; + status->buf = buf; + return dest - sl_buffer; +} + +static BOOL +SL_LoadInternal (void *buffer, UWORD infmt, UWORD outfmt, int scalefactor, ULONG length, URL reader) +{ + SBYTE *bptr = (SBYTE *) buffer; + SWORD *wptr = (SWORD *) buffer; + int stodo, t, u; + + int result, c_block = 0; /* compression bytes until next block */ + ITPACK status; + UWORD incnt; + + while (length) + { + stodo = (length < SLBUFSIZE) ? length : SLBUFSIZE; + + if (infmt & SF_ITPACKED) + { + sl_rlength = 0; + if (!c_block) + { + status.bits = (infmt & SF_16BITS) ? 17 : 9; + status.last = status.bufbits = 0; + incnt = _mm_read_I_UWORD (reader); + c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000; + if (infmt & SF_DELTA) + sl_old = 0; + } + if (infmt & SF_16BITS) + { + if (!(result = read_itcompr16 (&status, reader, sl_buffer, stodo, &incnt))) + return 1; + } + else + { + if (!(result = read_itcompr8 (&status, reader, sl_buffer, stodo, &incnt))) + return 1; + } + if (result != stodo) + { + _mm_errno = MMERR_ITPACK_INVALID_DATA; + return 1; + } + c_block -= stodo; + } + else + { + if (infmt & SF_16BITS) + { + if (infmt & SF_BIG_ENDIAN) + _mm_read_M_SWORDS (sl_buffer, stodo, reader); + else + _mm_read_I_SWORDS (sl_buffer, stodo, reader); + } + else + { + /* Always convert to 16 bits for internal use */ + SBYTE *src; + SWORD *dest; + + _mm_read_UBYTES (sl_buffer, stodo, reader); + src = (SBYTE *) sl_buffer; + dest = sl_buffer; + src += stodo; + dest += stodo; + + for (t = 0; t < stodo; t++) + { + src--; + dest--; + *dest = (*src) << 8; + } + } + sl_rlength -= stodo; + } + + if (infmt & SF_DELTA) + for (t = 0; t < stodo; t++) + { + sl_buffer[t] += sl_old; + sl_old = sl_buffer[t]; + } + + if ((infmt ^ outfmt) & SF_SIGNED) + for (t = 0; t < stodo; t++) + sl_buffer[t] ^= 0x8000; + + /* Dithering... */ + if ((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) + { + /* dither stereo to mono, average together every two samples */ + SLONG avgval; + int idx = 0; + + t = 0; + while (t < stodo && length) + { + avgval = sl_buffer[t++]; + avgval += sl_buffer[t++]; + sl_buffer[idx++] = avgval >> 1; + length -= 2; + } + stodo = idx; + } + else if (scalefactor) + { + int idx = 0; + SLONG scaleval; + + /* Sample Scaling... average values for better results. */ + t = 0; + while (t < stodo && length) + { + scaleval = 0; + for (u = scalefactor; u && t < stodo; u--, t++) + scaleval += sl_buffer[t]; + sl_buffer[idx++] = scaleval / (scalefactor - u); + length--; + } + stodo = idx; + } + else + length -= stodo; + + if (outfmt & SF_16BITS) + { + for (t = 0; t < stodo; t++) + *(wptr++) = sl_buffer[t]; + } + else + { + for (t = 0; t < stodo; t++) + *(bptr++) = sl_buffer[t] >> 8; + } + } + return 0; +} + +static SWORD * +SL_Load (struct SAMPLOAD *sload) +{ + SAMPLE *s = sload->sample; + SWORD *data; + ULONG t, length, loopstart, loopend; + + length = s->length; + loopstart = s->loopstart; + loopend = s->loopend; + + if (!(data = (SWORD *) _mm_malloc ((length + 20) << 1))) + { + _mm_errno = MMERR_SAMPLE_TOO_BIG; + return NULL; + } + + /* read sample into buffer */ + if (SL_LoadInternal (data, sload->infmt, sload->outfmt, + sload->scalefactor, length, sload->reader)) + return NULL; + + /* Unclick sample */ + if (s->flags & SF_LOOP) + { + if (s->flags & SF_BIDI) + for (t = 0; t < 16; t++) + data[loopend + t] = data[(loopend - t) - 1]; + else + for (t = 0; t < 16; t++) + data[loopend + t] = data[t + loopstart]; + } + else + for (t = 0; t < 16; t++) + data[t + length] = 0; + + return data; +} + +/* Registers a sample for loading when SL_LoadSamples() is called. */ +SAMPLOAD * +SL_RegisterSample (SAMPLE * s, URL reader) +{ + SAMPLOAD *news, *cruise; + + cruise = musiclist; + + /* Allocate and add structure to the END of the list */ + if (!(news = (SAMPLOAD *) _mm_malloc (sizeof (SAMPLOAD)))) + return NULL; + + if (cruise) + { + while (cruise->next) + cruise = cruise->next; + cruise->next = news; + } + else + musiclist = news; + + news->infmt = s->flags & SF_FORMATMASK; + news->outfmt = news->infmt; + news->reader = reader; + news->sample = s; + news->length = s->length; + news->loopstart = s->loopstart; + news->loopend = s->loopend; + + if (ML_monosamples) + { + news->outfmt &= ~SF_STEREO; + } + + if (ML_8bitsamples) + { + SL_SampleUnsigned (news); + SL_Sample16to8 (news); + } + else + { + SL_SampleSigned (news); + SL_Sample8to16 (news); + } + + + return news; +} + +static void +FreeSampleList () +{ + SAMPLOAD *old, *s = musiclist; + + while (s) + { + old = s; + s = s->next; + free (old); + } + musiclist = NULL; +} + +/* Returns the total amount of memory required by the musiclist queue. */ +static ULONG +SampleTotal () +{ + int total = 0; + SAMPLOAD *samplist = musiclist; + SAMPLE *s; + + while (samplist) + { + s = samplist->sample; + s->flags = (s->flags & ~SF_FORMATMASK) | samplist->outfmt; + + total += (s->length * ((s->flags & SF_16BITS) ? 2 : 1)) + 16; + + samplist = samplist->next; + } + + return total; +} + +static ULONG +RealSpeed (SAMPLOAD * s) +{ + return (s->sample->speed / (s->scalefactor ? s->scalefactor : 1)); +} + +BOOL +SL_LoadSamples (void) +{ + SAMPLOAD *s; + + if (!musiclist) + return 0; + +#ifdef MAX_SAMPLESPACE + while (SampleTotal () > (MAX_SAMPLESPACE * 1024)) + { + /* First Pass - check for any 16 bit samples */ + s = musiclist; + while (s) + { + if (s->outfmt & SF_16BITS) + { + SL_Sample16to8 (s); + break; + } + s = s->next; + } + /* Second pass (if no 16bits found above) is to take the sample with + the highest speed and dither it by half. */ + if (!s) + { + SAMPLOAD *c2smp = NULL; + ULONG maxsize, speed; + + s = musiclist; + speed = 0; + while (s) + { + if ((s->sample->length) && (RealSpeed (s) > speed)) + { + speed = RealSpeed (s); + c2smp = s; + } + s = s->next; + } + if (c2smp) + SL_HalveSample (c2smp); + } + } +#endif + + /* Samples dithered, now load them ! */ + s = musiclist; + while (s) + { + /* sample has to be loaded ? -> increase number of samples, allocate + memory and load sample. */ + if (s->sample->length) + { + if (s->sample->seekpos) + _mm_fseek (s->reader, s->sample->seekpos, SEEK_SET); + + /* Call the sample load routine of the driver module. It has to + return a pointer to sample dat). */ + if (SL_Init (s)) + { + s->sample->data = SL_Load (s); + SL_Exit (s); + } + s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt; + if (s->sample->data == NULL) + { + FreeSampleList (musiclist); + return 1; + } + } + s = s->next; + } + + FreeSampleList (musiclist); + return 0; +} + +void +SL_Sample16to8 (SAMPLOAD * s) +{ + s->outfmt &= ~SF_16BITS; + s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt; +} + +void +SL_Sample8to16 (SAMPLOAD * s) +{ + s->outfmt |= SF_16BITS; + s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt; +} + +void +SL_SampleSigned (SAMPLOAD * s) +{ + s->outfmt |= SF_SIGNED; + s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt; +} + +void +SL_SampleUnsigned (SAMPLOAD * s) +{ + s->outfmt &= ~SF_SIGNED; + s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt; +} + +void +SL_HalveSample (SAMPLOAD * s) +{ + s->scalefactor = 2; /* this is a divisor */ + s->sample->divfactor = 1; /* this is a shift count */ + s->sample->length = s->length / s->scalefactor; + s->sample->loopstart = s->loopstart / s->scalefactor; + s->sample->loopend = s->loopend / s->scalefactor; +} + + +CHAR * +ML_InfoLoader (void) +{ + int len = 0; + MLOADER *l; + CHAR *list = NULL; + + /* compute size of buffer */ + for (l = firstloader; l; l = l->next) + len += 1 + (l->next ? 1 : 0) + strlen (l->version); + + if (len) + if ((list = _mm_malloc (len * sizeof (CHAR)))) + { + list[0] = 0; + /* list all registered module loders */ + for (l = firstloader; l; l = l->next) + sprintf (list, (l->next) ? "%s%s\n" : "%s%s", list, l->version); + } + return list; +} + +BOOL +ReadComment (UWORD len) +{ + if (len) + { + int i; + + if (!(of.comment = (CHAR *) _mm_malloc (len + 1))) + return 0; + _mm_read_UBYTES (of.comment, len, modreader); + + /* translate IT linefeeds */ + for (i = 0; i < len; i++) + if (of.comment[i] == '\r') + of.comment[i] = '\n'; + + of.comment[len] = 0; /* just in case */ + } + if (!of.comment[0]) + { + free (of.comment); + of.comment = NULL; + } + return 1; +} + +BOOL +ReadLinedComment (UWORD lines, UWORD linelen) +{ + CHAR *tempcomment, *line, *storage; + UWORD total = 0, t, len = lines * linelen; + int i; + + if (lines) + { + if (!(tempcomment = (CHAR *) _mm_malloc (len + 1))) + return 0; + if (!(storage = (CHAR *) _mm_malloc (linelen + 1))) + { + free (tempcomment); + return 0; + } + _mm_read_UBYTES (tempcomment, len, modreader); + + /* compute message length */ + for (line = tempcomment, total = t = 0; t < lines; t++, line += linelen) + { + for (i = linelen; (i >= 0) && (line[i] == ' '); i--) + line[i] = 0; + for (i = 0; i < linelen; i++) + if (!line[i]) + break; + total += 1 + i; + } + + if (total > lines) + { + if (!(of.comment = (CHAR *) _mm_malloc (total + 1))) + { + free (storage); + free (tempcomment); + return 0; + } + + /* convert message */ + for (line = tempcomment, t = 0; t < lines; t++, line += linelen) + { + for (i = 0; i < linelen; i++) + if (!(storage[i] = line[i])) + break; + storage[i] = 0; /* if (i==linelen) */ + strcat (of.comment, storage); + strcat (of.comment, "\r"); + } + free (storage); + free (tempcomment); + } + } + return 1; +} + +BOOL +AllocPositions (int total) +{ + if (!total) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + if (!(of.positions = _mm_calloc (total, sizeof (UWORD)))) + return 0; + return 1; +} + +BOOL +AllocPatterns (void) +{ + int s, t, tracks = 0; + + if ((!of.numpat) || (!of.numchn)) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + /* Allocate track sequencing array */ + if (!(of.patterns = (UWORD *) _mm_calloc ((ULONG) (of.numpat + 1) * of.numchn, sizeof (UWORD)))) + return 0; + if (!(of.pattrows = (UWORD *) _mm_calloc (of.numpat + 1, sizeof (UWORD)))) + return 0; + + for (t = 0; t <= of.numpat; t++) + { + of.pattrows[t] = 64; + for (s = 0; s < of.numchn; s++) + of.patterns[(t * of.numchn) + s] = tracks++; + } + + return 1; +} + +BOOL +AllocTracks (void) +{ + if (!of.numtrk) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + if (!(of.tracks = (UBYTE **) _mm_calloc (of.numtrk, sizeof (UBYTE *)))) + return 0; + return 1; +} + +BOOL +AllocInstruments (void) +{ + int t, n; + + if (!of.numins) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + if (!(of.instruments = (INSTRUMENT *) _mm_calloc (of.numins, sizeof (INSTRUMENT)))) + return 0; + + for (t = 0; t < of.numins; t++) + { + for (n = 0; n < INSTNOTES; n++) + { + /* Init note / sample lookup table */ + of.instruments[t].samplenote[n] = n; + of.instruments[t].samplenumber[n] = t; + } + of.instruments[t].globvol = 64; + } + return 1; +} + +BOOL +AllocSamples (void) +{ + UWORD u; + + if (!of.numsmp) + { + _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + if (!(of.samples = (SAMPLE *) _mm_calloc (of.numsmp, sizeof (SAMPLE)))) + return 0; + + for (u = 0; u < of.numsmp; u++) + { + of.samples[u].panning = 128; /* center */ + of.samples[u].data = NULL; + of.samples[u].globvol = 64; + of.samples[u].volume = 64; + } + return 1; +} + +static BOOL +ML_LoadSamples (void) +{ + SAMPLE *s; + int u; + + for (u = of.numsmp, s = of.samples; u; u--, s++) + if (s->length) + SL_RegisterSample (s, modreader); + + return 1; +} + +/* Creates a CSTR out of a character buffer of 'len' bytes, but strips any + terminating non-printing characters like 0, spaces etc. */ +CHAR * +DupStr (CHAR * s, UWORD len, BOOL strict) +{ + UWORD t; + CHAR *d = NULL; + + /* Scan for last printing char in buffer [includes high ascii up to 254] */ + while (len) + { + if (s[len - 1] > 0x20) + break; + len--; + } + + /* Scan forward for possible NULL character */ + if (strict) + { + for (t = 0; t < len; t++) + if (!s[t]) + break; + if (t < len) + len = t; + } + + /* When the buffer wasn't completely empty, allocate a cstring and copy the + buffer into that string, except for any control-chars */ + if ((d = (CHAR *) _mm_malloc (sizeof (CHAR) * (len + 1)))) + { + for (t = 0; t < len; t++) + d[t] = (s[t] < 32) ? '.' : s[t]; + d[len] = 0; + } + return d; +} + +static void +ML_XFreeSample (SAMPLE * s) +{ + if (s->data) + free (s->data); + if (s->samplename) + free (s->samplename); +} + +static void +ML_XFreeInstrument (INSTRUMENT * i) +{ + if (i->insname) + free (i->insname); +} + +void +ML_Free (MODULE * mf) +{ + UWORD t; + + if (!mf) + return; + + if (mf->songname) + free (mf->songname); + if (mf->comment) + free (mf->comment); + + if (mf->modtype) + free (mf->modtype); + if (mf->positions) + free (mf->positions); + if (mf->patterns) + free (mf->patterns); + if (mf->pattrows) + free (mf->pattrows); + + if (mf->tracks) + { + for (t = 0; t < mf->numtrk; t++) + if (mf->tracks[t]) + free (mf->tracks[t]); + free (mf->tracks); + } + if (mf->instruments) + { + for (t = 0; t < mf->numins; t++) + ML_XFreeInstrument (&mf->instruments[t]); + free (mf->instruments); + } + if (mf->samples) + { + for (t = 0; t < mf->numsmp; t++) + if (mf->samples[t].length) + ML_XFreeSample (&mf->samples[t]); + free (mf->samples); + } + memset (mf, 0, sizeof (MODULE)); + if (mf != &of) + free (mf); +} + +static MODULE * +ML_AllocUniMod (void) +{ + return (_mm_malloc (sizeof (MODULE))); +} + +CHAR * +ML_LoadTitle (URL reader) +{ + MLOADER *l; + + modreader = reader; + _mm_errno = 0; + + /* Try to find a loader that recognizes the module */ + for (l = firstloader; l; l = l->next) + { + _mm_rewind (modreader); + if (l->Test ()) + break; + } + + if (!l) + { + _mm_errno = MMERR_NOT_A_MODULE; + return NULL; + } + + return l->LoadTitle (); +} + +/* Check if it is a module given a reader */ +BOOL +ML_Test (URL reader) +{ + MLOADER *l; + + modreader = reader; + _mm_errno = 0; + + /* Try to find a loader that recognizes the module */ + for (l = firstloader; l; l = l->next) + { + _mm_rewind (modreader); + if (l->Test ()) + return 1; + } + return 0; +} + +/* Loads a module given a reader */ +MODULE * +ML_Load (URL reader, int maxchan, BOOL curious) +{ + int t; + MLOADER *l; + BOOL ok; + MODULE *mf; + + modreader = reader; + _mm_errno = 0; + + /* Try to find a loader that recognizes the module */ + for (l = firstloader; l; l = l->next) + { + _mm_rewind (modreader); + if (l->Test ()) + break; + } + + if (!l) + { + _mm_errno = MMERR_NOT_A_MODULE; + _mm_rewind (modreader); + return NULL; + } + + /* init unitrk routines */ + if (!UniInit ()) + { + _mm_rewind (modreader); + return NULL; + } + + /* load the song using the song's loader variable */ + memset (&of, 0, sizeof (MODULE)); + of.initvolume = 128; + + /* init panning array */ + for (t = 0; t < 64; t++) + of.panning[t] = ((t + 1) & 2) ? 255 : 0; + for (t = 0; t < 64; t++) + of.chanvol[t] = 64; + + /* init module loader and load the header / patterns */ + if (l->Init ()) + { + _mm_rewind (modreader); + ok = l->Load (curious); + } + else + ok = 0; + + /* free loader and unitrk allocations */ + l->Cleanup (); + UniCleanup (); + + if (!ok) + { + ML_Free (&of); + _mm_rewind (modreader); + return NULL; + } + + if (!ML_LoadSamples ()) + { + ML_Free (&of); + _mm_rewind (modreader); + return NULL; + } + + if (!(mf = ML_AllocUniMod ())) + { + ML_Free (&of); + return NULL; + } + + /* Copy the static MODULE contents into the dynamic MODULE struct. */ + memcpy (mf, &of, sizeof (MODULE)); + + if (maxchan > 0) + { + if (!(mf->flags & UF_NNA) && (mf->numchn < maxchan)) + maxchan = mf->numchn; + else if ((mf->numvoices) && (mf->numvoices < maxchan)) + maxchan = mf->numvoices; + + if (maxchan < mf->numchn) + mf->flags |= UF_NNA; + } + if (SL_LoadSamples ()) + { + ML_Free (mf); + return NULL; + } + return mf; +} + + +void +ML_RegisterAllLoaders (void) +{ + MLOADER *last = NULL; + + if (firstloader) + return; + +#define LOADER(fmt) { \ + extern MLOADER fmt; \ + if (!last) \ + firstloader = &fmt; \ + else \ + last->next = &fmt; \ + last = &fmt; \ +} + + + /* Most likely first */ + LOADER (load_xm); + LOADER (load_s3m); + LOADER (load_mod); + LOADER (load_it); + + /* Then the others in alphabetic order */ + LOADER (load_669); + LOADER (load_amf); + LOADER (load_dsm); + LOADER (load_far); + LOADER (load_gdm); + LOADER (load_imf); + LOADER (load_med); + LOADER (load_mtm); + LOADER (load_stm); + LOADER (load_stx); + LOADER (load_ult); + LOADER (load_uni); + + /* must be last! */ + LOADER (load_m15); +} +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/mlutil.c TiMidity++-2.9.0/libunimod/mlutil.c --- TiMidity++-2.8.2/libunimod/mlutil.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/mlutil.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,521 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +/*============================================================================== + + $Id: mlutil.c,v 1.12 1999/10/25 16:31:41 miod Exp $ + + Utility functions for the module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MEMORY_H +#include +#endif + +#include +#include "unimod_priv.h" + +SBYTE remap[64]; /* for removing empty channels */ +UBYTE* poslookup=NULL; /* lookup table for pattern jumps after blank + pattern removal */ +UBYTE poslookupcnt; +UWORD* origpositions=NULL; + +BOOL filters; /* resonant filters in use */ +UBYTE activemacro; /* active midi macro number for Sxx,xx<80h */ +UBYTE filtermacros[16]; /* midi macros settings */ +FILTER filtersettings[256]; /* computed filter settings */ + +/*========== Linear periods stuff */ + + +/* Triton's linear periods to frequency translation table (for XM modules) */ +static ULONG lintab[768] = +{ + 535232, 534749, 534266, 533784, 533303, 532822, 532341, 531861, + 531381, 530902, 530423, 529944, 529466, 528988, 528511, 528034, + 527558, 527082, 526607, 526131, 525657, 525183, 524709, 524236, + 523763, 523290, 522818, 522346, 521875, 521404, 520934, 520464, + 519994, 519525, 519057, 518588, 518121, 517653, 517186, 516720, + 516253, 515788, 515322, 514858, 514393, 513929, 513465, 513002, + 512539, 512077, 511615, 511154, 510692, 510232, 509771, 509312, + 508852, 508393, 507934, 507476, 507018, 506561, 506104, 505647, + 505191, 504735, 504280, 503825, 503371, 502917, 502463, 502010, + 501557, 501104, 500652, 500201, 499749, 499298, 498848, 498398, + 497948, 497499, 497050, 496602, 496154, 495706, 495259, 494812, + 494366, 493920, 493474, 493029, 492585, 492140, 491696, 491253, + 490809, 490367, 489924, 489482, 489041, 488600, 488159, 487718, + 487278, 486839, 486400, 485961, 485522, 485084, 484647, 484210, + 483773, 483336, 482900, 482465, 482029, 481595, 481160, 480726, + 480292, 479859, 479426, 478994, 478562, 478130, 477699, 477268, + 476837, 476407, 475977, 475548, 475119, 474690, 474262, 473834, + 473407, 472979, 472553, 472126, 471701, 471275, 470850, 470425, + 470001, 469577, 469153, 468730, 468307, 467884, 467462, 467041, + 466619, 466198, 465778, 465358, 464938, 464518, 464099, 463681, + 463262, 462844, 462427, 462010, 461593, 461177, 460760, 460345, + 459930, 459515, 459100, 458686, 458272, 457859, 457446, 457033, + 456621, 456209, 455797, 455386, 454975, 454565, 454155, 453745, + 453336, 452927, 452518, 452110, 451702, 451294, 450887, 450481, + 450074, 449668, 449262, 448857, 448452, 448048, 447644, 447240, + 446836, 446433, 446030, 445628, 445226, 444824, 444423, 444022, + 443622, 443221, 442821, 442422, 442023, 441624, 441226, 440828, + 440430, 440033, 439636, 439239, 438843, 438447, 438051, 437656, + 437261, 436867, 436473, 436079, 435686, 435293, 434900, 434508, + 434116, 433724, 433333, 432942, 432551, 432161, 431771, 431382, + 430992, 430604, 430215, 429827, 429439, 429052, 428665, 428278, + 427892, 427506, 427120, 426735, 426350, 425965, 425581, 425197, + 424813, 424430, 424047, 423665, 423283, 422901, 422519, 422138, + 421757, 421377, 420997, 420617, 420237, 419858, 419479, 419101, + 418723, 418345, 417968, 417591, 417214, 416838, 416462, 416086, + 415711, 415336, 414961, 414586, 414212, 413839, 413465, 413092, + 412720, 412347, 411975, 411604, 411232, 410862, 410491, 410121, + 409751, 409381, 409012, 408643, 408274, 407906, 407538, 407170, + 406803, 406436, 406069, 405703, 405337, 404971, 404606, 404241, + 403876, 403512, 403148, 402784, 402421, 402058, 401695, 401333, + 400970, 400609, 400247, 399886, 399525, 399165, 398805, 398445, + 398086, 397727, 397368, 397009, 396651, 396293, 395936, 395579, + 395222, 394865, 394509, 394153, 393798, 393442, 393087, 392733, + 392378, 392024, 391671, 391317, 390964, 390612, 390259, 389907, + 389556, 389204, 388853, 388502, 388152, 387802, 387452, 387102, + 386753, 386404, 386056, 385707, 385359, 385012, 384664, 384317, + 383971, 383624, 383278, 382932, 382587, 382242, 381897, 381552, + 381208, 380864, 380521, 380177, 379834, 379492, 379149, 378807, + 378466, 378124, 377783, 377442, 377102, 376762, 376422, 376082, + 375743, 375404, 375065, 374727, 374389, 374051, 373714, 373377, + 373040, 372703, 372367, 372031, 371695, 371360, 371025, 370690, + 370356, 370022, 369688, 369355, 369021, 368688, 368356, 368023, + 367691, 367360, 367028, 366697, 366366, 366036, 365706, 365376, + 365046, 364717, 364388, 364059, 363731, 363403, 363075, 362747, + 362420, 362093, 361766, 361440, 361114, 360788, 360463, 360137, + 359813, 359488, 359164, 358840, 358516, 358193, 357869, 357547, + 357224, 356902, 356580, 356258, 355937, 355616, 355295, 354974, + 354654, 354334, 354014, 353695, 353376, 353057, 352739, 352420, + 352103, 351785, 351468, 351150, 350834, 350517, 350201, 349885, + 349569, 349254, 348939, 348624, 348310, 347995, 347682, 347368, + 347055, 346741, 346429, 346116, 345804, 345492, 345180, 344869, + 344558, 344247, 343936, 343626, 343316, 343006, 342697, 342388, + 342079, 341770, 341462, 341154, 340846, 340539, 340231, 339924, + 339618, 339311, 339005, 338700, 338394, 338089, 337784, 337479, + 337175, 336870, 336566, 336263, 335959, 335656, 335354, 335051, + 334749, 334447, 334145, 333844, 333542, 333242, 332941, 332641, + 332341, 332041, 331741, 331442, 331143, 330844, 330546, 330247, + 329950, 329652, 329355, 329057, 328761, 328464, 328168, 327872, + 327576, 327280, 326985, 326690, 326395, 326101, 325807, 325513, + 325219, 324926, 324633, 324340, 324047, 323755, 323463, 323171, + 322879, 322588, 322297, 322006, 321716, 321426, 321136, 320846, + 320557, 320267, 319978, 319690, 319401, 319113, 318825, 318538, + 318250, 317963, 317676, 317390, 317103, 316817, 316532, 316246, + 315961, 315676, 315391, 315106, 314822, 314538, 314254, 313971, + 313688, 313405, 313122, 312839, 312557, 312275, 311994, 311712, + 311431, 311150, 310869, 310589, 310309, 310029, 309749, 309470, + 309190, 308911, 308633, 308354, 308076, 307798, 307521, 307243, + 306966, 306689, 306412, 306136, 305860, 305584, 305308, 305033, + 304758, 304483, 304208, 303934, 303659, 303385, 303112, 302838, + 302565, 302292, 302019, 301747, 301475, 301203, 300931, 300660, + 300388, 300117, 299847, 299576, 299306, 299036, 298766, 298497, + 298227, 297958, 297689, 297421, 297153, 296884, 296617, 296349, + 296082, 295815, 295548, 295281, 295015, 294749, 294483, 294217, + 293952, 293686, 293421, 293157, 292892, 292628, 292364, 292100, + 291837, 291574, 291311, 291048, 290785, 290523, 290261, 289999, + 289737, 289476, 289215, 288954, 288693, 288433, 288173, 287913, + 287653, 287393, 287134, 286875, 286616, 286358, 286099, 285841, + 285583, 285326, 285068, 284811, 284554, 284298, 284041, 283785, + 283529, 283273, 283017, 282762, 282507, 282252, 281998, 281743, + 281489, 281235, 280981, 280728, 280475, 280222, 279969, 279716, + 279464, 279212, 278960, 278708, 278457, 278206, 277955, 277704, + 277453, 277203, 276953, 276703, 276453, 276204, 275955, 275706, + 275457, 275209, 274960, 274712, 274465, 274217, 273970, 273722, + 273476, 273229, 272982, 272736, 272490, 272244, 271999, 271753, + 271508, 271263, 271018, 270774, 270530, 270286, 270042, 269798, + 269555, 269312, 269069, 268826, 268583, 268341, 268099, 267857 +}; + +static UWORD oldperiods[OCTAVE * 2] = +{ + 1712 * 16, 1664 * 16, 1616 * 16, 1570 * 16, 1524 * 16, 1480 * 16, + 1438 * 16, 1396 * 16, 1356 * 16, 1318 * 16, 1280 * 16, 1244 * 16, + 1208 * 16, 1174 * 16, 1140 * 16, 1108 * 16, 1076 * 16, 1046 * 16, + 1016 * 16, 988 * 16, 960 * 16, 932 * 16, 906 * 16, 880 * 16 +}; + +#define LOGFAC 2*16 +static UWORD logtab[104] = +{ + LOGFAC * 907, LOGFAC * 900, LOGFAC * 894, LOGFAC * 887, + LOGFAC * 881, LOGFAC * 875, LOGFAC * 868, LOGFAC * 862, + LOGFAC * 856, LOGFAC * 850, LOGFAC * 844, LOGFAC * 838, + LOGFAC * 832, LOGFAC * 826, LOGFAC * 820, LOGFAC * 814, + LOGFAC * 808, LOGFAC * 802, LOGFAC * 796, LOGFAC * 791, + LOGFAC * 785, LOGFAC * 779, LOGFAC * 774, LOGFAC * 768, + LOGFAC * 762, LOGFAC * 757, LOGFAC * 752, LOGFAC * 746, + LOGFAC * 741, LOGFAC * 736, LOGFAC * 730, LOGFAC * 725, + LOGFAC * 720, LOGFAC * 715, LOGFAC * 709, LOGFAC * 704, + LOGFAC * 699, LOGFAC * 694, LOGFAC * 689, LOGFAC * 684, + LOGFAC * 678, LOGFAC * 675, LOGFAC * 670, LOGFAC * 665, + LOGFAC * 660, LOGFAC * 655, LOGFAC * 651, LOGFAC * 646, + LOGFAC * 640, LOGFAC * 636, LOGFAC * 632, LOGFAC * 628, + LOGFAC * 623, LOGFAC * 619, LOGFAC * 614, LOGFAC * 610, + LOGFAC * 604, LOGFAC * 601, LOGFAC * 597, LOGFAC * 592, + LOGFAC * 588, LOGFAC * 584, LOGFAC * 580, LOGFAC * 575, + LOGFAC * 570, LOGFAC * 567, LOGFAC * 563, LOGFAC * 559, + LOGFAC * 555, LOGFAC * 551, LOGFAC * 547, LOGFAC * 543, + LOGFAC * 538, LOGFAC * 535, LOGFAC * 532, LOGFAC * 528, + LOGFAC * 524, LOGFAC * 520, LOGFAC * 516, LOGFAC * 513, + LOGFAC * 508, LOGFAC * 505, LOGFAC * 502, LOGFAC * 498, + LOGFAC * 494, LOGFAC * 491, LOGFAC * 487, LOGFAC * 484, + LOGFAC * 480, LOGFAC * 477, LOGFAC * 474, LOGFAC * 470, + LOGFAC * 467, LOGFAC * 463, LOGFAC * 460, LOGFAC * 457, + LOGFAC * 453, LOGFAC * 450, LOGFAC * 447, LOGFAC * 443, + LOGFAC * 440, LOGFAC * 437, LOGFAC * 434, LOGFAC * 431 +}; + + +int* noteindex=NULL; /* remap value for linear period modules */ +static int noteindexcount=0; + +int *AllocLinear(void) +{ + if(of.numsmp>noteindexcount) { + noteindexcount=of.numsmp; + noteindex=realloc(noteindex,noteindexcount*sizeof(int)); + } + return noteindex; +} + +void FreeLinear(void) +{ + if(noteindex) { + free(noteindex); + noteindex=NULL; + } + noteindexcount=0; +} + +static SWORD +Interpolate (SWORD p, SWORD p1, SWORD p2, SWORD v1, SWORD v2) +{ + if ((p1 == p2) || (p == p1)) + return v1; + return v1 + ((SLONG) ((p - p1) * (v2 - v1)) / (p2 - p1)); +} + + +UWORD +getlinearperiod (UWORD note, ULONG fine) +{ + UWORD t; + + t = (20L * OCTAVE + 2 - note) * 32L - (fine >> 1); + return t; +} + + +/* XM linear period to MOD period conversion */ +ULONG getfrequency (UBYTE flags, ULONG period) +{ + if (flags & UF_LINEAR) + return lintab[period % 768] >> (period / 768); + else + return (8363L * 1712L) / (period ? period : 1); +} + +UWORD getlogperiod (UWORD note, ULONG fine) +{ + UWORD n, o; + UWORD p1, p2; + ULONG i; + + n = note % (2 * OCTAVE); + o = note / (2 * OCTAVE); + i = (n << 2) + (fine >> 4); /* n*8 + fine/16 */ + + p1 = logtab[i]; + p2 = logtab[i + 1]; + + return (Interpolate (fine >> 4, 0, 15, p1, p2) >> o); +} + +UWORD getoldperiod (UWORD note, ULONG speed) +{ + UWORD n, o; + + if (!speed) + { +#ifdef MIKMOD_DEBUG + fprintf (stderr, "\rmplayer: getoldperiod() called with note=%d, speed=0 !\n", note); +#endif + return 4242; /* <- prevent divide overflow.. (42 hehe) */ + } + + n = note % (2 * OCTAVE); + o = note / (2 * OCTAVE); + return ((8363L * (ULONG) oldperiods[n]) >> o) / speed; +} + +int speed_to_finetune(ULONG speed,int sample) +{ + int ctmp=0,tmp,note=1,finetune=0; + + speed>>=1; + while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))speed) + tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune)); + else { + note--; + while(ctmp> (period / 768); + period = (8363L * 1712L) / period; + } + + return (period); +} + + +/*========== Order stuff */ + +/* handles S3M and IT orders */ +void S3MIT_CreateOrders(BOOL curious) +{ + int t; + + of.numpos = 0; + memset(of.positions,0,poslookupcnt*sizeof(UWORD)); + memset(poslookup,-1,256); + for(t=0;t>4; + + /* process S3M / IT specific command structure */ + + if(cmd!=255) { + switch(cmd) { + case 1: /* Axx set speed to xx */ + UniEffect(UNI_S3MEFFECTA,inf); + break; + case 2: /* Bxx position jump */ + if (inf>4)*10+(inf&0xf)); + else + UniPTEffect(0xd,inf); + break; + case 4: /* Dxy volumeslide */ + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 5: /* Exy toneslide down */ + UniEffect(UNI_S3MEFFECTE,inf); + break; + case 6: /* Fxy toneslide up */ + UniEffect(UNI_S3MEFFECTF,inf); + break; + case 7: /* Gxx Tone portamento, speed xx */ + UniEffect(UNI_ITEFFECTG,inf); + break; + case 8: /* Hxy vibrato */ + if(oldeffect&1) + UniPTEffect(0x4,inf); + else + UniEffect(UNI_ITEFFECTH,inf); + break; + case 9: /* Ixy tremor, ontime x, offtime y */ + if(oldeffect&1) + UniEffect(UNI_S3MEFFECTI,inf); + else + UniEffect(UNI_ITEFFECTI,inf); + break; + case 0xa: /* Jxy arpeggio */ + UniPTEffect(0x0,inf); + break; + case 0xb: /* Kxy Dual command H00 & Dxy */ + if(oldeffect&1) + UniPTEffect(0x4,0); + else + UniEffect(UNI_ITEFFECTH,0); + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 0xc: /* Lxy Dual command G00 & Dxy */ + if(oldeffect&1) + UniPTEffect(0x3,0); + else + UniEffect(UNI_ITEFFECTG,0); + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 0xd: /* Mxx Set Channel Volume */ + UniEffect(UNI_ITEFFECTM,inf); + break; + case 0xe: /* Nxy Slide Channel Volume */ + UniEffect(UNI_ITEFFECTN,inf); + break; + case 0xf: /* Oxx set sampleoffset xx00h */ + UniPTEffect(0x9,inf); + break; + case 0x10: /* Pxy Slide Panning Commands */ + UniEffect(UNI_ITEFFECTP,inf); + break; + case 0x11: /* Qxy Retrig (+volumeslide) */ + UniWriteByte(UNI_S3MEFFECTQ); + if(inf && !lo && !(oldeffect&1)) + UniWriteByte(1); + else + UniWriteByte(inf); + break; + case 0x12: /* Rxy tremolo speed x, depth y */ + UniEffect(UNI_S3MEFFECTR,inf); + break; + case 0x13: /* Sxx special commands */ + if (inf>=0xf0) { + /* change resonant filter settings if necessary */ + if((filters)&&((inf&0xf)!=activemacro)) { + activemacro=inf&0xf; + for(inf=0;inf<0x80;inf++) + filtersettings[inf].filter=filtermacros[activemacro]; + } + } else + UniEffect(UNI_ITEFFECTS0,inf); + break; + case 0x14: /* Txx tempo */ + if(inf>=0x20) + UniEffect(UNI_S3MEFFECTT,inf); + else { + if(!(oldeffect&1)) + /* IT Tempo slide */ + UniEffect(UNI_ITEFFECTT,inf); + } + break; + case 0x15: /* Uxy Fine Vibrato speed x, depth y */ + if(oldeffect&1) + UniEffect(UNI_S3MEFFECTU,inf); + else + UniEffect(UNI_ITEFFECTU,inf); + break; + case 0x16: /* Vxx Set Global Volume */ + UniEffect(UNI_XMEFFECTG,inf); + break; + case 0x17: /* Wxy Global Volume Slide */ + UniEffect(UNI_ITEFFECTW,inf); + break; + case 0x18: /* Xxx amiga command 8xx */ + if(oldeffect&1) { + if(inf>128) + UniEffect(UNI_ITEFFECTS0,0x91); /* surround */ + else + UniPTEffect(0x8,(inf==128)?255:(inf<<1)); + } else + UniPTEffect(0x8,inf); + break; + case 0x19: /* Yxy Panbrello speed x, depth y */ + UniEffect(UNI_ITEFFECTY,inf); + break; + case 0x1a: /* Zxx midi/resonant filters */ + if(filtersettings[inf].filter) { + UniWriteByte(UNI_ITEFFECTZ); + UniWriteByte(filtersettings[inf].filter); + UniWriteByte(filtersettings[inf].inf); + } + break; + } + } +} + +/*========== Unitrk stuff */ + +/* Generic effect writing routine */ +void UniEffect(UWORD eff,UWORD dat) +{ + if((!eff)||(eff>=UNI_LAST)) return; + + UniWriteByte(eff); + if(unioperands[eff]==2) + UniWriteWord(dat); + else + UniWriteByte(dat); +} + +/* Appends UNI_PTEFFECTX opcode to the unitrk stream. */ +void UniPTEffect(UBYTE eff, UBYTE dat) +{ +#ifdef MIKMOD_DEBUG + if (eff>=0x10) + fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff); + else +#endif + if((eff)||(dat)) UniEffect(UNI_PTEFFECT0+eff,dat); +} + +/* Appends UNI_VOLEFFECT + effect/dat to unistream. */ +void UniVolEffect(UWORD eff,UBYTE dat) +{ + if((eff)||(dat)) { /* don't write empty effect */ + UniWriteByte(UNI_VOLEFFECTS); + UniWriteByte(eff);UniWriteByte(dat); + } +} + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/mmsup.c TiMidity++-2.9.0/libunimod/mmsup.c --- TiMidity++-2.8.2/libunimod/mmsup.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/mmsup.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,200 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: mmsup.c,v 1.30 1999/10/25 16:31:41 miod Exp $ + + Error handling, memory, I/O functions. + +==============================================================================*/ + +#include "unimod_priv.h" + +int _mm_errno = 0; + +static CHAR *_mm_errmsg[MMERR_MAX + 1] = +{ +/* No error */ + + "No error", + +/* Generic errors */ + + "Could not open requested file", + "Out of memory", + "Dynamic linking failed", + +/* Sample errors */ + + "Out of memory to load sample", + "Out of sample handles to load sample", + "Sample format not recognized", + +/* Module errors */ + + "Failure loading module pattern", + "Failure loading module track", + "Failure loading module header", + "Failure loading sampleinfo", + "Module format not recognized", + "Module sample format not recognized", + "Synthsounds not supported in MED files", + "Compressed sample is invalid", + +/* Invalid error */ + + "Invalid error code" +}; + +char * +ML_strerror (int code) +{ + if ((code < 0) || (code > MMERR_MAX)) + code = MMERR_MAX + 1; + return _mm_errmsg[code]; +} + + +/* Same as malloc, but sets error variable _mm_error when fails */ +void * +_mm_malloc (size_t size) +{ + void *d; + + if (!(d = calloc (1, size))) + { + _mm_errno = MMERR_OUT_OF_MEMORY; + } + return d; +} + +/* Same as calloc, but sets error variable _mm_error when fails */ +void * +_mm_calloc (size_t nitems, size_t size) +{ + void *d; + + if (!(d = calloc (nitems, size))) + { + _mm_errno = MMERR_OUT_OF_MEMORY; + } + return d; +} + + + +/* I/O - wrappers around liburl + + The way this module works: + + - _mm_read_I_* and _mm_read_M_* differ : the first is for reading data + written by a little endian (intel) machine, and the second is for reading + big endian (Mac, RISC, Alpha) machine data. + - _mm_read_string is for reading binary strings. It is basically the same + as an fread of bytes. + + */ + +#define COPY_BUFSIZE 1024 + +/*========== Read functions */ + +int +_mm_read_string (CHAR * buffer, int number, URL reader) +{ + return url_nread (reader, buffer, number); +} + +UWORD +_mm_read_M_UWORD (URL reader) +{ + UWORD result = ((UWORD) _mm_read_UBYTE (reader)) << 8; + result |= _mm_read_UBYTE (reader); + return result; +} + +UWORD +_mm_read_I_UWORD (URL reader) +{ + UWORD result = _mm_read_UBYTE (reader); + result |= ((UWORD) _mm_read_UBYTE (reader)) << 8; + return result; +} + +ULONG +_mm_read_M_ULONG (URL reader) +{ + ULONG result = ((ULONG) _mm_read_M_UWORD (reader)) << 16; + result |= _mm_read_M_UWORD (reader); + return result; +} + +ULONG +_mm_read_I_ULONG (URL reader) +{ + ULONG result = _mm_read_I_UWORD (reader); + result |= ((ULONG) _mm_read_I_UWORD (reader)) << 16; + return result; +} + +SWORD +_mm_read_M_SWORD (URL reader) +{ + return ((SWORD) _mm_read_M_UWORD (reader)); +} + +SWORD +_mm_read_I_SWORD (URL reader) +{ + return ((SWORD) _mm_read_I_UWORD (reader)); +} + +SLONG +_mm_read_M_SLONG (URL reader) +{ + return ((SLONG) _mm_read_M_ULONG (reader)); +} + +SLONG +_mm_read_I_SLONG (URL reader) +{ + return ((SLONG) _mm_read_I_ULONG (reader)); +} + +#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \ +int _mm_read_##type_name##S (type *buffer,int number,URL reader) \ +{ \ + while(number-->0) \ + *(buffer++)=_mm_read_##type_name(reader); \ + return !url_eof(reader); \ +} + +DEFINE_MULTIPLE_READ_FUNCTION (M_SWORD, SWORD) +DEFINE_MULTIPLE_READ_FUNCTION (M_UWORD, UWORD) +DEFINE_MULTIPLE_READ_FUNCTION (I_SWORD, SWORD) +DEFINE_MULTIPLE_READ_FUNCTION (I_UWORD, UWORD) + +DEFINE_MULTIPLE_READ_FUNCTION (M_SLONG, SLONG) +DEFINE_MULTIPLE_READ_FUNCTION (M_ULONG, ULONG) +DEFINE_MULTIPLE_READ_FUNCTION (I_SLONG, SLONG) +DEFINE_MULTIPLE_READ_FUNCTION (I_ULONG, ULONG) + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/munitrk.c TiMidity++-2.9.0/libunimod/munitrk.c --- TiMidity++-2.8.2/libunimod/munitrk.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/munitrk.c Thu Feb 17 23:22:34 2000 @@ -0,0 +1,332 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: munitrk.c,v 1.27 1999/10/25 16:31:41 miod Exp $ + + All routines dealing with the manipulation of UNITRK streams + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "unimod_priv.h" + +#include + +/* Unibuffer chunk size */ +#define BUFPAGE 128 + +UWORD unioperands[UNI_LAST] = +{ + 0, /* not used */ + 1, /* UNI_NOTE */ + 1, /* UNI_INSTRUMENT */ + 1, /* UNI_PTEFFECT0 */ + 1, /* UNI_PTEFFECT1 */ + 1, /* UNI_PTEFFECT2 */ + 1, /* UNI_PTEFFECT3 */ + 1, /* UNI_PTEFFECT4 */ + 1, /* UNI_PTEFFECT5 */ + 1, /* UNI_PTEFFECT6 */ + 1, /* UNI_PTEFFECT7 */ + 1, /* UNI_PTEFFECT8 */ + 1, /* UNI_PTEFFECT9 */ + 1, /* UNI_PTEFFECTA */ + 1, /* UNI_PTEFFECTB */ + 1, /* UNI_PTEFFECTC */ + 1, /* UNI_PTEFFECTD */ + 1, /* UNI_PTEFFECTE */ + 1, /* UNI_PTEFFECTF */ + 1, /* UNI_S3MEFFECTA */ + 1, /* UNI_S3MEFFECTD */ + 1, /* UNI_S3MEFFECTE */ + 1, /* UNI_S3MEFFECTF */ + 1, /* UNI_S3MEFFECTI */ + 1, /* UNI_S3MEFFECTQ */ + 1, /* UNI_S3MEFFECTR */ + 1, /* UNI_S3MEFFECTT */ + 1, /* UNI_S3MEFFECTU */ + 0, /* UNI_KEYOFF */ + 1, /* UNI_KEYFADE */ + 2, /* UNI_VOLEFFECTS */ + 1, /* UNI_XMEFFECT4 */ + 1, /* UNI_XMEFFECTA */ + 1, /* UNI_XMEFFECTE1 */ + 1, /* UNI_XMEFFECTE2 */ + 1, /* UNI_XMEFFECTEA */ + 1, /* UNI_XMEFFECTEB */ + 1, /* UNI_XMEFFECTG */ + 1, /* UNI_XMEFFECTH */ + 1, /* UNI_XMEFFECTL */ + 1, /* UNI_XMEFFECTP */ + 1, /* UNI_XMEFFECTX1 */ + 1, /* UNI_XMEFFECTX2 */ + 1, /* UNI_ITEFFECTG */ + 1, /* UNI_ITEFFECTH */ + 1, /* UNI_ITEFFECTI */ + 1, /* UNI_ITEFFECTM */ + 1, /* UNI_ITEFFECTN */ + 1, /* UNI_ITEFFECTP */ + 1, /* UNI_ITEFFECTT */ + 1, /* UNI_ITEFFECTU */ + 1, /* UNI_ITEFFECTW */ + 1, /* UNI_ITEFFECTY */ + 2, /* UNI_ITEFFECTZ */ + 1, /* UNI_ITEFFECTS0 */ + 2, /* UNI_ULTEFFECT9 */ + 2, /* UNI_MEDSPEED */ + 0, /* UNI_MEDEFFECTF1 */ + 0, /* UNI_MEDEFFECTF2 */ + 0 /* UNI_MEDEFFECTF3 */ +}; + +/* Sparse description of the internal module format + ------------------------------------------------ + + A UNITRK stream is an array of bytes representing a single track of a pattern. + It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly + language): + + rrrlllll + [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND].. + ^ ^ ^ + |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track... + + The rep/len byte contains the number of bytes in the current row, _including_ + the length byte itself (So the LENGTH byte of row 0 in the previous example + would have a value of 5). This makes it easy to search through a stream for a + particular row. A track is concluded by a 0-value length byte. + + The upper 3 bits of the rep/len byte contain the number of times -1 this row + is repeated for this track. (so a value of 7 means this row is repeated 8 times) + + Opcodes can range from 1 to 255 but currently only opcodes 1 to 52 are being + used. Each opcode can have a different number of operands. You can find the + number of operands to a particular opcode by using the opcode as an index into + the 'unioperands' table. + + */ + +/*========== Reading routines */ + +static UBYTE *rowstart; /* startadress of a row */ +static UBYTE *rowend; /* endaddress of a row (exclusive) */ +static UBYTE *rowpc; /* current unimod(tm) programcounter */ + + +void +UniSetRow (UBYTE * t) +{ + rowstart = t; + rowpc = rowstart; + rowend = t ? rowstart + (*(rowpc++) & 0x1f) : t; +} + +UBYTE +UniGetByte (void) +{ + return (rowpc < rowend) ? *(rowpc++) : 0; +} + +UWORD +UniGetWord (void) +{ + return ((UWORD) UniGetByte () << 8) | UniGetByte (); +} + +void +UniSkipOpcode (UBYTE op) +{ + if (op < UNI_LAST) + { + UWORD t = unioperands[op]; + + while (t--) + UniGetByte (); + } +} + +/* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns + NULL if the row can't be found. */ +UBYTE * +UniFindRow (UBYTE * t, UWORD row) +{ + UBYTE c, l; + + if (t) + while (1) + { + c = *t; /* get rep/len byte */ + if (!c) + return NULL; /* zero ? -> end of track.. */ + l = (c >> 5) + 1; /* extract repeat value */ + if (l > row) + break; /* reached wanted row? -> return pointer */ + row -= l; /* haven't reached row yet.. update row */ + t += c & 0x1f; /* point t to the next row */ + } + return t; +} + +/*========== Writing routines */ + +static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */ +static UWORD unimax; /* buffer size */ + +static UWORD unipc; /* buffer cursor */ +static UWORD unitt; /* current row index */ +static UWORD lastp; /* previous row index */ + +/* Resets index-pointers to create a new track. */ +void +UniReset (void) +{ + unitt = 0; /* reset index to rep/len byte */ + unipc = 1; /* first opcode will be written to index 1 */ + lastp = 0; /* no previous row yet */ + unibuf[0] = 0; /* clear rep/len byte */ +} + +/* Expands the buffer */ +static BOOL +UniExpand (int wanted) +{ + if ((unipc + wanted) >= unimax) + { + UBYTE *newbuf; + + /* Expand the buffer by BUFPAGE bytes */ + newbuf = (UBYTE *) realloc (unibuf, (unimax + BUFPAGE) * sizeof (UBYTE)); + + /* Check if realloc succeeded */ + if (newbuf) + { + unibuf = newbuf; + unimax += BUFPAGE; + return 1; + } + else + return 0; + } + return 1; +} + +/* Appends one byte of data to the current row of a track. */ +void +UniWriteByte (UBYTE data) +{ + if (UniExpand (1)) + /* write byte to current position and update */ + unibuf[unipc++] = data; +} + +void +UniWriteWord (UWORD data) +{ + if (UniExpand (2)) + { + unibuf[unipc++] = data >> 8; + unibuf[unipc++] = data & 0xff; + } +} + +static BOOL +MyCmp (UBYTE * a, UBYTE * b, UWORD l) +{ + UWORD t; + + for (t = 0; t < l; t++) + if (*(a++) != *(b++)) + return 0; + return 1; +} + +/* Closes the current row of a unitrk stream (updates the rep/len byte) and sets + pointers to start a new row. */ +void +UniNewline (void) +{ + UWORD n, l, len; + + n = (unibuf[lastp] >> 5) + 1; /* repeat of previous row */ + l = (unibuf[lastp] & 0x1f); /* length of previous row */ + + len = unipc - unitt; /* length of current row */ + + /* Now, check if the previous and the current row are identical.. when they + are, just increase the repeat field of the previous row */ + if (n < 8 && len == l && MyCmp (&unibuf[lastp + 1], &unibuf[unitt + 1], len - 1)) + { + unibuf[lastp] += 0x20; + unipc = unitt + 1; + } + else + { + if (UniExpand (unitt - unipc)) + { + /* current and previous row aren't equal... update the pointers */ + unibuf[unitt] = len; + lastp = unitt; + unitt = unipc++; + } + } +} + +/* Terminates the current unitrk stream and returns a pointer to a copy of the + stream. */ +UBYTE * +UniDup (void) +{ + UBYTE *d; + + if (!UniExpand (unitt - unipc)) + return NULL; + unibuf[unitt] = 0; + + if (!(d = (UBYTE *) _mm_malloc (unipc))) + return NULL; + memcpy (d, unibuf, unipc); + + return d; +} + +BOOL +UniInit (void) +{ + unimax = BUFPAGE; + + if (!(unibuf = (UBYTE *) _mm_malloc (unimax * sizeof (UBYTE)))) + return 0; + return 1; +} + +void +UniCleanup (void) +{ + if (unibuf) + free (unibuf); + unibuf = NULL; +} + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/unimod.h TiMidity++-2.9.0/libunimod/unimod.h --- TiMidity++-2.8.2/libunimod/unimod.h Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/unimod.h Thu Feb 24 14:14:44 2000 @@ -0,0 +1,505 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: unimod.h,v 1.35 1999/10/25 16:31:41 miod Exp $ + + MikMod sound library include file + +==============================================================================*/ + +#ifndef _UNIMOD_H_ +#define _UNIMOD_H_ + +#include +#include +#include "url.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * ========== Platform independent-type definitions + */ + +#ifdef __W32__ +#define WIN32_LEAN_AND_MEAN +#include +#include +#elif defined(__OS2__)||defined(__EMX__) +#define INCL_DOSSEMAPHORES +#include +#else +typedef char CHAR; +#endif + +#if defined(__alpha) +/* 64 bit architectures */ + +typedef signed char SBYTE; /* 1 byte, signed */ +typedef unsigned char UBYTE; /* 1 byte, unsigned */ +typedef signed short SWORD; /* 2 bytes, signed */ +typedef unsigned short UWORD; /* 2 bytes, unsigned */ +typedef signed int SLONG; /* 4 bytes, signed */ +typedef unsigned int ULONG; /* 4 bytes, unsigned */ +typedef int BOOL; /* 0=false, <>0 true */ + +#else +/* 32 bit architectures */ + +typedef signed char SBYTE; /* 1 byte, signed */ +typedef unsigned char UBYTE; /* 1 byte, unsigned */ +typedef signed short SWORD; /* 2 bytes, signed */ +typedef unsigned short UWORD; /* 2 bytes, unsigned */ +typedef signed long SLONG; /* 4 bytes, signed */ +#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(__W32__) +typedef unsigned long ULONG; /* 4 bytes, unsigned */ +typedef int BOOL; /* 0=false, <>0 true */ +#endif +#endif + +/* + * ========== Error handling and error codes + */ + +extern int ML_errno; +extern char *ML_strerror (int); + +enum +{ + MMERR_OPENING_FILE = 1, + MMERR_OUT_OF_MEMORY, + MMERR_DYNAMIC_LINKING, + + MMERR_SAMPLE_TOO_BIG, + MMERR_OUT_OF_HANDLES, + MMERR_UNKNOWN_WAVE_TYPE, + + MMERR_LOADING_PATTERN, + MMERR_LOADING_TRACK, + MMERR_LOADING_HEADER, + MMERR_LOADING_SAMPLEINFO, + MMERR_NOT_A_MODULE, + MMERR_NOT_A_STREAM, + MMERR_MED_SYNTHSAMPLES, + MMERR_ITPACK_INVALID_DATA, + + MMERR_MAX +}; + +/*========== Internal module representation (UniMod) interface */ + +/* number of notes in an octave */ +#define OCTAVE 12 + +extern void UniSetRow (UBYTE *); +extern UBYTE UniGetByte (void); +extern UWORD UniGetWord (void); +extern UBYTE *UniFindRow (UBYTE *, UWORD); +extern void UniSkipOpcode (UBYTE); +extern void UniReset (void); +extern void UniWriteByte (UBYTE); +extern void UniWriteWord (UWORD); +extern void UniNewline (void); +extern UBYTE *UniDup (void); +extern BOOL UniInit (void); +extern void UniCleanup (void); +extern void UniEffect (UWORD, UWORD); +#define UniInstrument(x) UniEffect(UNI_INSTRUMENT,x) +#define UniNote(x) UniEffect(UNI_NOTE,x) +extern void UniPTEffect (UBYTE, UBYTE); +extern void UniVolEffect (UWORD, UBYTE); + +/*========== Module Commands */ + +enum +{ + /* Simple note */ + UNI_NOTE = 1, + /* Instrument change */ + UNI_INSTRUMENT, + /* Protracker effects */ + UNI_PTEFFECT0, /* arpeggio */ + UNI_PTEFFECT1, /* porta up */ + UNI_PTEFFECT2, /* porta down */ + UNI_PTEFFECT3, /* porta to note */ + UNI_PTEFFECT4, /* vibrato */ + UNI_PTEFFECT5, /* dual effect 3+A */ + UNI_PTEFFECT6, /* dual effect 4+A */ + UNI_PTEFFECT7, /* tremolo */ + UNI_PTEFFECT8, /* pan */ + UNI_PTEFFECT9, /* sample offset */ + UNI_PTEFFECTA, /* volume slide */ + UNI_PTEFFECTB, /* pattern jump */ + UNI_PTEFFECTC, /* set volume */ + UNI_PTEFFECTD, /* pattern break */ + UNI_PTEFFECTE, /* extended effects */ + UNI_PTEFFECTF, /* set speed */ + /* Scream Tracker effects */ + UNI_S3MEFFECTA, /* set speed */ + UNI_S3MEFFECTD, /* volume slide */ + UNI_S3MEFFECTE, /* porta down */ + UNI_S3MEFFECTF, /* porta up */ + UNI_S3MEFFECTI, /* tremor */ + UNI_S3MEFFECTQ, /* retrig */ + UNI_S3MEFFECTR, /* tremolo */ + UNI_S3MEFFECTT, /* set tempo */ + UNI_S3MEFFECTU, /* fine vibrato */ + UNI_KEYOFF, /* note off */ + /* Fast Tracker effects */ + UNI_KEYFADE, /* note fade */ + UNI_VOLEFFECTS, /* volume column effects */ + UNI_XMEFFECT4, /* vibrato */ + UNI_XMEFFECTA, /* volume slide */ + UNI_XMEFFECTE1, /* fine porta up */ + UNI_XMEFFECTE2, /* fine porta down */ + UNI_XMEFFECTEA, /* fine volume slide up */ + UNI_XMEFFECTEB, /* fine volume slide down */ + UNI_XMEFFECTG, /* set global volume */ + UNI_XMEFFECTH, /* global volume slide */ + UNI_XMEFFECTL, /* set envelope position */ + UNI_XMEFFECTP, /* pan slide */ + UNI_XMEFFECTX1, /* extra fine porta up */ + UNI_XMEFFECTX2, /* extra fine porta down */ + /* Impulse Tracker effects */ + UNI_ITEFFECTG, /* porta to note */ + UNI_ITEFFECTH, /* vibrato */ + UNI_ITEFFECTI, /* tremor (xy not incremented) */ + UNI_ITEFFECTM, /* set channel volume */ + UNI_ITEFFECTN, /* slide / fineslide channel volume */ + UNI_ITEFFECTP, /* slide / fineslide channel panning */ + UNI_ITEFFECTT, /* slide tempo */ + UNI_ITEFFECTU, /* fine vibrato */ + UNI_ITEFFECTW, /* slide / fineslide global volume */ + UNI_ITEFFECTY, /* panbrello */ + UNI_ITEFFECTZ, /* resonant filters */ + UNI_ITEFFECTS0, + /* UltraTracker effects */ + UNI_ULTEFFECT9, /* Sample fine offset */ + /* OctaMED effects */ + UNI_MEDSPEED, + UNI_MEDEFFECTF1, /* play note twice */ + UNI_MEDEFFECTF2, /* delay note */ + UNI_MEDEFFECTF3, /* play note three times */ + + UNI_LAST +}; + +extern UWORD unioperands[UNI_LAST]; + +/* IT / S3M Extended SS effects: */ +enum +{ + SS_GLISSANDO = 1, + SS_FINETUNE, + SS_VIBWAVE, + SS_TREMWAVE, + SS_PANWAVE, + SS_FRAMEDELAY, + SS_S7EFFECTS, + SS_PANNING, + SS_SURROUND, + SS_HIOFFSET, + SS_PATLOOP, + SS_NOTECUT, + SS_NOTEDELAY, + SS_PATDELAY +}; + +/* IT Volume column effects */ +enum +{ + VOL_VOLUME = 1, + VOL_PANNING, + VOL_VOLSLIDE, + VOL_PITCHSLIDEDN, + VOL_PITCHSLIDEUP, + VOL_PORTAMENTO, + VOL_VIBRATO +}; + +/* IT resonant filter information */ + +#define FILT_CUT 0x80 +#define FILT_RESONANT 0x81 + +typedef struct FILTER +{ + UBYTE filter, inf; +} +FILTER; + +/*========== Instruments */ + +/* Instrument format flags */ +#define IF_OWNPAN 1 +#define IF_PITCHPAN 2 + +/* Envelope flags: */ +#define EF_ON 1 +#define EF_SUSTAIN 2 +#define EF_LOOP 4 +#define EF_VOLENV 8 + +/* New Note Action Flags */ +#define NNA_CUT 0 +#define NNA_CONTINUE 1 +#define NNA_OFF 2 +#define NNA_FADE 3 + +#define NNA_MASK 3 + +#define DCT_OFF 0 +#define DCT_NOTE 1 +#define DCT_SAMPLE 2 +#define DCT_INST 3 + +#define DCA_CUT 0 +#define DCA_OFF 1 +#define DCA_FADE 2 + +#define KEY_KICK 0 +#define KEY_OFF 1 +#define KEY_FADE 2 +#define KEY_KILL (KEY_OFF|KEY_FADE) + +#define KICK_ABSENT 0 +#define KICK_NOTE 1 +#define KICK_KEYOFF 2 +#define KICK_ENV 4 + +#define AV_IT 1 /* IT vs. XM vibrato info */ + + +/* + * ========== Samples + */ + +/* Sample format [loading and in-memory] flags: */ +#define SF_16BITS 0x0001 +#define SF_STEREO 0x0002 +#define SF_SIGNED 0x0004 +#define SF_BIG_ENDIAN 0x0008 +#define SF_DELTA 0x0010 +#define SF_ITPACKED 0x0020 + +#define SF_FORMATMASK 0x003F + +/* General Playback flags */ + +#define SF_LOOP 0x0100 +#define SF_BIDI 0x0200 +#define SF_REVERSE 0x0400 +#define SF_SUSTAIN 0x0800 + +#define SF_PLAYBACKMASK 0x0C00 + +/* Module-only Playback Flags */ + +#define SF_OWNPAN 0x1000 +#define SF_UST_LOOP 0x2000 + +#define SF_EXTRAPLAYBACKMASK 0x3000 + +/* Panning constants */ +#define PAN_LEFT 0 +#define PAN_CENTER 128 +#define PAN_RIGHT 255 +#define PAN_SURROUND 512 /* panning value for Dolby Surround */ + +/* This stuff is all filled -- it's up to you whether to implement it. */ +typedef struct SAMPLE +{ + SWORD panning; /* panning (0-255 or PAN_SURROUND) */ + ULONG speed; /* Base playing speed/frequency of note */ + UBYTE volume; /* volume 0-64 */ + UWORD inflags; /* sample format on disk */ + UWORD flags; /* sample format in memory */ + ULONG length; /* length of sample (in samples!) */ + ULONG loopstart; /* repeat position (relative to start, in samples) */ + ULONG loopend; /* repeat end */ + ULONG susbegin; /* sustain loop begin (in samples) */ + ULONG susend; /* sustain loop end */ + + UBYTE globvol; /* global volume */ + UBYTE vibflags; /* autovibrato flag stuffs */ + UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */ + UBYTE vibsweep; + UBYTE vibdepth; + UBYTE vibrate; + CHAR *samplename; /* name of the sample */ + + UWORD id; /* available for user */ + UBYTE divfactor; /* for sample scaling */ + ULONG seekpos; /* seek position in file -- internal */ + SWORD *data; /* ptr to actual sample data */ +} +SAMPLE; + +/* + * ========== Internal module representation (UniMod) + */ + +/* + Instrument definition - for information only, the only field which may be + of use in user programs is the name field + */ + +/* Instrument note count */ +#define INSTNOTES 120 + +/* Envelope point */ +typedef struct ENVPT +{ + SWORD pos; + SWORD val; +} +ENVPT; + +/* Envelope point count */ +#define ENVPOINTS 32 + +/* Instrument structure */ +typedef struct INSTRUMENT +{ + CHAR *insname; + + UBYTE flags; + UWORD samplenumber[INSTNOTES]; + UBYTE samplenote[INSTNOTES]; + + UBYTE nnatype; + UBYTE dca; /* duplicate check action */ + UBYTE dct; /* duplicate check type */ + UBYTE globvol; + UWORD volfade; + SWORD panning; /* instrument-based panning var */ + + UBYTE pitpansep; /* pitch pan separation (0 to 255) */ + UBYTE pitpancenter; /* pitch pan center (0 to 119) */ + UBYTE rvolvar; /* random volume varations (0 - 100%) */ + UBYTE rpanvar; /* random panning varations (0 - 100%) */ + + /* volume envelope */ + UBYTE volflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE volpts; + UBYTE volsusbeg; + UBYTE volsusend; + UBYTE volbeg; + UBYTE volend; + ENVPT volenv[ENVPOINTS]; + /* panning envelope */ + UBYTE panflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE panpts; + UBYTE pansusbeg; + UBYTE pansusend; + UBYTE panbeg; + UBYTE panend; + ENVPT panenv[ENVPOINTS]; + /* pitch envelope */ + UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE pitpts; + UBYTE pitsusbeg; + UBYTE pitsusend; + UBYTE pitbeg; + UBYTE pitend; + ENVPT pitenv[ENVPOINTS]; +} +INSTRUMENT; + +/* Module flags */ +#define UF_XMPERIODS 0x0001 /* XM periods / finetuning */ +#define UF_LINEAR 0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */ +#define UF_INST 0x0004 /* Instruments are used */ +#define UF_NNA 0x0008 /* IT: NNA used, set numvoices rather than numchn */ +#define UF_S3MSLIDES 0x0010 /* uses old S3M volume slides */ +#define UF_BGSLIDES 0x0020 /* continue volume slides in the background */ +#define UF_HIGHBPM 0x0040 /* MED: can use >255 bpm */ +#define UF_NOWRAP 0x0080 /* XM-type (i.e. illogical) pattern brk semantics */ +#define UF_ARPMEM 0x0100 /* IT: need arpeggio memory */ +#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */ + +typedef struct MODULE +{ + /* general module information */ + CHAR *songname; /* name of the song */ + CHAR *modtype; /* string type of module loaded */ + CHAR *comment; /* module comments */ + + UWORD flags; /* See module flags above */ + UBYTE numchn; /* number of module channels */ + UBYTE numvoices; /* max # voices used for full NNA playback */ + UWORD numpos; /* number of positions in this song */ + UWORD numpat; /* number of patterns in this song */ + UWORD numins; /* number of instruments */ + UWORD numsmp; /* number of samples */ + INSTRUMENT *instruments; /* all instruments */ + SAMPLE *samples; /* all samples */ + + /* playback settings */ + UWORD reppos; /* restart position */ + UBYTE initspeed; /* initial song speed */ + UWORD inittempo; /* initial song tempo */ + UBYTE initvolume; /* initial global volume (0 - 128) */ + UWORD panning[64]; /* 64 panning positions */ + UBYTE chanvol[64]; /* 64 channel positions */ + UWORD bpm; /* current beats-per-minute speed */ + + /* internal module representation */ + UWORD numtrk; /* number of tracks */ + UBYTE **tracks; /* array of numtrk pointers to tracks */ + UWORD *patterns; /* array of Patterns */ + UWORD *pattrows; /* array of number of rows for each pattern */ + UWORD *positions; /* all positions */ +} + MODULE; + +/* used to convert c4spd to linear XM periods (IT and IMF loaders). */ +extern UWORD finetune[]; +extern UWORD getlinearperiod (UWORD, ULONG); +extern UWORD getlogperiod (UWORD note, ULONG fine); +extern UWORD getoldperiod (UWORD, ULONG); +extern ULONG getfrequency (UBYTE, ULONG); +extern ULONG getAmigaPeriod (UBYTE, ULONG); + +/* + * ========== External interface + */ + +extern UWORD finetune[]; +extern BOOL ML_8bitsamples; +extern BOOL ML_monosamples; +extern CHAR *ML_InfoLoader (void); +extern void ML_RegisterAllLoaders (void); +extern BOOL ML_Test (URL); +extern MODULE *ML_Load (URL, int, BOOL); +extern CHAR *ML_LoadTitle (URL); +extern void ML_Free (MODULE *); + +#ifdef __cplusplus +} +#endif + +#endif + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/libunimod/unimod_priv.h TiMidity++-2.9.0/libunimod/unimod_priv.h --- TiMidity++-2.8.2/libunimod/unimod_priv.h Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/libunimod/unimod_priv.h Thu Feb 24 14:15:25 2000 @@ -0,0 +1,153 @@ +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + */ + +/*============================================================================== + + $Id: unimod_priv.h,v 1.23 1999/10/25 16:31:41 miod Exp $ + + MikMod sound library internal definitions + +==============================================================================*/ + +#ifndef _UNIMOD_PRIV_H +#define _UNIMOD_PRIV_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef HAVE_MALLOC_H +#include +#endif +#include +#if defined(__OS2__)||defined(__EMX__)||defined(__W32__) +#define strcasecmp(s,t) stricmp(s,t) +#endif + +#include "unimod.h" +#include "url.h" + +#ifdef __W32__ +#pragma warning(disable:4761) +#endif + +/*========== Error handling */ + +#define _mm_errno ML_errno + +/*========== Memory allocation */ + +extern void *_mm_malloc (size_t); +extern void *_mm_calloc (size_t, size_t); +#define _mm_free(p) do { if (p) free(p); p = NULL; } while(0) + +/*========== Portable file I/O */ + +#define _mm_read_SBYTE(x) ((SBYTE)url_getc(x)) +#define _mm_read_UBYTE(x) ((UBYTE)url_getc(x)) +#define _mm_read_SBYTES(x,y,z) url_nread(z,(void *)x,y) +#define _mm_read_UBYTES(x,y,z) url_nread(z,(void *)x,y) +#define _mm_fseek(x,y,z) url_seek(x,y,z) +#define _mm_ftell(x) url_tell(x) +#define _mm_eof(x) url_eof(x) +#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET) + +extern int _mm_read_string (CHAR *, int, URL); + +extern SWORD _mm_read_M_SWORD (URL); +extern SWORD _mm_read_I_SWORD (URL); +extern UWORD _mm_read_M_UWORD (URL); +extern UWORD _mm_read_I_UWORD (URL); + +extern SLONG _mm_read_M_SLONG (URL); +extern SLONG _mm_read_I_SLONG (URL); +extern ULONG _mm_read_M_ULONG (URL); +extern ULONG _mm_read_I_ULONG (URL); + +extern int _mm_read_M_SWORDS (SWORD *, int, URL); +extern int _mm_read_I_SWORDS (SWORD *, int, URL); +extern int _mm_read_M_UWORDS (UWORD *, int, URL); +extern int _mm_read_I_UWORDS (UWORD *, int, URL); + +extern int _mm_read_M_SLONGS (SLONG *, int, URL); +extern int _mm_read_I_SLONGS (SLONG *, int, URL); +extern int _mm_read_M_ULONGS (ULONG *, int, URL); +extern int _mm_read_I_ULONGS (ULONG *, int, URL); + + +/*========== Loaders */ + +typedef struct MLOADER +{ + struct MLOADER *next; + CHAR *type; + CHAR *version; + BOOL (*Init) (void); + BOOL (*Test) (void); + BOOL (*Load) (BOOL); + void (*Cleanup) (void); + CHAR *(*LoadTitle) (void); +} +MLOADER; + +/* internal loader variables: */ +extern URL modreader; +extern UWORD finetune[16]; +extern MODULE of; /* static unimod loading space */ + +extern SBYTE remap[64]; /* for removing empty channels */ +extern UBYTE *poslookup; /* lookup table for pattern jumps after + blank pattern removal */ +extern UBYTE poslookupcnt; +extern UWORD *origpositions; + +extern BOOL filters; /* resonant filters in use */ +extern UBYTE activemacro; /* active midi macro number for Sxx */ +extern UBYTE filtermacros[16]; /* midi macros settings */ +extern FILTER filtersettings[256]; /* computed filter settings */ + +extern int *noteindex; + +/*========== Internal loader interface */ + +extern BOOL ReadComment (UWORD); +extern BOOL ReadLinedComment (UWORD, UWORD); +extern BOOL AllocPositions (int); +extern BOOL AllocPatterns (void); +extern BOOL AllocTracks (void); +extern BOOL AllocInstruments (void); +extern BOOL AllocSamples (void); +extern CHAR *DupStr (CHAR *, UWORD, BOOL); + +/* loader utility functions */ +extern int *AllocLinear (void); +extern void FreeLinear (void); +extern int speed_to_finetune (ULONG, int); +extern void S3MIT_ProcessCmd (UBYTE, UBYTE, BOOL); +extern void S3MIT_CreateOrders (BOOL); + +#ifdef __cplusplus +} +#endif + +#endif + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/timidity/Makefile.am TiMidity++-2.9.0/timidity/Makefile.am --- TiMidity++-2.8.2/timidity/Makefile.am Mon Feb 7 08:02:27 2000 +++ TiMidity++-2.9.0/timidity/Makefile.am Wed Feb 16 01:05:03 2000 @@ -21,6 +21,7 @@ INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/libarc \ + -I$(top_srcdir)/libunimod \ -I$(top_srcdir)/interface \ -I$(top_srcdir)/utils \ $(EXTRAINCS) @@ -46,7 +47,6 @@ instrum.c \ instrum.h \ list_a.c \ - load_mod.c \ loadtab.c \ mid-j.defs \ mid.defs \ @@ -56,6 +56,8 @@ mix.h \ mod.c \ mod.h \ + mod2midi.c \ + mod2midi.h \ output.c \ output.h \ playmidi.c \ @@ -128,12 +130,14 @@ $(SYSEXTRAS:.c=.o) \ $(top_builddir)/interface/libinterface.a \ $(top_builddir)/libarc/libarc.a \ + $(top_builddir)/libunimod/libunimod.a \ $(top_builddir)/utils/libutils.a \ $(W32GUI_RES) timidity_DEPENDENCIES = $(SYSEXTRAS:.c=.o) \ $(top_builddir)/interface/libinterface.a \ $(top_builddir)/libarc/libarc.a \ + $(top_builddir)/libunimod/libunimod.a \ $(top_builddir)/utils/libutils.a \ $(W32GUI_RES) @@ -145,6 +149,9 @@ $(top_builddir)/libarc/libarc.a: cd $(top_builddir)/libarc; $(MAKE) + +$(top_builddir)/libunimod/libunimod.a: + cd $(top_builddir)/libunimod; $(MAKE) $(top_builddir)/utils/libutils.a: cd $(top_builddir)/utils; $(MAKE) diff -ruN TiMidity++-2.8.2/timidity/Makefile.in TiMidity++-2.9.0/timidity/Makefile.in --- TiMidity++-2.8.2/timidity/Makefile.in Mon Feb 7 21:39:34 2000 +++ TiMidity++-2.9.0/timidity/Makefile.in Sun Feb 27 22:50:34 2000 @@ -112,12 +112,12 @@ tcltk_dep = @tcltk_dep@ timidity_LDFLAGS = @timidity_LDFLAGS@ -INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libarc -I$(top_srcdir)/interface -I$(top_srcdir)/utils $(EXTRAINCS) +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libarc -I$(top_srcdir)/libunimod -I$(top_srcdir)/interface -I$(top_srcdir)/utils $(EXTRAINCS) bin_PROGRAMS = timidity -timidity_SOURCES = aenc.h aiff_a.c aq.c aq.h au_a.c audio_cnv.c audio_cnv.h common.c common.h controls.c controls.h dlutils.h effect.c filter.c filter.h instrum.c instrum.h list_a.c load_mod.c loadtab.c mid-j.defs mid.defs miditrace.c miditrace.h mix.c mix.h mod.c mod.h output.c output.h playmidi.c playmidi.h raw_a.c rcp.c readmidi.c readmidi.h recache.c recache.h resample.c resample.h reverb.c reverb.h sbkconv.c sffile.c sffile.h sfitem.c sfitem.h sflayer.h smfconv.c smfconv.h sndfont.c tables.c tables.h timidity.c timidity.h version.c wave_a.c wrd.h wrd_read.c wrdt.c +timidity_SOURCES = aenc.h aiff_a.c aq.c aq.h au_a.c audio_cnv.c audio_cnv.h common.c common.h controls.c controls.h dlutils.h effect.c filter.c filter.h instrum.c instrum.h list_a.c loadtab.c mid-j.defs mid.defs miditrace.c miditrace.h mix.c mix.h mod.c mod.h mod2midi.c mod2midi.h output.c output.h playmidi.c playmidi.h raw_a.c rcp.c readmidi.c readmidi.h recache.c recache.h resample.c resample.h reverb.c reverb.h sbkconv.c sffile.c sffile.h sfitem.c sfitem.h sflayer.h smfconv.c smfconv.h sndfont.c tables.c tables.h timidity.c timidity.h version.c wave_a.c wrd.h wrd_read.c wrdt.c EXTRA_timidity_SOURCES = alsa_a.c audriv.h audriv_a.c audriv_al.c audriv_mme.c audriv_none.c dl_w32.c dl_dld.c dl_dlopen.c dl_hpux.c bsd20_a.c esd_a.c hpux_a.c hpux_d_a.c oss_a.c mac_a.c mac_qt_a.c mac_com.h mac_dlog.c mac_main.c mac_main.h mac_soundspec.c mfnode.c mfnode.h nas_a.c sun_a.c w32_a.c w32g_a.c timpp32g.ini @@ -125,10 +125,10 @@ @ENABLE_W32GUI_TRUE@W32GUI_RES = $(top_builddir)/interface/w32g_res.res -timidity_LDADD = $(SYSEXTRAS:.c=.o) $(top_builddir)/interface/libinterface.a $(top_builddir)/libarc/libarc.a $(top_builddir)/utils/libutils.a $(W32GUI_RES) +timidity_LDADD = $(SYSEXTRAS:.c=.o) $(top_builddir)/interface/libinterface.a $(top_builddir)/libarc/libarc.a $(top_builddir)/libunimod/libunimod.a $(top_builddir)/utils/libutils.a $(W32GUI_RES) -timidity_DEPENDENCIES = $(SYSEXTRAS:.c=.o) $(top_builddir)/interface/libinterface.a $(top_builddir)/libarc/libarc.a $(top_builddir)/utils/libutils.a $(W32GUI_RES) +timidity_DEPENDENCIES = $(SYSEXTRAS:.c=.o) $(top_builddir)/interface/libinterface.a $(top_builddir)/libarc/libarc.a $(top_builddir)/libunimod/libunimod.a $(top_builddir)/utils/libutils.a $(W32GUI_RES) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = ../config.h ../interface.h @@ -145,8 +145,8 @@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ timidity_OBJECTS = aiff_a.o aq.o au_a.o audio_cnv.o common.o controls.o \ -effect.o filter.o instrum.o list_a.o load_mod.o loadtab.o miditrace.o \ -mix.o mod.o output.o playmidi.o raw_a.o rcp.o readmidi.o recache.o \ +effect.o filter.o instrum.o list_a.o loadtab.o miditrace.o mix.o mod.o \ +mod2midi.o output.o playmidi.o raw_a.o rcp.o readmidi.o recache.o \ resample.o reverb.o sbkconv.o sffile.o sfitem.o smfconv.o sndfont.o \ tables.o timidity.o version.o wave_a.o wrd_read.o wrdt.o CFLAGS = @CFLAGS@ @@ -280,8 +280,7 @@ ../libarc/arc.h ../utils/nkflib.h wrd.h ../utils/strtab.h controls.o: controls.c ../config.h ../interface.h timidity.h \ ../utils/support.h controls.h -dl_dlopen.o: dl_dlopen.c ../config.h timidity.h ../utils/support.h \ - dlutils.h +debug.o: debug.c effect.o: effect.c ../config.h timidity.h ../utils/support.h instrum.h \ playmidi.h output.h reverb.h filter.o: filter.c ../config.h timidity.h ../utils/support.h common.h \ @@ -292,9 +291,6 @@ list_a.o: list_a.c ../config.h timidity.h ../utils/support.h common.h \ ../libarc/url.h ../utils/mblock.h instrum.h playmidi.h \ readmidi.h output.h controls.h -load_mod.o: load_mod.c ../config.h timidity.h ../utils/support.h \ - common.h ../libarc/url.h ../utils/mblock.h instrum.h playmidi.h \ - readmidi.h tables.h mod.h output.h controls.h loadtab.o: loadtab.c ../config.h timidity.h ../utils/support.h common.h \ ../libarc/url.h ../utils/mblock.h tables.h controls.h miditrace.o: miditrace.c ../config.h timidity.h ../utils/support.h \ @@ -305,7 +301,12 @@ controls.h tables.h resample.h mix.h mod.o: mod.c ../config.h timidity.h ../utils/support.h common.h \ ../libarc/url.h ../utils/mblock.h instrum.h playmidi.h \ - readmidi.h tables.h mod.h output.h controls.h + readmidi.h tables.h mod.h output.h controls.h \ + ../libunimod/unimod.h mod2midi.h +mod2midi.o: mod2midi.c ../config.h timidity.h ../utils/support.h \ + common.h ../libarc/url.h ../utils/mblock.h instrum.h playmidi.h \ + readmidi.h tables.h mod.h output.h controls.h \ + ../libunimod/unimod.h mod2midi.h nas_a.o: nas_a.c ../config.h timidity.h ../utils/support.h common.h \ ../libarc/url.h ../utils/mblock.h output.h controls.h \ ../utils/timer.h instrum.h playmidi.h miditrace.h @@ -352,7 +353,8 @@ ../utils/support.h common.h ../libarc/url.h ../utils/mblock.h \ instrum.h playmidi.h readmidi.h output.h controls.h tables.h \ miditrace.h reverb.h ../interface/soundspec.h recache.h \ - ../libarc/arc.h ../utils/strtab.h wrd.h mid.defs aq.h mix.h + ../libarc/arc.h ../utils/strtab.h wrd.h mid.defs aq.h mix.h \ + ../libunimod/unimod.h wave_a.o: wave_a.c ../config.h timidity.h ../utils/support.h output.h \ controls.h wrd_read.o: wrd_read.c ../config.h timidity.h ../utils/support.h \ @@ -443,6 +445,9 @@ $(top_builddir)/libarc/libarc.a: cd $(top_builddir)/libarc; $(MAKE) + +$(top_builddir)/libunimod/libunimod.a: + cd $(top_builddir)/libunimod; $(MAKE) $(top_builddir)/utils/libutils.a: cd $(top_builddir)/utils; $(MAKE) diff -ruN TiMidity++-2.8.2/timidity/controls.h TiMidity++-2.9.0/timidity/controls.h --- TiMidity++-2.8.2/timidity/controls.h Mon Feb 7 08:00:42 2000 +++ TiMidity++-2.9.0/timidity/controls.h Sat Feb 19 18:34:12 2000 @@ -88,7 +88,7 @@ CTLE_CURRENT_TIME, /* v1:secs, v2:voices */ CTLE_NOTE, /* v1:status, v2:ch, v3:note, v4:velo */ CTLE_MASTER_VOLUME, /* v1:amp(%) */ - CTLE_PROGRAM, /* v1:ch, v2:prog, v3:name */ + CTLE_PROGRAM, /* v1:ch, v2:prog, v3:name, v4:bank,lsb.msb */ CTLE_VOLUME, /* v1:ch, v2:value */ CTLE_EXPRESSION, /* v1:ch, v2:value */ CTLE_PANNING, /* v1:ch, v2:value */ @@ -103,7 +103,8 @@ CTLE_SPEANA, /* v1:double[] v2:len */ CTLE_PAUSE, /* v1:pause on/off v2:time of pause */ CTLE_GSLCD, /* GS L.C.D. */ - CTLE_MAXVOICES /* v1:voices, Change voices */ + CTLE_MAXVOICES, /* v1:voices, Change voices */ + CTLE_DRUMPART /* v1:ch, v2:is_drum */ }; typedef struct _CtlEvent { diff -ruN TiMidity++-2.8.2/timidity/instrum.c TiMidity++-2.9.0/timidity/instrum.c --- TiMidity++-2.8.2/timidity/instrum.c Mon Feb 7 07:59:45 2000 +++ TiMidity++-2.9.0/timidity/instrum.c Thu Feb 17 20:40:18 2000 @@ -1003,10 +1003,13 @@ free(special_patch[i]->name); n = special_patch[i]->samples; sp = special_patch[i]->sample; - for(j = 0; j < n; j++) - if(sp[j].data_alloced) - free(sp[j].data); - free(sp); + if(sp) + { + for(j = 0; j < n; j++) + if(sp[j].data_alloced && sp[j].data) + free(sp[j].data); + free(sp); + } free(special_patch[i]); special_patch[i] = NULL; } diff -ruN TiMidity++-2.8.2/timidity/load_mod.c TiMidity++-2.9.0/timidity/load_mod.c --- TiMidity++-2.8.2/timidity/load_mod.c Mon Feb 7 07:59:30 2000 +++ TiMidity++-2.9.0/timidity/load_mod.c Thu Jan 1 09:00:00 1970 @@ -1,438 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999,2000 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - load_mod.c: Module loader for TiMidity -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include -#ifdef HAVE_UNISTD_H -#include -#endif /* HAVE_UNISTD_H */ - -#ifndef NO_STRING_H -#include -#else -#include -#endif - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "readmidi.h" -#include "tables.h" -#include "mod.h" -#include "output.h" -#include "controls.h" - -typedef struct _mod_sample_info -{ - char name[22]; /* Sample name */ - uint16 len; /* Sample length */ - uint8 finetune; /* 0..7 => 0..7, 8..15 => -8..-1 */ - uint8 volume; /* 0..64 */ - uint16 loop_start; /* Loop point for sample */ - uint16 loop_len; /* Loop length for sample */ -} mod_sample_info; - -#define SETMIDIEVENT(e, at, t, ch, pa, pb) \ - { (e).time = (at); (e).type = (t); \ - (e).channel = (uint8)(ch); (e).a = (uint8)(pa); (e).b = (uint8)(pb); } - -#define MIDIEVENT(at, t, ch, pa, pb) \ - { MidiEvent event; SETMIDIEVENT(event, at, t, ch, pa, pb); \ - readmidi_add_event(&event); } - -static int mod_cnv_pattern(struct timidity_file *tf, int nch, int nptn, - uint8 *poslist, int npos, - mod_sample_info *sinfo); -static int install_mod_instruments(struct timidity_file *tf, - mod_sample_info *sinfo); - -static struct -{ - char *magic; - int ch; -} mod_magics[] = -{ - {"M.K.", 4}, /* Protracker */ - {"M!K!", 4}, /* Protracker */ - {"FLT4", 4}, /* Startracker */ - {"FLT8", 8}, /* Startracker */ - {"4CHN", 4}, /* Fasttracker */ - {"6CHN", 6}, /* Fasttracker */ - {"8CHN", 8}, /* Fasttracker */ - {"CD81", 8}, /* Atari Oktalyzer */ - {"OKTA", 8}, /* Atari Oktalyzer */ - {"16CN", 16},/* Taketracker */ - {"32CN", 32},/* Taketracker */ - {" ", 4}, /* 15-instrument */ - {0, 0} -}; - -int load_mod(struct timidity_file *tf) -{ - char buff[32]; - char songname[20]; - int i; - mod_sample_info sinfo[31]; - int nptn; - uint8 poslist[128]; - int nch; - - /* Song name (Must be end with '\0' */ - tf_read(songname, 1, 20, tf); - songname[19] = '\0'; /* for safty */ - - /* Information for sample */ - if(tf_read(sinfo, sizeof(mod_sample_info), 31, tf) != 31) - return 1; - for(i = 0; i < 31; i++) - { - sinfo[i].finetune &= 0xF; - if(sinfo[i].finetune >= 8) - sinfo[i].finetune -= 16; - if(sinfo[i].volume > 64) - sinfo[i].volume = 64; /* 0..64 */ - sinfo[i].len = 2 * BE_SHORT(sinfo[i].len); - sinfo[i].loop_start = 2 * BE_SHORT(sinfo[i].loop_start); - sinfo[i].loop_len = 2 * BE_SHORT(sinfo[i].loop_len); - } - - /* Song length */ - if(tf_getc(tf) == EOF) - return 1; - - /* I don't know what this is */ - if(tf_getc(tf) == EOF) - return 1; - - /* Song positions */ - if(tf_read(poslist, 1, 128, tf) != 128) - return 1; - - nptn = 0; - for(i = 0; i < 128; i++) - if(nptn < poslist[i]) - nptn = poslist[i]; - nptn++; - - /* magic */ - if(tf_read(buff, 1, 4, tf) != 4) - return 1; - buff[4] = '\0'; - nch = -1; - for(i = 0; mod_magics[i].magic; i++) - if(strncmp(buff, mod_magics[i].magic, 4) == 0) - { - nch = mod_magics[i].ch; - break; - } - if(nch == -1) - return 1; /* Not a MOD file */ - - current_file_info->file_type = IS_MOD_FILE; - if(current_file_info->seq_name == NULL) - current_file_info->seq_name = safe_strdup(songname); - if(mod_cnv_pattern(tf, nch, nptn, poslist, nptn, sinfo)) - return 2; - if(install_mod_instruments(tf, sinfo)) - return 2; - return 0; -} - -static int install_mod_instruments(struct timidity_file *tf, - mod_sample_info *sinfo) -{ - int i, j; - - for(i = 0; i < 31; i++) - { - sample_t *dat; - Sample *sp; - char name[23]; - - if(sinfo[i].len == 0) - continue; - - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - "MOD Sample %d (%.22s):len=%d ls=%d le=%d tune=%d v=%d", - i, sinfo[i].name, - sinfo[i].len, sinfo[i].loop_start, sinfo[i].loop_len, - sinfo[i].finetune, sinfo[i].volume); - - special_patch[i + 1] = - (SpecialPatch *)safe_malloc(sizeof(SpecialPatch)); - special_patch[i + 1]->type = INST_MOD; - special_patch[i + 1]->samples = 1; - special_patch[i + 1]->sample = sp = - (Sample *)safe_malloc(sizeof(Sample)); - memset(sp, 0, sizeof(Sample)); - memcpy(name, sinfo[i].name, 22); - name[22] = '\0'; - code_convert(name, NULL, 23, NULL, "ASCII"); - if(name[0] == '\0') - special_patch[i + 1]->name = NULL; - else - special_patch[i + 1]->name = safe_strdup(name); - special_patch[i + 1]->sample_offset = 0; - -#ifdef LOOKUP_HACK - dat = (sample_t *)safe_malloc(sinfo[i].len); - tf_read(dat, 1, sinfo[i].len, tf); -#else - dat = (sample_t *)safe_malloc(sinfo[i].len * 2); - tf_read(dat, 1, sinfo[i].len, tf); - for(j = sinfo[i].len - 1; j >= 0; j--) - dat[j] = 256 * ((int8 *)dat)[j]; -#endif /* LOOKUP_HACK */ - sp->data = dat; - sp->data_alloced = 1; - sp->data_length = sinfo[i].len; - sp->loop_start = sinfo[i].loop_start; - sp->loop_end = sinfo[i].loop_start + sinfo[i].loop_len; - sp->data_length <<= FRACTION_BITS; - sp->loop_start <<= FRACTION_BITS; - sp->loop_end <<= FRACTION_BITS; - if(sinfo[i].loop_len > 2) - sp->modes = MODES_LOOPING; - - sp->sample_rate = (int32)(NTSC_RATE * 16); - sp->low_freq = 0; - sp->high_freq = 0x7fffffff; - sp->root_freq = freq_table[MOD_BASE_NOTE + 48]; - sp->volume = 1.0; - sp->panning = 64; - sp->low_vel = 0; - sp->high_vel = 127; - } - return 0; -} - -static int mod_cnv_pattern(struct timidity_file *tf, int nch, int nptn, - uint8 *poslist, int npos, - mod_sample_info *sinfo) -{ - MBlockList pool; - uint8 **ptns, *pt; - int32 at, i, j; - int play_speed; - int songpos, ptpos, ptlen; - int v; - double r; - - int jumpflag, jump; - int jumpcnt; - int current_tempo = 125; - - init_mblock(&pool); - ptns = (uint8 **)new_segment(&pool, nptn * sizeof(uint8 *)); - ptlen = 4 * 64 * nch; - for(i = 0; i < nptn; i++) - { - ptns[i] = (uint8 *)new_segment(&pool, ptlen); - if(tf_read(ptns[i], 1, ptlen, tf) != ptlen) - { - reuse_mblock(&pool); - return 1; - } - } - - ModV = (ModVoice *)new_segment(&pool, nch * sizeof(ModVoice)); - - readmidi_set_track(0, 1); - - at = 0; - current_file_info->divisions = 24; - play_speed = 6; - - mod_change_tempo(0, current_tempo); - MIDIEVENT(0, ME_TEMPO, 0x00, 0x07, 0x53); /* 125 BPM */ - for(v = 0; v < nch; v++) - { - ModV[v].sample = 0; - ModV[v].noteon = -1; - ModV[v].period = 0; - ModV[v].tune = 0; - ModV[v].vol = ModV[v].lastvol = 64; - ModV[v].retrig = 0; - ModV[v].start = ModV[v].starttmp = 0; - - MIDIEVENT(0, ME_SET_PATCH, v, 1, 0); - MIDIEVENT(0, ME_PAN, v, (v & 1) ? 127 : 0, 0); - MIDIEVENT(0, ME_MONO, v, 0, 0); - MIDIEVENT(0, ME_RPN_LSB, v, 0, 0); - MIDIEVENT(0, ME_RPN_MSB, v, 0, 0); - MIDIEVENT(0, ME_DATA_ENTRY_MSB, v, MOD_BEND_SENSITIVE, 0); - } - - jumpflag = jump = jumpcnt = 0; - for(songpos = 0; songpos < npos; songpos++) - { - pt = ptns[poslist[songpos]]; - ptpos = 0; - i = 0; - if(jumpflag) - { - if(jumpflag == 0x0d) - i = jump; - else if(jumpflag == 0x0b) - { - songpos = jump; - pt = ptns[poslist[songpos]]; - } - jumpflag = jump = 0; - } - - for(; i < 64; i++) /* 16 q.n. */ - { - jumpflag = 0; - jump = 0; - for(v = 0; v < nch; v++) - { - int sample, period, efx, arg; - - sample = (pt[ptpos] & 0xF0) | (pt[ptpos + 2] >> 4); - period = ((pt[ptpos] & 0x0F) << 8) | pt[ptpos + 1]; - efx = pt[ptpos + 2] & 0x0F; - arg = pt[ptpos + 3]; - - if(sample > 0) - { - sample--; - if(sample > 31 || sinfo[sample].len == 0) - { - if(ModV[v].noteon != -1) - MIDIEVENT(at, ME_NOTEOFF, v, ModV[v].noteon, 0); - ModV[v].noteon = -1; - period = 0; - } - else - { - if(ModV[v].sample != sample) - { - ModV[v].sample = sample; - MIDIEVENT(at, ME_SET_PATCH, - v, ModV[v].sample + 1, 0); - ModV[v].start = 0; - } - ModV[v].vol = sinfo[sample].volume; - } - } - - ModV[v].efx = efx; - ModV[v].arg = arg; - ModV[v].skipon = 0; - switch(efx) - { - case 0x0b: /* Jump */ - if(jumpcnt < 2) - { - if(arg < npos) - { - jumpflag = 0x0b; - jump = arg; - if(arg <= songpos) - jumpcnt++; - songpos--; - } - } - break; - - case 0x0d: /* Break */ - jumpflag = 0x0d; - jump = (arg & 0x0f) + ((arg >> 4) & 0x0f) * 10; - if(jump > 63) - jump = 0; - break; - - case 0x0f: /* speed change */ - if(arg >= 0x20) - { - if(current_tempo != arg) - { - current_tempo = arg; - mod_change_tempo(at, current_tempo); - } - } - else if(arg > 0) - play_speed = arg; - break; - - default: - mod_new_effect(v, period, efx, arg); - break; - } - - if(ModV[v].lastvol != ModV[v].vol) - { - int vol; - ModV[v].lastvol = ModV[v].vol; - vol = ModV[v].vol * 2; - if(vol > 127) - vol = 127; - MIDIEVENT(at, ME_EXPRESSION, v, vol, 0); - } - - if(period && !ModV[v].skipon) - mod_start_note(at, v, period); - - ptpos += 4; - - if(jumpflag) - break; - } - - for(j = 0; j < play_speed - 1; j += 2, at += 2) - for(v = 0; v < nch; v++) - mod_update_effect(at, v, 2); - if(j < play_speed) - { - for(v = 0; v < nch; v++) - mod_update_effect(at, v, 1); - at++; - } - if(jumpflag) - break; - } - } - - r = 0.0; - for(v = 0; v < nch; v++) - if(ModV[v].sample != -1 && ModV[v].noteon != -1) - { - double sec; - - sec = sinfo[ModV[v].sample].len * (1.0 / NTSC_RATE) - * (freq_table[MOD_BASE_NOTE] / freq_table[ModV[v].noteon]); - if(r < sec) - r = sec; - } - i = (int32)(r * (48 / (60.0/125.0))); - at += i; - for(v = 0; v < nch; v++) - MIDIEVENT(at, ME_ALL_NOTES_OFF, v, 0, 0); - reuse_mblock(&pool); - return 0; -} diff -ruN TiMidity++-2.8.2/timidity/mod.c TiMidity++-2.9.0/timidity/mod.c --- TiMidity++-2.8.2/timidity/mod.c Mon Feb 7 07:58:20 2000 +++ TiMidity++-2.9.0/timidity/mod.c Sat Feb 19 20:58:35 2000 @@ -1,32 +1,41 @@ /* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999,2000 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. + TiMidity++ -- MIDI to WAVE converter and player + Copyright (C) 1999,2000 Masanao Izumo + Copyright (C) 1995 Tuukka Toivonen + + Most of this file is taken from the MikMod sound library, which is + (c) 1998, 1999 Miodrag Vallat and others - see file libunimod/AUTHORS + for complete list. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + */ + +/* Interface to libunimod + module player */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ -/* - * This is beta version of module player for TiMidity - */ #include +#include +#include + +#ifdef SUNOS +extern long int random (void); +#endif #ifndef NO_STRING_H #include @@ -43,277 +52,2950 @@ #include "mod.h" #include "output.h" #include "controls.h" +#include "unimod.h" +#include "mod2midi.h" + +static BOOL mod_do_play (MODULE *); + +int +load_module_file (struct timidity_file *tf, int mod_type) +{ + MODULE *mf; + +#ifdef LOOKUP_HACK + ML_8bitsamples = 1; +#else + ML_8bitsamples = 0; +#endif + ML_monosamples = 1; + + mf = ML_Load (tf->url, MOD_NUM_VOICES, 0); + if (ML_errno) + return 1; + + current_file_info->file_type = mod_type; + load_module_samples (mf->samples, mf->numsmp); + mod_do_play (mf); + ML_Free (mf); + return 0; +} + -#define SETMIDIEVENT(e, at, t, ch, pa, pb) \ - { (e).time = (at); (e).type = (t); \ - (e).channel = (uint8)(ch); (e).a = (uint8)(pa); (e).b = (uint8)(pb); } +int +get_module_type (char *fn) +{ + if (check_file_extension (fn, ".xm", 1) /* Most common first */ + || check_file_extension (fn, ".s3m", 1) + || check_file_extension (fn, ".mod", 1) + || check_file_extension (fn, ".it", 1) + || check_file_extension (fn, ".669", 1) /* Then the others in alphabetic order */ + || check_file_extension (fn, ".amf", 1) + || check_file_extension (fn, ".dsm", 1) + || check_file_extension (fn, ".far", 1) + || check_file_extension (fn, ".gdm", 1) + || check_file_extension (fn, ".imf", 1) + || check_file_extension (fn, ".med", 1) + || check_file_extension (fn, ".mtm", 1) + || check_file_extension (fn, ".stm", 1) + || check_file_extension (fn, ".stx", 1) + || check_file_extension (fn, ".ult", 1) + || check_file_extension (fn, ".uni", 1)) + + return IS_MOD_FILE; + + return IS_OTHER_FILE; +} -#define MIDIEVENT(at, t, ch, pa, pb) \ - { MidiEvent event; SETMIDIEVENT(event, at, t, ch, pa, pb); \ - readmidi_add_event(&event); } +char * +get_module_title (struct timidity_file *tf, int mod_type) +{ + return ML_LoadTitle (tf->url); +} -ModVoice *ModV; -extern int load_mod(struct timidity_file *tf); +/*========== Playing */ -static struct +#define POS_NONE (-2) /* no loop position defined */ + +typedef struct ENVPR { - int (* loader)(struct timidity_file *tf); - int type; -} mod_loaders[] = + UBYTE flg; /* envelope flag */ + UBYTE pts; /* number of envelope points */ + UBYTE susbeg; /* envelope sustain index begin */ + UBYTE susend; /* envelope sustain index end */ + UBYTE beg; /* envelope loop begin */ + UBYTE end; /* envelope loop end */ + SWORD p; /* current envelope counter */ + UWORD a; /* envelope index a */ + UWORD b; /* envelope index b */ + ENVPT *env; /* envelope points */ +} +ENVPR; + +typedef struct MP_CONTROL + { + INSTRUMENT *i; + SAMPLE *s; + UBYTE sample; /* which sample number */ + UBYTE note; /* the audible note as heard, direct rep of period */ + SWORD outvolume; /* output volume (vol + sampcol + instvol) */ + SBYTE chanvol; /* channel's "global" volume */ + UWORD fadevol; /* fading volume rate */ + SWORD panning; /* panning position */ + UBYTE kick; /* if true = sample has to be restarted */ + UWORD period; /* period to play the sample at */ + UBYTE nna; /* New note action type + master/slave flags */ + + UBYTE volflg; /* volume envelope settings */ + UBYTE panflg; /* panning envelope settings */ + UBYTE pitflg; /* pitch envelope settings */ + + UBYTE keyoff; /* if true = fade out and stuff */ + SWORD *data; /* which sample-data to play */ + UBYTE notedelay; /* (used for note delay) */ + SLONG start; /* The starting byte index in the sample */ + + UWORD ultoffset; /* fine sample offset memory */ + + struct MP_VOICE *slave; /* Audio Slave of current effects control channel */ + UBYTE slavechn; /* Audio Slave of current effects control channel */ + UBYTE anote; /* the note that indexes the audible */ + UBYTE oldnote; + SWORD ownper; + SWORD ownvol; + UBYTE dca; /* duplicate check action */ + UBYTE dct; /* duplicate check type */ + UBYTE *row; /* row currently playing on this channel */ + SBYTE retrig; /* retrig value (0 means don't retrig) */ + ULONG speed; /* what finetune to use */ + SWORD volume; /* amiga volume (0 t/m 64) to play the sample at */ + + SWORD tmpvolume; /* tmp volume */ + UWORD tmpperiod; /* tmp period */ + UWORD wantedperiod; /* period to slide to (with effect 3 or 5) */ + + UBYTE arpmem; /* arpeggio command memory */ + UBYTE pansspd; /* panslide speed */ + UWORD slidespeed; /* */ + UWORD portspeed; /* noteslide speed (toneportamento) */ + + UBYTE s3mtremor; /* s3m tremor (effect I) counter */ + UBYTE s3mtronof; /* s3m tremor ontime/offtime */ + UBYTE s3mvolslide; /* last used volslide */ + SBYTE sliding; + UBYTE s3mrtgspeed; /* last used retrig speed */ + UBYTE s3mrtgslide; /* last used retrig slide */ + + UBYTE glissando; /* glissando (0 means off) */ + UBYTE wavecontrol; + + SBYTE vibpos; /* current vibrato position */ + UBYTE vibspd; /* "" speed */ + UBYTE vibdepth; /* "" depth */ + + SBYTE trmpos; /* current tremolo position */ + UBYTE trmspd; /* "" speed */ + UBYTE trmdepth; /* "" depth */ + + UBYTE fslideupspd; + UBYTE fslidednspd; + UBYTE fportupspd; /* fx E1 (extra fine portamento up) data */ + UBYTE fportdnspd; /* fx E2 (extra fine portamento dn) data */ + UBYTE ffportupspd; /* fx X1 (extra fine portamento up) data */ + UBYTE ffportdnspd; /* fx X2 (extra fine portamento dn) data */ + + ULONG hioffset; /* last used high order of sample offset */ + UWORD soffset; /* last used low order of sample-offset (effect 9) */ + + UBYTE sseffect; /* last used Sxx effect */ + UBYTE ssdata; /* last used Sxx data info */ + UBYTE chanvolslide; /* last used channel volume slide */ + + UBYTE panbwave; /* current panbrello waveform */ + UBYTE panbpos; /* current panbrello position */ + SBYTE panbspd; /* "" speed */ + UBYTE panbdepth; /* "" depth */ + + UWORD newsamp; /* set to 1 upon a sample / inst change */ + UBYTE voleffect; /* Volume Column Effect Memory as used by IT */ + UBYTE voldata; /* Volume Column Data Memory */ + + SWORD pat_reppos; /* patternloop position */ + UWORD pat_repcnt; /* times to loop */ + } +MP_CONTROL; + +/* Used by NNA only player (audio control. MP_CONTROL is used for full effects + control). */ +typedef struct MP_VOICE + { + INSTRUMENT *i; + SAMPLE *s; + UBYTE sample; /* which instrument number */ + + SWORD volume; /* output volume (vol + sampcol + instvol) */ + SWORD panning; /* panning position */ + SBYTE chanvol; /* channel's "global" volume */ + UWORD fadevol; /* fading volume rate */ + UWORD period; /* period to play the sample at */ + + UBYTE volflg; /* volume envelope settings */ + UBYTE panflg; /* panning envelope settings */ + UBYTE pitflg; /* pitch envelope settings */ + + UBYTE keyoff; /* if true = fade out and stuff */ + UBYTE kick; /* if true = sample has to be restarted */ + UBYTE note; /* the audible note (as heard, direct rep of period) */ + UBYTE nna; /* New note action type + master/slave flags */ + SWORD *data; /* which sample-data to play */ + SLONG start; /* The start byte index in the sample */ + +/* Below here is info NOT in MP_CONTROL!! */ + ENVPR venv; + ENVPR penv; + ENVPR cenv; + + UWORD avibpos; /* autovibrato pos */ + UWORD aswppos; /* autovibrato sweep pos */ + + ULONG totalvol; /* total volume of channel (before global mixings) */ + + BOOL mflag; + SWORD masterchn; + UWORD masterperiod; + + MP_CONTROL *master; /* index of "master" effects channel */ + } +MP_VOICE; + +typedef struct MP_STATUS + { + SWORD channel; /* channel we're working on */ + UWORD oldsngspd; /* old song speed */ + UWORD sngspd; /* current song speed */ + SWORD volume; /* song volume (0-128) (or user volume) */ + UWORD bpm; /* current beats-per-minute speed */ + UWORD newbpm; /* next beats-per-minute speed */ + + UBYTE realchn; /* real number of channels used */ + UBYTE totalchn; /* total number of channels used (incl NNAs) */ + + UWORD patpos; /* current row number */ + SWORD sngpos; /* current song position */ + + UWORD numrow; /* number of rows on current pattern */ + UWORD vbtick; /* tick counter (counts from 0 to sngspd) */ + + struct MP_CONTROL *control; /* Effects Channel info (size pf->numchn) */ + struct MP_VOICE voice[MOD_NUM_VOICES]; /* Audio Voice information */ + + UBYTE globalslide; /* global volume slide rate */ + UBYTE pat_repcrazy; /* module has just looped to position -1 */ + UWORD patbrk; /* position where to start a new pattern */ + UBYTE patdly; /* patterndelay counter (command memory) */ + UBYTE patdly2; /* patterndelay counter (real one) */ + SWORD posjmp; /* flag to indicate a jump is needed... */ + int explicitslides; + } +MP_STATUS; + +MODULE *pf = NULL; /* modfile being played */ +static MP_CONTROL *a; /* current AUDTMP we're working on */ +static MP_STATUS mp; /* player status */ + +static UBYTE VibratoTable[32] = { - {load_mod, IS_MOD_FILE}, - {NULL, IS_OTHER_FILE} + 0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253, + 255, 253, 250, 244, 235, 224, 212, 197, 180, 161, 141, 120, 97, 74, 49, 24 }; -static int period_table[60] = +static UBYTE avibtab[128] = { -/* C C# D D# E F F# G G# A A# B */ -/* 0 */ 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906, -/* 1 */ 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, -/* 2 */ 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, -/* 3 */ 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, -/* 4 */ 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56 + 0, 1, 3, 4, 6, 7, 9, 10, 12, 14, 15, 17, 18, 20, 21, 23, + 24, 25, 27, 28, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 42, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 54, 55, 56, 57, 57, 58, + 59, 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, + 64, 63, 63, 63, 63, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, 59, + 59, 58, 57, 57, 56, 55, 54, 54, 53, 52, 51, 50, 49, 48, 47, 46, + 45, 44, 42, 41, 40, 39, 38, 36, 35, 34, 32, 31, 30, 28, 27, 25, + 24, 23, 21, 20, 18, 17, 15, 14, 12, 10, 9, 7, 6, 4, 3, 1 }; -int load_module_file(struct timidity_file *tf, int mod_type) +static SBYTE PanbrelloTable[256] = { - int i, err; + 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23, + 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, + 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, + 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, + 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26, + 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2, + 0, -2, -3, -5, -6, -8, -9, -11, -12, -14, -16, -17, -19, -20, -22, -23, + -24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44, + -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59, + -59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60, + -59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, + -45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26, + -24, -23, -22, -20, -19, -17, -16, -14, -12, -11, -9, -8, -6, -5, -3, -2 +}; - for(i = 0; mod_loaders[i].loader; i++) - if(mod_type == mod_loaders[i].type) - { - err = mod_loaders[i].loader(tf); - if(err == 1) - { - url_rewind(tf->url); - if(tf_getc(tf) == 0) - { - skip(tf, 127); - err = mod_loaders[i].loader(tf); - } - } - return err; - } - return 1; +/* returns a random value between 0 and ceil-1, ceil must be a power of two */ +static int +getrandom (int ceil) +{ +#ifdef HAVE_SRANDOM + return random () & (ceil - 1); +#else + return (rand () * ceil) / (RAND_MAX + 1.0); +#endif } +/* New Note Action Scoring System : + -------------------------------- + 1) total-volume (fadevol, chanvol, volume) is the main scorer. + 2) a looping sample is a bonus x2 + 3) a foreground channel is a bonus x4 + 4) an active envelope with keyoff is a handicap -x2 */ +static int +MP_FindEmptyChannel (void) +{ + MP_VOICE *a; + ULONG t, k, tvol, pp; + + for (t = 0; t < MOD_NUM_VOICES; t++) + if (((mp.voice[t].kick == KICK_ABSENT) || (mp.voice[t].kick == KICK_ENV)) && + Voice_Stopped (t)) + return t; + + tvol = 0xffffffUL; + t = 0; + a = mp.voice; + for (k = 0; k < MOD_NUM_VOICES; k++, a++) + if ((a->kick == KICK_ABSENT) || (a->kick == KICK_ENV)) + { + pp = a->totalvol << ((a->s->flags & SF_LOOP) ? 1 : 0); + if ((a->master) && (a == a->master->slave)) + pp <<= 2; + + if (pp < tvol) + { + tvol = pp; + t = k; + } + } + + if (tvol > 8000 * 7) + return -1; + return t; +} -int get_module_type(char *fn) +static UWORD GetPeriod (UWORD note, ULONG speed) { - char *p; + if (pf->flags & UF_XMPERIODS) + return (pf->flags & UF_LINEAR) ? getlinearperiod (note, speed) : getlogperiod (note, speed); - if(check_file_extension(fn, ".mod", 1)) - return IS_MOD_FILE; + return getoldperiod (note, speed); +} + + +static SWORD +Interpolate (SWORD p, SWORD p1, SWORD p2, SWORD v1, SWORD v2) +{ + if ((p1 == p2) || (p == p1)) + return v1; + return v1 + ((SLONG) ((p - p1) * (v2 - v1)) / (p2 - p1)); +} - if((p = strchr(fn, '#')) != NULL) - p++; - else - p = fn; - if(strncmp(p, "mod.", 4) == 0 || strncmp(p, "MOD.", 4) == 0) - return IS_MOD_FILE; - return IS_OTHER_FILE; +static SWORD +InterpolateEnv (SWORD p, ENVPT * a, ENVPT * b) +{ + return (Interpolate (p, a->pos, b->pos, a->val, b->val)); } -void mod_change_tempo(int32 at, int bpm) +static SWORD +DoPan (SWORD envpan, SWORD pan) { - int32 tempo; - int c, a, b; + int newpan; - tempo = 60000000/bpm; - c = (tempo & 0xff); - a = ((tempo >> 8) & 0xff); - b = ((tempo >> 16) & 0xff); - MIDIEVENT(at, ME_TEMPO, c, b, a); + newpan = pan + (((envpan - PAN_CENTER) * (128 - abs (pan - PAN_CENTER))) / 128); + + return (newpan < PAN_LEFT) ? PAN_LEFT : (newpan > PAN_RIGHT ? PAN_RIGHT : newpan); } -static int mod_vol_slide(int vol, int slide) +static void +StartEnvelope (ENVPR * t, UBYTE flg, UBYTE pts, UBYTE susbeg, UBYTE susend, UBYTE beg, UBYTE end, ENVPT * p, UBYTE keyoff) { - vol += slide >> 4; - vol -= slide & 0x0f; - if(vol < 0) - return 0; - if(vol > 64) - return 64; - return vol; + t->flg = flg; + t->pts = pts; + t->susbeg = susbeg; + t->susend = susend; + t->beg = beg; + t->end = end; + t->env = p; + t->p = 0; + t->a = 0; + t->b = ((t->flg & EF_SUSTAIN) && (!(keyoff & KEY_OFF))) ? 0 : 1; + + /* Imago Orpheus sometimes stores an extra initial point in the envelope */ + if ((t->pts >= 2) && (t->env[0].pos == t->env[1].pos)) + { + t->a++; + t->b++; + } + + if (t->b >= t->pts) + t->b = t->pts - 1; } -void mod_new_effect(int v, int period, int efx, int arg) +/* This procedure processes all envelope types, include volume, pitch, and + panning. Envelopes are defined by a set of points, each with a magnitude + [relating either to volume, panning position, or pitch modifier] and a tick + position. + + Envelopes work in the following manner: + + (a) Each tick the envelope is moved a point further in its progression. For + an accurate progression, magnitudes between two envelope points are + interpolated. + + (b) When progression reaches a defined point on the envelope, values are + shifted to interpolate between this point and the next, and checks for + loops or envelope end are done. + + Misc: + Sustain loops are loops that are only active as long as the keyoff flag is + clear. When a volume envelope terminates, so does the current fadeout. */ +static SWORD +ProcessEnvelope (ENVPR * t, SWORD v, UBYTE keyoff) { - switch(efx) + if (t->flg & EF_ON) { - case MOD_EFX_PORTAMENT: - if(ModV[v].noteon == -1) + UBYTE a, b; /* actual points in the envelope */ + UWORD p; /* the 'tick counter' - real point being played */ + + a = t->a; + b = t->b; + p = t->p; + + /* if sustain loop on one point (XM type), don't move and don't + interpolate when the point is reached */ + if ((t->flg & EF_SUSTAIN) && (t->susbeg == t->susend) && + (!(keyoff & KEY_OFF)) && (p == t->env[t->susbeg].pos)) + v = t->env[t->susbeg].val; + else { - ModV[v].efx = 0; - break; + /* compute the current envelope value between points a and b */ + if (a == b) + v = t->env[a].val; + else + v = InterpolateEnv (p, &t->env[a], &t->env[b]); + + p++; + /* pointer reached point b? */ + if (p >= t->env[b].pos) + { + a = b++; /* shift points a and b */ + + /* Check for loops, sustain loops, or end of envelope. */ + if ((t->flg & EF_SUSTAIN) && (!(keyoff & KEY_OFF)) && (b > t->susend)) + { + a = t->susbeg; + b = (t->susbeg == t->susend) ? a : a + 1; + p = t->env[a].pos; + } + else if ((t->flg & EF_LOOP) && (b > t->end)) + { + a = t->beg; + b = (t->beg == t->end) ? a : a + 1; + p = t->env[a].pos; + } + else + { + if (b >= t->pts) + { + if ((t->flg & EF_VOLENV) && (mp.channel != -1)) + { + mp.voice[mp.channel].keyoff |= KEY_FADE; + if (!v) + mp.voice[mp.channel].fadevol = 0; + } + b--; + p--; + } + } + } + t->a = a; + t->b = b; + t->p = p; } - if(arg) - ModV[v].period_step = arg; - if(period) - ModV[v].period_todo = period; - ModV[v].skipon = 1; - break; + } + return v; +} - case MOD_EFX_SAMPOFFS: - ModV[v].starttmp = arg * 256; - break; +/*========== Protracker effects */ - case MOD_EFX_VOLSLIDE: - ModV[v].vol = mod_vol_slide(ModV[v].vol, arg); - break; +static void +DoEEffects (UBYTE dat) +{ + UBYTE nib = dat & 0xf; - case MOD_EFX_VOLCHNG: - arg &= 0x3f; - ModV[v].vol = arg; + switch (dat >> 4) + { + case 0x0: /* hardware filter toggle, not supported */ + break; + case 0x1: /* fineslide up */ + if (a->period) + if (!mp.vbtick) + a->tmpperiod -= (nib << 2); + break; + case 0x2: /* fineslide dn */ + if (a->period) + if (!mp.vbtick) + a->tmpperiod += (nib << 2); + break; + case 0x3: /* glissando ctrl */ + a->glissando = nib; + break; + case 0x4: /* set vibrato waveform */ + a->wavecontrol &= 0xf0; + a->wavecontrol |= nib; + break; + case 0x5: /* set finetune */ + if (a->period) + { + if (pf->flags & UF_XMPERIODS) + a->speed = nib + 128; + else + a->speed = finetune[nib]; + a->tmpperiod = GetPeriod ((UWORD) a->note << 1, a->speed); + } + break; + case 0x6: /* set patternloop */ + if (mp.vbtick) break; + if (nib) + { /* set reppos or repcnt ? */ + /* set repcnt, so check if repcnt already is set, which means we + are already looping */ + if (a->pat_repcnt) + a->pat_repcnt--; /* already looping, decrease counter */ + else + { +#if 0 + /* this would make walker.xm, shipped with Xsoundtracker, + play correctly, but it's better to remain compatible + with FT2 */ + if ((!(pf->flags & UF_NOWRAP)) || (a->pat_reppos != POS_NONE)) +#endif + a->pat_repcnt = nib; /* not yet looping, so set repcnt */ + } - default: - if(efx) + if (a->pat_repcnt) + { /* jump to reppos if repcnt>0 */ + if (a->pat_reppos == POS_NONE) + a->pat_reppos = mp.patpos - 1; + if (a->pat_reppos == -1) + { + mp.pat_repcrazy = 1; + mp.patpos = 0; + } + else + mp.patpos = a->pat_reppos; + } + else + a->pat_reppos = POS_NONE; + } + else + a->pat_reppos = mp.patpos - 1; /* set reppos - can be (-1) */ + break; + case 0x7: /* set tremolo waveform */ + a->wavecontrol &= 0x0f; + a->wavecontrol |= nib << 4; + break; + case 0x8: /* set panning */ + if (nib <= 8) + nib <<= 4; + else + nib *= 17; + a->panning = pf->panning[mp.channel] = nib; + break; + case 0x9: /* retrig note */ + /* only retrigger if data nibble > 0 */ + if (nib) { - ctl->cmsg(CMSG_WARNING, VERB_DEBUG, - "Effect V%d 0x%02x 0x%02x period=%d (Ignored)", - v, efx, arg, period); + if (!a->retrig) + { + /* when retrig counter reaches 0, reset counter and restart + the sample */ + if (a->period) + a->kick = KICK_NOTE; + a->retrig = nib; + } + a->retrig--; /* countdown */ } + break; + case 0xa: /* fine volume slide up */ + if (mp.vbtick) break; + a->tmpvolume += nib; + if (a->tmpvolume > 64) + a->tmpvolume = 64; + break; + case 0xb: /* fine volume slide dn */ + if (mp.vbtick) + break; + a->tmpvolume -= nib; + if (a->tmpvolume < 0) + a->tmpvolume = 0; + break; + case 0xc: /* cut note */ + /* When mp.vbtick reaches the cut-note value, turn the volume to + zero ( Just like on the amiga) */ + if (mp.vbtick >= nib) + a->tmpvolume = 0; /* just turn the volume down */ + break; + case 0xd: /* note delay */ + /* delay the start of the sample until mp.vbtick==nib */ + if (!mp.vbtick) + a->notedelay = nib; + else if (a->notedelay) + a->notedelay--; + break; + case 0xe: /* pattern delay */ + if (mp.vbtick) + break; + if (!mp.patdly2) + mp.patdly = nib + 1; /* only once, when vbtick=0 */ + break; + case 0xf: /* invert loop, not supported */ + break; + } +} + +static void +DoVibrato (void) +{ + UBYTE q; + UWORD temp = 0; + + q = (a->vibpos >> 2) & 0x1f; + + switch (a->wavecontrol & 3) + { + case 0: /* sine */ + temp = VibratoTable[q]; + break; + case 1: /* ramp down */ + q <<= 3; + if (a->vibpos < 0) + q = 255 - q; + temp = q; + break; + case 2: /* square wave */ + temp = 255; + break; + case 3: /* random wave */ + temp = getrandom (256); + break; + } + + temp *= a->vibdepth; + temp >>= 7; + temp <<= 2; + + if (a->vibpos >= 0) + a->period = a->tmpperiod + temp; + else + a->period = a->tmpperiod - temp; + + if (mp.vbtick) + a->vibpos += a->vibspd; +} + +static void +DoTremolo (void) +{ + UBYTE q; + UWORD temp = 0; + + q = (a->trmpos >> 2) & 0x1f; + + switch ((a->wavecontrol >> 4) & 3) + { + case 0: /* sine */ + temp = VibratoTable[q]; + break; + case 1: /* ramp down */ + q <<= 3; + if (a->trmpos < 0) + q = 255 - q; + temp = q; + break; + case 2: /* square wave */ + temp = 255; + break; + case 3: /* random wave */ + temp = getrandom (256); + break; + } + temp *= a->trmdepth; + temp >>= 6; + + if (a->trmpos >= 0) + { + a->volume = a->tmpvolume + temp; + if (a->volume > 64) + a->volume = 64; + } + else + { + a->volume = a->tmpvolume - temp; + if (a->volume < 0) + a->volume = 0; } + + if (mp.vbtick) + a->trmpos += a->trmspd; } -void mod_update_effect(int32 at, int v, int mul) +static void +DoVolSlide (UBYTE dat) { - int i; + if (!mp.vbtick) + return; - switch(ModV[v].efx) + if (dat & 0xf) { - case MOD_EFX_PORTAMENT: - if(ModV[v].period > ModV[v].period_todo) + a->tmpvolume -= (dat & 0x0f); + if (a->tmpvolume < 0) + a->tmpvolume = 0; + } + else + { + a->tmpvolume += (dat >> 4); + if (a->tmpvolume > 64) + a->tmpvolume = 64; + } +} + +static void +DoToneSlide (void) +{ + if (mp.vbtick) + { + int dist; + + /* We have to slide a->period towards a->wantedperiod, so compute the + difference between those two values */ + dist = a->period - a->wantedperiod; + + /* if they are equal or if portamentospeed is too big ... */ + if ((!dist) || a->portspeed > abs (dist)) + /* ...make tmpperiod equal tperiod */ + a->tmpperiod = a->period = a->wantedperiod; + else if (dist > 0) { - i = ModV[v].period - ModV[v].period_step * mul; - if(i < ModV[v].period_todo) - i = ModV[v].period_todo; - mod_period_move(at, v, i); + a->tmpperiod -= a->portspeed; + a->period -= a->portspeed; /* dist>0, slide up */ } - else if(ModV[v].period < ModV[v].period_todo) + else { - i = ModV[v].period + ModV[v].period_step * mul; - if(i > ModV[v].period_todo) - i = ModV[v].period_todo; - mod_period_move(at, v, i); + a->tmpperiod += a->portspeed; + a->period += a->portspeed; /* dist<0, slide down */ } - break; + } + else + a->tmpperiod = a->period; +} + +static void +DoArpeggio (UBYTE dat) +{ + UBYTE note = a->note; - case MOD_EFX_VOLSLIDE: - for(i = 0; i < mul; i++) - ModV[v].vol = mod_vol_slide(ModV[v].vol, ModV[v].arg); - if(ModV[v].lastvol != ModV[v].vol) + if (dat) + { + switch (mp.vbtick % 3) { - int vol; - ModV[v].lastvol = ModV[v].vol; - vol = ModV[v].vol * 2; - if(vol > 127) - vol = 127; - MIDIEVENT(at, ME_EXPRESSION, v, vol, 0); + case 1: + note += (dat >> 4); + break; + case 2: + note += (dat & 0xf); + break; } - break; + a->period = GetPeriod ((UWORD) note << 1, a->speed); + a->ownper = 1; + } +} + +/*========== Scream Tracker effects */ + +static void +DoS3MVolSlide (UBYTE inf) +{ + UBYTE lo, hi; + + mp.explicitslides = 1; + + if (inf) + a->s3mvolslide = inf; + else + inf = a->s3mvolslide; + + lo = inf & 0xf; + hi = inf >> 4; + + if (!lo) + { + if ((mp.vbtick) || (pf->flags & UF_S3MSLIDES)) + a->tmpvolume += hi; + } + else if (!hi) + { + if ((mp.vbtick) || (pf->flags & UF_S3MSLIDES)) + a->tmpvolume -= lo; + } + else if (lo == 0xf) + { + if (!mp.vbtick) + a->tmpvolume += (hi ? hi : 0xf); + } + else if (hi == 0xf) + { + if (!mp.vbtick) + a->tmpvolume -= (lo ? lo : 0xf); + } + else + return; + + if (a->tmpvolume < 0) + a->tmpvolume = 0; + else if (a->tmpvolume > 64) + a->tmpvolume = 64; +} + +static void +DoS3MSlideDn (UBYTE inf) +{ + UBYTE hi, lo; + + if (inf) + a->slidespeed = inf; + else + inf = a->slidespeed; + + hi = inf >> 4; + lo = inf & 0xf; + + if (hi == 0xf) + { + if (!mp.vbtick) + a->tmpperiod += (UWORD) lo << 2; + } + else if (hi == 0xe) + { + if (!mp.vbtick) + a->tmpperiod += lo; + } + else + { + if (mp.vbtick) + a->tmpperiod += (UWORD) inf << 2; } } -void mod_pitchbend(int at, int v, int tune) +static void +DoS3MSlideUp (UBYTE inf) { - int bend; + UBYTE hi, lo; - if(ModV[v].tune != tune) + if (inf) + a->slidespeed = inf; + else + inf = a->slidespeed; + + hi = inf >> 4; + lo = inf & 0xf; + + if (hi == 0xf) + { + if (!mp.vbtick) + a->tmpperiod -= (UWORD) lo << 2; + } + else if (hi == 0xe) { - ModV[v].tune = tune; - bend = tune * (8192 / 256) / MOD_BEND_SENSITIVE + 8192; - if(bend <= 0) - bend = 1; - else if(bend >= 2 * 8192) - bend = 2 * 8192 - 1; - MIDIEVENT(at, ME_PITCHWHEEL, v, bend & 0x7F, (bend >> 7) & 0x7F); + if (!mp.vbtick) + a->tmpperiod -= lo; + } + else + { + if (mp.vbtick) + a->tmpperiod -= (UWORD) inf << 2; } } -void mod_start_note(int32 at, int v, int period) +static void +DoS3MTremor (UBYTE inf) { - int tune; + UBYTE on, off; + + if (inf) + a->s3mtronof = inf; + else + { + inf = a->s3mtronof; + if (!inf) + return; + } + + if (!mp.vbtick) + return; + + on = (inf >> 4) + 1; + off = (inf & 0xf) + 1; + a->s3mtremor %= (on + off); + a->volume = (a->s3mtremor < on) ? a->tmpvolume : 0; + a->s3mtremor++; +} - if(ModV[v].noteon != -1) +static void +DoS3MRetrig (UBYTE inf) +{ + if (inf) { - MIDIEVENT(at, ME_NOTEOFF, v, ModV[v].noteon, 0); + a->s3mrtgslide = inf >> 4; + a->s3mrtgspeed = inf & 0xf; } - if(ModV[v].start != ModV[v].starttmp) + /* only retrigger if low nibble > 0 */ + if (a->s3mrtgspeed > 0) { - int a, b; - ModV[v].start = ModV[v].starttmp; - a = (ModV[v].start & 0xff); - b = ((ModV[v].start >> 8) & 0xff); - MIDIEVENT(at, ME_PATCH_OFFS, - ModV[v].sample + 1, a, b); + if (!a->retrig) + { + /* when retrig counter reaches 0, reset counter and restart the + sample */ + if (a->kick != KICK_NOTE) + a->kick = KICK_KEYOFF; + a->retrig = a->s3mrtgspeed; + + if ((mp.vbtick) || (pf->flags & UF_S3MSLIDES)) + { + switch (a->s3mrtgslide) + { + case 1: + case 2: + case 3: + case 4: + case 5: + a->tmpvolume -= (1 << (a->s3mrtgslide - 1)); + break; + case 6: + a->tmpvolume = (2 * a->tmpvolume) / 3; + break; + case 7: + a->tmpvolume >>= 1; + break; + case 9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + a->tmpvolume += (1 << (a->s3mrtgslide - 9)); + break; + case 0xe: + a->tmpvolume = (3 * a->tmpvolume) >> 1; + break; + case 0xf: + a->tmpvolume = a->tmpvolume << 1; + break; + } + if (a->tmpvolume < 0) + a->tmpvolume = 0; + else if (a->tmpvolume > 64) + a->tmpvolume = 64; + } + } + a->retrig--; /* countdown */ } +} + +static void +DoS3MSpeed (UBYTE speed) +{ + if (mp.vbtick || mp.patdly2) + return; - ModV[v].noteon = period2note(period, &tune); - if(ModV[v].noteon >= 0) + if (speed > 128) + speed -= 128; + if (speed) { - MIDIEVENT(at, ME_NOTEON, v, ModV[v].noteon, 0x7f); - ModV[v].period = period; - ModV[v].period_start = period; + mp.sngspd = speed; + mp.vbtick = 0; } - ModV[v].tuneon = tune; - mod_pitchbend(at, v, tune); } -void mod_period_move(int32 at, int v, int newperiod) +static void +DoS3MTempo (UBYTE tempo) { - int note, tune, diff; + if (mp.vbtick || mp.patdly2) + return; - diff = newperiod - ModV[v].period; - if(diff == 0 || ModV[v].noteon == -1) - return; - ModV[v].period = newperiod; - note = period2note(ModV[v].period, &tune); - tune = (note * 256 + tune) - - (ModV[v].noteon * 256 + ModV[v].tuneon); - mod_pitchbend(at, v, tune); + mp.newbpm = (tempo < 32) ? 32 : tempo; } -int period2note(int period, int *finetune) +static void +DoS3MFineVibrato (void) { - int note; - int l, r, m; + UBYTE q; + UWORD temp = 0; - if(period < 56 || period > 1712) - return -1; + q = (a->vibpos >> 2) & 0x1f; - /* bin search */ - l = 0; - r = 60; - while(l < r) + switch (a->wavecontrol & 3) { - m = (l + r) / 2; - if(period_table[m] >= period) - l = m + 1; - else - r = m; + case 0: /* sine */ + temp = VibratoTable[q]; + break; + case 1: /* ramp down */ + q <<= 3; + if (a->vibpos < 0) + q = 255 - q; + temp = q; + break; + case 2: /* square wave */ + temp = 255; + break; + case 3: /* random */ + temp = getrandom (256); + break; + } + + temp *= a->vibdepth; + temp >>= 8; + + if (a->vibpos >= 0) + a->period = a->tmpperiod + temp; + else + a->period = a->tmpperiod - temp; + + a->vibpos += a->vibspd; +} + +static void +DoS3MTremolo (void) +{ + UBYTE q; + UWORD temp = 0; + + q = (a->trmpos >> 2) & 0x1f; + + switch ((a->wavecontrol >> 4) & 3) + { + case 0: /* sine */ + temp = VibratoTable[q]; + break; + case 1: /* ramp down */ + q <<= 3; + if (a->trmpos < 0) + q = 255 - q; + temp = q; + break; + case 2: /* square wave */ + temp = 255; + break; + case 3: /* random */ + temp = getrandom (256); + break; + } + + temp *= a->trmdepth; + temp >>= 7; + + if (a->trmpos >= 0) + { + a->volume = a->tmpvolume + temp; + if (a->volume > 64) + a->volume = 64; + } + else + { + a->volume = a->tmpvolume - temp; + if (a->volume < 0) + a->volume = 0; + } + + if (mp.vbtick) + a->trmpos += a->trmspd; +} + +/*========== Fast Tracker effects */ + +static void +DoXMVolSlide (UBYTE inf) +{ + UBYTE lo, hi; + + mp.explicitslides = 2; + + if (inf) + a->s3mvolslide = inf; + else + inf = a->s3mvolslide; + + if (!mp.vbtick) + return; + + lo = inf & 0xf; + hi = inf >> 4; + + if (!hi) + { + a->tmpvolume -= lo; + if (a->tmpvolume < 0) + a->tmpvolume = 0; + } + else + { + a->tmpvolume += hi; + if (a->tmpvolume > 64) + a->tmpvolume = 64; + } +} + +static void +DoXMGlobalSlide (UBYTE inf) +{ + if (mp.vbtick) + { + if (inf) + mp.globalslide = inf; + else + inf = mp.globalslide; + if (inf & 0xf0) + inf &= 0xf0; + mp.volume = mp.volume + ((inf >> 4) - (inf & 0xf)) * 2; + + if (mp.volume < 0) + mp.volume = 0; + else if (mp.volume > 128) + mp.volume = 128; + } +} + +static void +DoXMPanSlide (UBYTE inf) +{ + UBYTE lo, hi; + SWORD pan; + + if (inf) + a->pansspd = inf; + else + inf = a->pansspd; + + if (!mp.vbtick) + return; + + lo = inf & 0xf; + hi = inf >> 4; + + /* slide right has absolute priority */ + if (hi) + lo = 0; + + pan = ((a->panning == PAN_SURROUND) ? PAN_CENTER : a->panning) + hi - lo; + + a->panning = (pan < PAN_LEFT) ? PAN_LEFT : (pan > PAN_RIGHT ? PAN_RIGHT : pan); +} + +static void +DoXMExtraFineSlideUp (UBYTE inf) +{ + if (!mp.vbtick) + { + a->period -= inf; + a->tmpperiod -= inf; + } +} + +static void +DoXMExtraFineSlideDown (UBYTE inf) +{ + if (!mp.vbtick) + { + a->period += inf; + a->tmpperiod += inf; + } +} + +/*========== Impulse Tracker effects */ + +static void +DoITChanVolSlide (UBYTE inf) +{ + UBYTE lo, hi; + + if (inf) + a->chanvolslide = inf; + inf = a->chanvolslide; + + lo = inf & 0xf; + hi = inf >> 4; + + if (!hi) + a->chanvol -= lo; + else if (!lo) + { + a->chanvol += hi; + } + else if (hi == 0xf) + { + if (!mp.vbtick) + a->chanvol -= lo; + } + else if (lo == 0xf) + { + if (!mp.vbtick) + a->chanvol += hi; } - note = l - 1; - /* - * 59 >= note >= 0 - * period_table[note] >= period > period_table[note + 1] - */ + if (a->chanvol < 0) + a->chanvol = 0; + if (a->chanvol > 64) + a->chanvol = 64; +} + +static void +DoITGlobalSlide (UBYTE inf) +{ + UBYTE lo, hi; + + if (inf) + mp.globalslide = inf; + inf = mp.globalslide; + + lo = inf & 0xf; + hi = inf >> 4; - if(period_table[note] == period) + if (!lo) + { + if (mp.vbtick) + mp.volume += hi; + } + else if (!hi) + { + if (mp.vbtick) + mp.volume -= lo; + } + else if (lo == 0xf) { - *finetune = 0; - return note + MOD_NOTE_OFFSET; + if (!mp.vbtick) + mp.volume += hi; } + else if (hi == 0xf) + { + if (!mp.vbtick) + mp.volume -= lo; + } + + if (mp.volume < 0) + mp.volume = 0; + if (mp.volume > 128) + mp.volume = 128; +} - /* fine tune completion */ - *finetune = (int)(256.0 * - (period_table[note] - period) / - (period_table[note] - period_table[note + 1])); +static void +DoITPanSlide (UBYTE inf) +{ + UBYTE lo, hi; + SWORD pan; + + if (inf) + a->pansspd = inf; + else + inf = a->pansspd; + + lo = inf & 0xf; + hi = inf >> 4; + + pan = (a->panning == PAN_SURROUND) ? PAN_CENTER : a->panning; + + if (!hi) + pan += lo << 2; + else if (!lo) + { + pan -= hi << 2; + } + else if (hi == 0xf) + { + if (!mp.vbtick) + pan += lo << 2; + } + else if (lo == 0xf) + { + if (!mp.vbtick) + pan -= hi << 2; + } + a->panning = /*pf->panning[mp.channel]= */ + (pan < PAN_LEFT) ? PAN_LEFT : (pan > PAN_RIGHT ? PAN_RIGHT : pan); +} + +static void +DoITTempo (UBYTE tempo) +{ + SWORD temp = mp.newbpm; + + if (mp.vbtick || mp.patdly2) + return; + + if (tempo & 0x10) + temp += (tempo & 0x0f); + else + temp -= tempo; + + mp.newbpm = (temp > 255) ? 255 : (temp < 1 ? 1 : temp); +} + +static void +DoITVibrato (void) +{ + UBYTE q; + UWORD temp = 0; + + q = (a->vibpos >> 2) & 0x1f; + + switch (a->wavecontrol & 3) + { + case 0: /* sine */ + temp = VibratoTable[q]; + break; + case 1: /* square wave */ + temp = 255; + break; + case 2: /* ramp down */ + q <<= 3; + if (a->vibpos < 0) + q = 255 - q; + temp = q; + break; + case 3: /* random */ + temp = getrandom (256); + break; + } + + temp *= a->vibdepth; + temp >>= 8; + temp <<= 2; + + if (a->vibpos >= 0) + a->period = a->tmpperiod + temp; + else + a->period = a->tmpperiod - temp; + + a->vibpos += a->vibspd; +} + +static void +DoITFineVibrato (void) +{ + UBYTE q; + UWORD temp = 0; + + q = (a->vibpos >> 2) & 0x1f; + + switch (a->wavecontrol & 3) + { + case 0: /* sine */ + temp = VibratoTable[q]; + break; + case 1: /* square wave */ + temp = 255; + break; + case 2: /* ramp down */ + q <<= 3; + if (a->vibpos < 0) + q = 255 - q; + temp = q; + break; + case 3: /* random */ + temp = getrandom (256); + break; + } + + temp *= a->vibdepth; + temp >>= 8; + + if (a->vibpos >= 0) + a->period = a->tmpperiod + temp; + else + a->period = a->tmpperiod - temp; + + a->vibpos += a->vibspd; +} + +static void +DoITTremor (UBYTE inf) +{ + UBYTE on, off; + + if (inf) + a->s3mtronof = inf; + else + { + inf = a->s3mtronof; + if (!inf) + return; + } + + if (!mp.vbtick) + return; + + on = (inf >> 4); + off = (inf & 0xf); + + a->s3mtremor %= (on + off); + a->volume = (a->s3mtremor < on) ? a->tmpvolume : 0; + a->s3mtremor++; +} + +static void +DoITPanbrello (void) +{ + UBYTE q; + SLONG temp = 0; + + q = a->panbpos; + + switch (a->panbwave) + { + case 0: /* sine */ + temp = PanbrelloTable[q]; + break; + case 1: /* square wave */ + temp = (q < 0x80) ? 64 : 0; + break; + case 2: /* ramp down */ + q <<= 3; + temp = q; + break; + case 3: /* random */ + if (a->panbpos >= a->panbspd) + { + a->panbpos = 0; + temp = getrandom (256); + } + } + + temp *= a->panbdepth; + temp = (temp / 8) + pf->panning[mp.channel]; + + a->panning = (temp < PAN_LEFT) ? PAN_LEFT : (temp > PAN_RIGHT ? PAN_RIGHT : temp); + a->panbpos += a->panbspd; +} + +static void +DoITToneSlide (void) +{ + /* if we don't come from another note, ignore the slide and play the note + as is */ + if (!a->oldnote) + return; + + if (mp.vbtick) + { + int dist; + + /* We have to slide a->period towards a->wantedperiod, compute the + difference between those two values */ + dist = a->period - a->wantedperiod; + + /* if they are equal or if portamentospeed is too big... */ + if ((!dist) || ((a->portspeed << 2) > abs (dist))) + /* ... make tmpperiod equal tperiod */ + a->tmpperiod = a->period = a->wantedperiod; + else if (dist > 0) + { + a->tmpperiod -= a->portspeed << 2; + a->period -= a->portspeed << 2; /* dist>0 slide up */ + } + else + { + a->tmpperiod += a->portspeed << 2; + a->period += a->portspeed << 2; /* dist<0 slide down */ + } + } + else + a->tmpperiod = a->period; +} + +static void DoNNAEffects (UBYTE dat); +/* Impulse/Scream Tracker Sxx effects. + All Sxx effects share the same memory space. */ +static void +DoSSEffects (UBYTE dat) +{ + UBYTE inf, c; + + inf = dat & 0xf; + c = dat >> 4; + + if (!dat) + { + c = a->sseffect; + inf = a->ssdata; + } + else + { + a->sseffect = c; + a->ssdata = inf; + } + + switch (c) + { + case SS_GLISSANDO: /* S1x set glissando voice */ + DoEEffects (0x30 | inf); + break; + case SS_FINETUNE: /* S2x set finetune */ + DoEEffects (0x50 | inf); + break; + case SS_VIBWAVE: /* S3x set vibrato waveform */ + DoEEffects (0x40 | inf); + break; + case SS_TREMWAVE: /* S4x set tremolo waveform */ + DoEEffects (0x70 | inf); + break; + case SS_PANWAVE: /* S5x panbrello */ + a->panbwave = inf; + break; + case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */ + DoEEffects (0xe0 | inf); + break; + case SS_S7EFFECTS: /* S7x instrument / NNA commands */ + DoNNAEffects (inf); + break; + case SS_PANNING: /* S8x set panning position */ + DoEEffects (0x80 | inf); + break; + case SS_SURROUND: /* S9x set surround Sound */ + a->panning = pf->panning[mp.channel] = PAN_SURROUND; + break; + case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */ + if (!mp.vbtick) + { + a->hioffset = inf << 16; + a->start = a->hioffset | a->soffset; + + if ((a->s) && (a->start > a->s->length)) + a->start = a->s->flags & (SF_LOOP | SF_BIDI) ? a->s->loopstart : a->s->length; + } + break; + case SS_PATLOOP: /* SBx pattern loop */ + DoEEffects (0x60 | inf); + break; + case SS_NOTECUT: /* SCx notecut */ + DoEEffects (0xC0 | inf); + break; + case SS_NOTEDELAY: /* SDx notedelay */ + DoEEffects (0xD0 | inf); + break; + case SS_PATDELAY: /* SEx patterndelay */ + DoEEffects (0xE0 | inf); + break; + } +} + +/* Impulse Tracker Volume/Pan Column effects. + All volume/pan column effects share the same memory space. */ +static void +DoVolEffects (UBYTE c) +{ + UBYTE inf = UniGetByte (); + + if ((!c) && (!inf)) + { + c = a->voleffect; + inf = a->voldata; + } + else + { + a->voleffect = c; + a->voldata = inf; + } + + if (c) + switch (c) + { + case VOL_VOLUME: + if (mp.vbtick) + break; + if (inf > 64) + inf = 64; + a->tmpvolume = inf; + break; + case VOL_PANNING: + a->panning = /*pf->panning[mp.channel]= */ inf; + break; + case VOL_VOLSLIDE: + DoS3MVolSlide (inf); + break; + case VOL_PITCHSLIDEDN: + if (a->period) + DoS3MSlideDn (inf); + break; + case VOL_PITCHSLIDEUP: + if (a->period) + DoS3MSlideUp (inf); + break; + case VOL_PORTAMENTO: + if (inf) + a->slidespeed = inf; + if (a->period) + { + if ((!mp.vbtick) || (a->newsamp)) + { + a->kick = KICK_NOTE; + a->start = -1; + } + else + a->kick = (a->kick == KICK_NOTE) ? KICK_ENV : KICK_ABSENT; + DoITToneSlide (); + a->ownper = 1; + } + break; + case VOL_VIBRATO: + if (!mp.vbtick) + { + if (inf & 0x0f) + a->vibdepth = inf & 0xf; + if (inf & 0xf0) + a->vibspd = (inf & 0xf0) >> 2; + } + if (a->period) + { + DoITVibrato (); + a->ownper = 1; + } + break; + } +} + +/*========== UltraTracker effects */ + +static void +DoULTSampleOffset (void) +{ + UWORD offset = UniGetWord (); + + if (offset) + a->ultoffset = offset; + + a->start = a->ultoffset << 2; + if ((a->s) && (a->start > a->s->length)) + a->start = a->s->flags & (SF_LOOP | SF_BIDI) ? a->s->loopstart : a->s->length; +} + +/*========== OctaMED effects */ + +static void +DoMEDSpeed (void) +{ + UWORD speed = UniGetWord (); + + mp.newbpm = speed; +} + +/*========== General player functions */ + +static void +pt_playeffects (void) +{ + UBYTE dat, c; + + while ((c = UniGetByte ())) + { + int oldsliding = a->sliding; + + a->sliding = 0; + switch (c) + { + case UNI_NOTE: + case UNI_INSTRUMENT: + a->sliding = oldsliding; + UniSkipOpcode (c); + break; + case UNI_PTEFFECT0: + dat = UniGetByte (); + if (!mp.vbtick) + { + if ((!dat) && (pf->flags & UF_ARPMEM)) + dat = a->arpmem; + a->arpmem = dat; + } + if (a->period) + DoArpeggio (a->arpmem); + break; + case UNI_PTEFFECT1: + dat = UniGetByte (); + if ((!mp.vbtick) && (dat)) + a->slidespeed = (UWORD) dat << 2; + if (a->period) + if (mp.vbtick) + a->tmpperiod -= a->slidespeed; + break; + case UNI_PTEFFECT2: + dat = UniGetByte (); + if ((!mp.vbtick) && (dat)) + a->slidespeed = (UWORD) dat << 2; + if (a->period) + if (mp.vbtick) + a->tmpperiod += a->slidespeed; + break; + case UNI_PTEFFECT3: + dat = UniGetByte (); + if ((!mp.vbtick) && (dat)) + a->portspeed = (UWORD) dat << 2; + if (a->period) + { + if (!a->fadevol) + a->kick = (a->kick == KICK_NOTE) ? KICK_NOTE : KICK_KEYOFF; + else + a->kick = (a->kick == KICK_NOTE) ? KICK_ENV : KICK_ABSENT; + DoToneSlide (); + a->ownper = 1; + } + break; + case UNI_PTEFFECT4: + case UNI_XMEFFECT4: + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat & 0x0f) + a->vibdepth = dat & 0xf; + if (dat & 0xf0) + a->vibspd = (dat & 0xf0) >> 2; + } + else if (a->period) + { + DoVibrato (); + a->ownper = 1; + } + break; + case UNI_PTEFFECT5: + dat = UniGetByte (); + if (a->period) + { + if (!a->fadevol) + a->kick = (a->kick == KICK_NOTE) ? KICK_NOTE : KICK_KEYOFF; + else + a->kick = (a->kick == KICK_NOTE) ? KICK_ENV : KICK_ABSENT; + DoToneSlide (); + a->ownper = 1; + } + DoVolSlide (dat); + break; + case UNI_PTEFFECT6: + dat = UniGetByte (); + if ((a->period) && (mp.vbtick)) + { + DoVibrato (); + a->ownper = 1; + } + DoVolSlide (dat); + break; + case UNI_PTEFFECT7: + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat & 0x0f) + a->trmdepth = dat & 0xf; + if (dat & 0xf0) + a->trmspd = (dat & 0xf0) >> 2; + } + if (a->period) + { + DoTremolo (); + a->ownvol = 1; + } + break; + case UNI_PTEFFECT8: + dat = UniGetByte (); + a->panning = pf->panning[mp.channel] = dat; + break; + case UNI_PTEFFECT9: + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat) + a->soffset = (UWORD) dat << 8; + a->start = a->hioffset | a->soffset; + + if ((a->s) && (a->start > a->s->length)) + a->start = a->s->flags & (SF_LOOP | SF_BIDI) ? a->s->loopstart : a->s->length; + } + break; + case UNI_PTEFFECTA: + DoVolSlide (UniGetByte ()); + break; + case UNI_PTEFFECTB: + dat = UniGetByte (); + if ((mp.vbtick) || (mp.patdly2)) + break; + /* Vincent Voois uses a nasty trick in "Universal Bolero" */ + if (dat == mp.sngpos && mp.patbrk == mp.patpos) + break; + if ((!mp.patbrk) && ((dat < mp.sngpos) || + ((mp.sngpos == pf->numpos - 1) && (!mp.patbrk)) || + ((dat == mp.sngpos) && (pf->flags & UF_NOWRAP)))) + { + /* if we don't loop, better not to skip the end of the + pattern, after all... so: + mp.patbrk=0; */ + mp.posjmp = 3; + } + else + { + /* if we were fading, adjust... */ + if (mp.sngpos == (pf->numpos - 1)) + mp.volume = pf->initvolume > 128 ? 128 : pf->initvolume; + mp.sngpos = dat; + mp.posjmp = 2; + mp.patpos = 0; + } + break; + case UNI_PTEFFECTC: + dat = UniGetByte (); + if (mp.vbtick) + break; + if (dat == (UBYTE) - 1) + a->anote = dat = 0; /* note cut */ + else if (dat > 64) + dat = 64; + a->tmpvolume = dat; + break; + case UNI_PTEFFECTD: + dat = UniGetByte (); + if ((mp.vbtick) || (mp.patdly2)) + break; + if ((pf->positions[mp.sngpos] != 255) && + (dat > pf->pattrows[pf->positions[mp.sngpos]])) + dat = pf->pattrows[pf->positions[mp.sngpos]]; + mp.patbrk = dat; + if (!mp.posjmp) + { + /* don't ask me to explain this code - it makes + backwards.s3m and children.xm (heretic's version) play + correctly, among others. Take that for granted, or write + the page of comments yourself... you might need some + aspirin - Miod */ + if ((mp.sngpos == pf->numpos - 1) && (dat) && + ((pf->positions[mp.sngpos] == (pf->numpat - 1) + && !(pf->flags & UF_NOWRAP)))) + { + mp.sngpos = 0; + mp.posjmp = 2; + } + else + mp.posjmp = 3; + } + break; + case UNI_PTEFFECTE: + DoEEffects (UniGetByte ()); + break; + case UNI_PTEFFECTF: + dat = UniGetByte (); + if (mp.vbtick || mp.patdly2) + break; + if (dat >= 0x20) + mp.newbpm = dat; + else if (dat) + { + mp.sngspd = (dat > 32) ? 32 : dat; + mp.vbtick = 0; + } + break; + case UNI_S3MEFFECTA: + DoS3MSpeed (UniGetByte ()); + break; + case UNI_S3MEFFECTD: + DoS3MVolSlide (UniGetByte ()); + break; + case UNI_S3MEFFECTE: + dat = UniGetByte (); + if (a->period) + DoS3MSlideDn (dat); + break; + case UNI_S3MEFFECTF: + dat = UniGetByte (); + if (a->period) + DoS3MSlideUp (dat); + break; + case UNI_S3MEFFECTI: + DoS3MTremor (UniGetByte ()); + a->ownvol = 1; + break; + case UNI_S3MEFFECTQ: + dat = UniGetByte (); + if (a->period) + DoS3MRetrig (dat); + break; + case UNI_S3MEFFECTR: + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat & 0x0f) + a->trmdepth = dat & 0xf; + if (dat & 0xf0) + a->trmspd = (dat & 0xf0) >> 2; + } + DoS3MTremolo (); + a->ownvol = 1; + break; + case UNI_S3MEFFECTT: + DoS3MTempo (UniGetByte ()); + break; + case UNI_S3MEFFECTU: + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat & 0x0f) + a->vibdepth = dat & 0xf; + if (dat & 0xf0) + a->vibspd = (dat & 0xf0) >> 2; + } + else if (a->period) + { + DoS3MFineVibrato (); + a->ownper = 1; + } + break; + case UNI_KEYOFF: + a->keyoff |= KEY_OFF; + if ((!(a->volflg & EF_ON)) || (a->volflg & EF_LOOP)) + a->keyoff = KEY_KILL; + break; + case UNI_KEYFADE: + dat = UniGetByte (); + if ((mp.vbtick >= dat) || (mp.vbtick == mp.sngspd - 1)) + { + a->keyoff = KEY_KILL; + if (!(a->volflg & EF_ON)) + a->fadevol = 0; + } + break; + case UNI_VOLEFFECTS: + DoVolEffects (UniGetByte ()); + break; + case UNI_XMEFFECTA: + DoXMVolSlide (UniGetByte ()); + break; + case UNI_XMEFFECTE1: /* XM fineslide up */ + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat) + a->fportupspd = dat; + if (a->period) + a->tmpperiod -= (a->fportupspd << 2); + } + break; + case UNI_XMEFFECTE2: /* XM fineslide dn */ + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat) + a->fportdnspd = dat; + if (a->period) + a->tmpperiod += (a->fportdnspd << 2); + } + break; + case UNI_XMEFFECTEA: /* fine volume slide up */ + dat = UniGetByte (); + if (!mp.vbtick) + if (dat) + a->fslideupspd = dat; + a->tmpvolume += a->fslideupspd; + if (a->tmpvolume > 64) + a->tmpvolume = 64; + break; + case UNI_XMEFFECTEB: /* fine volume slide dn */ + dat = UniGetByte (); + if (!mp.vbtick) + if (dat) + a->fslidednspd = dat; + a->tmpvolume -= a->fslidednspd; + if (a->tmpvolume < 0) + a->tmpvolume = 0; + break; + case UNI_XMEFFECTG: + mp.volume = UniGetByte () << 1; + if (mp.volume > 128) + mp.volume = 128; + break; + case UNI_XMEFFECTH: + DoXMGlobalSlide (UniGetByte ()); + break; + case UNI_XMEFFECTL: + dat = UniGetByte (); + if ((!mp.vbtick) && (a->i)) + { + UWORD points; + INSTRUMENT *i = a->i; + MP_VOICE *aout; + + if ((aout = a->slave)) + { + points = i->volenv[i->volpts - 1].pos; + aout->venv.p = aout->venv.env[(dat > points) ? points : dat].pos; + points = i->panenv[i->panpts - 1].pos; + aout->penv.p = aout->penv.env[(dat > points) ? points : dat].pos; + } + } + break; + case UNI_XMEFFECTP: + dat = UniGetByte (); + DoXMPanSlide (dat); + break; + case UNI_XMEFFECTX1: + dat = UniGetByte (); + if (dat) + a->ffportupspd = dat; + else + dat = a->ffportupspd; + if (a->period) + { + DoXMExtraFineSlideUp (dat); + a->ownper = 1; + } + break; + case UNI_XMEFFECTX2: + dat = UniGetByte (); + if (dat) + a->ffportdnspd = dat; + else + dat = a->ffportdnspd; + if (a->period) + { + DoXMExtraFineSlideDown (dat); + a->ownper = 1; + } + break; + case UNI_ITEFFECTG: + dat = UniGetByte (); + if (dat) + { + a->portspeed = dat; + } + if (a->period) + { + if ((!mp.vbtick) && (a->newsamp)) + { + a->kick = KICK_NOTE; + a->start = -1; + } + else + a->kick = (a->kick == KICK_NOTE) ? KICK_ENV : KICK_ABSENT; + DoITToneSlide (); + a->ownper = 1; + } + break; + case UNI_ITEFFECTH: /* IT vibrato */ + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat & 0x0f) + a->vibdepth = dat & 0xf; + if (dat & 0xf0) + a->vibspd = (dat & 0xf0) >> 2; + } + if (a->period) + { + DoITVibrato (); + a->ownper = 1; + } + break; + case UNI_ITEFFECTI: /* IT tremor */ + DoITTremor (UniGetByte ()); + a->ownvol = 1; + break; + case UNI_ITEFFECTM: + a->chanvol = UniGetByte (); + if (a->chanvol > 64) + a->chanvol = 64; + else if (a->chanvol < 0) + a->chanvol = 0; + break; + case UNI_ITEFFECTN: /* slide / fineslide channel volume */ + DoITChanVolSlide (UniGetByte ()); + break; + case UNI_ITEFFECTP: /* slide / fineslide channel panning */ + dat = UniGetByte (); + DoITPanSlide (dat); + break; + case UNI_ITEFFECTT: /* slide / fineslide tempo */ + DoITTempo (UniGetByte ()); + break; + case UNI_ITEFFECTU: /* fine vibrato */ + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat & 0x0f) + a->vibdepth = dat & 0xf; + if (dat & 0xf0) + a->vibspd = (dat & 0xf0) >> 2; + } + if (a->period) + { + DoITFineVibrato (); + a->ownper = 1; + } + break; + case UNI_ITEFFECTW: /* slide / fineslide global volume */ + DoITGlobalSlide (UniGetByte ()); + break; + case UNI_ITEFFECTY: /* panbrello */ + dat = UniGetByte (); + if (!mp.vbtick) + { + if (dat & 0x0f) + a->panbdepth = (dat & 0xf); + if (dat & 0xf0) + a->panbspd = (dat & 0xf0) >> 4; + } + DoITPanbrello (); + break; + case UNI_ITEFFECTS0: + DoSSEffects (UniGetByte ()); + break; + case UNI_ITEFFECTZ: + /* FIXME not yet implemented */ + UniSkipOpcode (UNI_ITEFFECTZ); + break; + case UNI_ULTEFFECT9: + DoULTSampleOffset (); + break; + case UNI_MEDSPEED: + DoMEDSpeed (); + break; + case UNI_MEDEFFECTF1: + DoEEffects (0x90 | (mp.sngspd / 2)); + break; + case UNI_MEDEFFECTF2: + DoEEffects (0xd0 | (mp.sngspd / 2)); + break; + case UNI_MEDEFFECTF3: + DoEEffects (0x90 | (mp.sngspd / 3)); + break; + default: + a->sliding = oldsliding; + UniSkipOpcode (c); + break; + } + } +} + +static void +DoNNAEffects (UBYTE dat) +{ + int t; + MP_VOICE *aout; + + dat &= 0xf; + aout = (a->slave) ? a->slave : NULL; + + switch (dat) + { + case 0x0: /* past note cut */ + for (t = 0; t < MOD_NUM_VOICES; t++) + if (mp.voice[t].master == a) + mp.voice[t].fadevol = 0; + break; + case 0x1: /* past note off */ + for (t = 0; t < MOD_NUM_VOICES; t++) + if (mp.voice[t].master == a) + { + mp.voice[t].keyoff |= KEY_OFF; + if ((!(mp.voice[t].venv.flg & EF_ON)) || + (mp.voice[t].venv.flg & EF_LOOP)) + mp.voice[t].keyoff = KEY_KILL; + } + break; + case 0x2: /* past note fade */ + for (t = 0; t < MOD_NUM_VOICES; t++) + if (mp.voice[t].master == a) + mp.voice[t].keyoff |= KEY_FADE; + break; + case 0x3: /* set NNA note cut */ + a->nna = (a->nna & ~NNA_MASK) | NNA_CUT; + break; + case 0x4: /* set NNA note continue */ + a->nna = (a->nna & ~NNA_MASK) | NNA_CONTINUE; + break; + case 0x5: /* set NNA note off */ + a->nna = (a->nna & ~NNA_MASK) | NNA_OFF; + break; + case 0x6: /* set NNA note fade */ + a->nna = (a->nna & ~NNA_MASK) | NNA_FADE; + break; + case 0x7: /* disable volume envelope */ + if (aout) + aout->volflg &= ~EF_ON; + break; + case 0x8: /* enable volume envelope */ + if (aout) + aout->volflg |= EF_ON; + break; + case 0x9: /* disable panning envelope */ + if (aout) + aout->panflg &= ~EF_ON; + break; + case 0xa: /* enable panning envelope */ + if (aout) + aout->panflg |= EF_ON; + break; + case 0xb: /* disable pitch envelope */ + if (aout) + aout->pitflg &= ~EF_ON; + break; + case 0xc: /* enable pitch envelope */ + if (aout) + aout->pitflg |= EF_ON; + break; + } +} + +static void +pt_UpdateVoices () +{ + SWORD envpan, envvol, envpit; + UWORD playperiod; + SLONG vibval, vibdpt; + ULONG tmpvol; + BOOL kick_voice; + + MP_VOICE *aout; + INSTRUMENT *i; + SAMPLE *s; + + mp.totalchn = mp.realchn = 0; + for (mp.channel = 0; mp.channel < MOD_NUM_VOICES; mp.channel++) + { + aout = &mp.voice[mp.channel]; + i = aout->i; + s = aout->s; + + if ((!s) || (!s->length)) + continue; + + if (aout->period < 40) + aout->period = 40; + else if (aout->period > 50000) + aout->period = 50000; + + if ((aout->kick == KICK_NOTE) || (aout->kick == KICK_KEYOFF)) + { + kick_voice = 1; + aout->fadevol = 32768; + aout->aswppos = 0; + } + else + kick_voice = 0; + + if (i && ((aout->kick == KICK_NOTE) || (aout->kick == KICK_ENV))) + { + StartEnvelope (&aout->venv, aout->volflg, i->volpts, i->volsusbeg, + i->volsusend, i->volbeg, i->volend, i->volenv, aout->keyoff); + StartEnvelope (&aout->penv, aout->panflg, i->panpts, i->pansusbeg, + i->pansusend, i->panbeg, i->panend, i->panenv, aout->keyoff); + StartEnvelope (&aout->cenv, aout->pitflg, i->pitpts, i->pitsusbeg, + i->pitsusend, i->pitbeg, i->pitend, i->pitenv, aout->keyoff); + if (aout->cenv.flg & EF_ON) + aout->masterperiod = GetPeriod ((UWORD) aout->note << 1, aout->master->speed); + } + aout->kick = KICK_ABSENT; + + envvol = (!(aout->volflg & EF_ON)) ? 256 : + ProcessEnvelope (&aout->venv, 256, aout->keyoff); + envpan = (!(aout->panflg & EF_ON)) ? PAN_CENTER : + ProcessEnvelope (&aout->penv, PAN_CENTER, aout->keyoff); + envpit = (!(aout->pitflg & EF_ON)) ? 32 : + ProcessEnvelope (&aout->cenv, 32, aout->keyoff); + + tmpvol = aout->fadevol; /* max 32768 */ + tmpvol *= aout->chanvol; /* * max 64 */ + tmpvol *= aout->volume; /* * max 256 */ + tmpvol /= 16384L; /* tmpvol is max 32768 */ + aout->totalvol = tmpvol >> 2; /* totalvolume used to determine samplevolume */ + tmpvol *= envvol; /* * max 256 */ + tmpvol *= mp.volume; /* * max 128 */ + tmpvol /= 4194304UL; + + Voice_SetVolume (mp.channel, tmpvol); + if ((tmpvol) && (aout->master) && (aout->master->slave == aout)) + mp.realchn++; + mp.totalchn++; + + if (aout->panning == PAN_SURROUND) + Voice_SetPanning (mp.channel, PAN_SURROUND); + else if (aout->penv.flg & EF_ON) + Voice_SetPanning (mp.channel, DoPan (envpan, aout->panning)); + else + Voice_SetPanning (mp.channel, aout->panning); + + if (aout->period && s->vibdepth) + switch (s->vibtype) + { + case 0: + vibval = avibtab[aout->avibpos & 127]; + if (aout->avibpos & 0x80) + vibval = -vibval; + break; + case 1: + vibval = 64; + if (aout->avibpos & 0x80) + vibval = -vibval; + break; + case 2: + vibval = 63 - (((aout->avibpos + 128) & 255) >> 1); + break; + default: + vibval = (((aout->avibpos + 128) & 255) >> 1) - 64; + break; + } + else + vibval = 0; + + if (s->vibflags & AV_IT) + { + if ((aout->aswppos >> 8) < s->vibdepth) + { + aout->aswppos += s->vibsweep; + vibdpt = aout->aswppos; + } + else + vibdpt = s->vibdepth << 8; + vibval = (vibval * vibdpt) >> 16; + if (aout->mflag) + { + if (!(pf->flags & UF_LINEAR)) + vibval >>= 1; + aout->period -= vibval; + } + } + else + { + /* do XM style auto-vibrato */ + if (!(aout->keyoff & KEY_OFF)) + { + if (aout->aswppos < s->vibsweep) + { + vibdpt = (aout->aswppos * s->vibdepth) / s->vibsweep; + aout->aswppos++; + } + else + vibdpt = s->vibdepth; + } + else + { + /* keyoff -> depth becomes 0 if final depth wasn't reached or + stays at final level if depth WAS reached */ + if (aout->aswppos >= s->vibsweep) + vibdpt = s->vibdepth; + else + vibdpt = 0; + } + vibval = (vibval * vibdpt) >> 8; + aout->period -= vibval; + } + + /* update vibrato position */ + aout->avibpos = (aout->avibpos + s->vibrate) & 0xff; + + /* process pitch envelope */ + playperiod = aout->period; + + if ((aout->pitflg & EF_ON) && (envpit != 32)) + { + long p1; + + envpit -= 32; + if ((aout->note << 1) + envpit <= 0) + envpit = -(aout->note << 1); + + p1 = GetPeriod (((UWORD) aout->note << 1) + envpit, aout->master->speed) - aout->masterperiod; + if (p1 > 0) + { + if ((UWORD) (playperiod + p1) <= playperiod) + { + p1 = 0; + aout->keyoff |= KEY_OFF; + } + } + else if (p1 < 0) + { + if ((UWORD) (playperiod + p1) >= playperiod) + { + p1 = 0; + aout->keyoff |= KEY_OFF; + } + } + playperiod += p1; + } + + if (!aout->fadevol) + { /* check for a dead note (fadevol=0) */ + Voice_Stop (mp.channel); + mp.totalchn--; + if ((tmpvol) && (aout->master) && (aout->master->slave == aout)) + mp.realchn--; + } + else + { + if (kick_voice) + Voice_Stop (mp.channel); + + Voice_SetPeriod (mp.channel, + getAmigaPeriod (pf->flags, playperiod)); + + if (kick_voice) + Voice_Play (mp.channel, s, (aout->start == -1) ? ((s->flags & SF_UST_LOOP) ? s->loopstart : 0) : aout->start); + + /* if keyfade, start substracting fadeoutspeed from fadevol: */ + if ((i) && (aout->keyoff & KEY_FADE)) + { + if (aout->fadevol >= i->volfade) + aout->fadevol -= i->volfade; + else + aout->fadevol = 0; + } + } + + if (mp.bpm != mp.newbpm || mp.sngspd != mp.oldsngspd) { + mp.bpm = mp.newbpm; + mp.oldsngspd = mp.sngspd; + Voice_NewTempo(mp.bpm, mp.sngspd); + } + } +} + +/* Handles new notes or instruments */ +static void +pt_Notes (void) +{ + UBYTE c, inst; + int tr, funky; /* funky is set to indicate note or instrument change */ + + for (mp.channel = 0; mp.channel < pf->numchn; mp.channel++) + { + a = &mp.control[mp.channel]; + + if (mp.sngpos >= pf->numpos) + { + tr = pf->numtrk; + mp.numrow = 0; + } + else + { + tr = pf->patterns[(pf->positions[mp.sngpos] * pf->numchn) + mp.channel]; + mp.numrow = pf->pattrows[pf->positions[mp.sngpos]]; + } + + a->row = (tr < pf->numtrk) ? UniFindRow (pf->tracks[tr], mp.patpos) : NULL; + a->newsamp = 0; + if (!mp.vbtick) + a->notedelay = 0; + + if (!a->row) + continue; + UniSetRow (a->row); + funky = 0; + + while ((c = UniGetByte ())) + switch (c) + { + case UNI_NOTE: + funky |= 1; + a->oldnote = a->anote, a->anote = UniGetByte (); + a->kick = KICK_NOTE; + a->start = -1; + a->sliding = 0; + + /* retrig tremolo and vibrato waves ? */ + if (!(a->wavecontrol & 0x80)) + a->trmpos = 0; + if (!(a->wavecontrol & 0x08)) + a->vibpos = 0; + if (!a->panbwave) + a->panbpos = 0; + break; + case UNI_INSTRUMENT: + inst = UniGetByte (); + if (inst >= pf->numins) + break; /* safety valve */ + funky |= 2; + a->i = (pf->flags & UF_INST) ? &pf->instruments[inst] : NULL; + a->retrig = 0; + a->s3mtremor = 0; + a->sample = inst; + break; + default: + UniSkipOpcode (c); + break; + } + + if (funky) + { + INSTRUMENT *i; + SAMPLE *s; + + i = a->i; + if (i) + { + if (i->samplenumber[a->anote] >= pf->numsmp) + continue; + s = &pf->samples[i->samplenumber[a->anote]]; + a->note = i->samplenote[a->anote]; + } + else + { + a->note = a->anote; + s = &pf->samples[a->sample]; + } + + if (a->s != s) + { + a->s = s; + a->newsamp = a->period; + } + + /* channel or instrument determined panning ? */ + a->panning = pf->panning[mp.channel]; + if (s->flags & SF_OWNPAN) + a->panning = s->panning; + else if ((i) && (i->flags & IF_OWNPAN)) + a->panning = i->panning; + + a->data = s->data; + a->speed = s->speed; + + if (i) + { + if ((i->flags & IF_PITCHPAN) + && (a->panning != PAN_SURROUND)) + { + a->panning += ((a->anote - i->pitpancenter) * i->pitpansep) / 8; + if (a->panning < PAN_LEFT) + a->panning = PAN_LEFT; + else if (a->panning > PAN_RIGHT) + a->panning = PAN_RIGHT; + } + a->pitflg = i->pitflg; + a->volflg = i->volflg; + a->panflg = i->panflg; + a->nna = i->nnatype; + a->dca = i->dca; + a->dct = i->dct; + } + else + { + a->pitflg = 0; + a->volflg = 0; + a->panflg = 0; + a->nna = 0; + a->dca = 0; + a->dct = 0; + } + + if (funky & 2) /* instrument change */ + { + /* IT random volume variations: 0:8 bit fixed, and one bit for + sign. */ + a->volume = a->tmpvolume = s->volume; + if ((s) && (i)) + { + if (i->rvolvar) + { + a->volume = a->tmpvolume = s->volume + + ((s->volume * ((SLONG) i->rvolvar * (SLONG) getrandom (512) + )) / 25600); + if (a->volume < 0) + a->volume = a->tmpvolume = 0; + else if (a->volume > 64) + a->volume = a->tmpvolume = 64; + } + if ((a->panning != PAN_SURROUND)) + { + a->panning += ((a->panning * ((SLONG) i->rpanvar * + (SLONG) getrandom (512))) / 25600); + if (a->panning < PAN_LEFT) + a->panning = PAN_LEFT; + else if (a->panning > PAN_RIGHT) + a->panning = PAN_RIGHT; + } + } + } + + a->wantedperiod = a->tmpperiod = GetPeriod ((UWORD) a->note << 1, a->speed); + a->keyoff = KEY_KICK; + } + } +} + +/* Handles effects */ +static void +pt_EffectsPass1 (void) +{ + MP_VOICE *aout; + + for (mp.channel = 0; mp.channel < pf->numchn; mp.channel++) + { + a = &mp.control[mp.channel]; + + if ((aout = a->slave)) + { + a->fadevol = aout->fadevol; + a->period = aout->period; + if (a->kick == KICK_KEYOFF) + a->keyoff = aout->keyoff; + } + + if (!a->row) + continue; + UniSetRow (a->row); + + a->ownper = a->ownvol = 0; + mp.explicitslides = 0; + pt_playeffects (); + + /* continue volume slide if necessary for XM and IT */ + if (pf->flags & UF_BGSLIDES) + { + if (!mp.explicitslides) + switch (a->sliding) + { + case 1: + DoS3MVolSlide (0); + break; + case 2: + DoXMVolSlide (0); + break; + } + else if (a->tmpvolume) + a->sliding = mp.explicitslides; + } + + if (!a->ownper) + a->period = a->tmpperiod; + if (!a->ownvol) + a->volume = a->tmpvolume; + + if (a->s) + { + if (a->i) + a->outvolume = (a->volume * a->s->globvol * a->i->globvol) >> 10; + else + a->outvolume = (a->volume * a->s->globvol) >> 4; + if (a->outvolume > 256) + a->volume = 256; + else if (a->outvolume < 0) + a->outvolume = 0; + } + } +} + +/* NNA management */ +static void +pt_NNA (void) +{ + for (mp.channel = 0; mp.channel < pf->numchn; mp.channel++) + { + a = &mp.control[mp.channel]; + + if (a->kick == KICK_NOTE) + { + BOOL k = 0; + + if (a->slave) + { + MP_VOICE *aout; + + aout = a->slave; + if (aout->nna & NNA_MASK) + { + /* Make sure the old MP_VOICE channel knows it has no + master now ! */ + a->slave = NULL; + /* assume the channel is taken by NNA */ + aout->mflag = 0; + + switch (aout->nna) + { + case NNA_CONTINUE: /* continue note, do nothing */ + break; + case NNA_OFF: /* note off */ + aout->keyoff |= KEY_OFF; + if ((!(aout->volflg & EF_ON)) || (aout->volflg & EF_LOOP)) + aout->keyoff = KEY_KILL; + break; + case NNA_FADE: + aout->keyoff |= KEY_FADE; + break; + } + } + } + + if (a->dct != DCT_OFF) + { + int t; + + for (t = 0; t < MOD_NUM_VOICES; t++) + if ((!Voice_Stopped (t)) && + (mp.voice[t].masterchn == mp.channel) && + (a->sample == mp.voice[t].sample)) + { + k = 0; + switch (a->dct) + { + case DCT_NOTE: + if (a->note == mp.voice[t].note) + k = 1; + break; + case DCT_SAMPLE: + if (a->data == mp.voice[t].data) + k = 1; + break; + case DCT_INST: + k = 1; + break; + } + if (k) + switch (a->dca) + { + case DCA_CUT: + mp.voice[t].fadevol = 0; + break; + case DCA_OFF: + mp.voice[t].keyoff |= KEY_OFF; + if ((!(mp.voice[t].volflg & EF_ON)) || + (mp.voice[t].volflg & EF_LOOP)) + mp.voice[t].keyoff = KEY_KILL; + break; + case DCA_FADE: + mp.voice[t].keyoff |= KEY_FADE; + break; + } + } + } + } /* if (a->kick==KICK_NOTE) */ + } +} + +/* Setup module and NNA voices */ +static void +pt_SetupVoices (void) +{ + MP_VOICE *aout; + + for (mp.channel = 0; mp.channel < pf->numchn; mp.channel++) + { + a = &mp.control[mp.channel]; + + if (a->notedelay) + continue; + if (a->kick == KICK_NOTE) + { + /* if no channel was cut above, find an empty or quiet channel + here */ + if (pf->flags & UF_NNA) + { + if (!a->slave) + { + int newchn; + + if ((newchn = MP_FindEmptyChannel ()) != -1) + a->slave = &mp.voice[a->slavechn = newchn]; + } + } + else + a->slave = &mp.voice[a->slavechn = mp.channel]; + + /* assign parts of MP_VOICE only done for a KICK ! */ + if ((aout = a->slave)) + { + if (aout->mflag && aout->master) + aout->master->slave = NULL; + a->slave = aout; + aout->master = a; + aout->masterchn = mp.channel; + aout->mflag = 1; + } + } + else + aout = a->slave; + + if (aout) + { + aout->kick = a->kick; + aout->i = a->i; + aout->s = a->s; + aout->sample = a->sample; + aout->data = a->data; + aout->period = a->period; + aout->panning = a->panning; + aout->chanvol = a->chanvol; + aout->fadevol = a->fadevol; + aout->start = a->start; + aout->volflg = a->volflg; + aout->panflg = a->panflg; + aout->pitflg = a->pitflg; + aout->volume = a->outvolume; + aout->keyoff = a->keyoff; + aout->note = a->note; + aout->nna = a->nna; + } + a->kick = KICK_ABSENT; + } +} + +/* second effect pass */ +static void +pt_EffectsPass2 (void) +{ + UBYTE c; + + for (mp.channel = 0; mp.channel < pf->numchn; mp.channel++) + { + a = &mp.control[mp.channel]; + + if (!a->row) + continue; + UniSetRow (a->row); + + while ((c = UniGetByte ())) + if (c == UNI_ITEFFECTS0) + { + c = UniGetByte (); + if ((c >> 4) == SS_S7EFFECTS) + DoNNAEffects (c & 0xf); + } + else + UniSkipOpcode (c); + } +} + +static BOOL +HandleTick (void) +{ + if ((!pf) || (mp.sngpos >= pf->numpos)) + return 0; + + if (++mp.vbtick >= mp.sngspd) + { + if (mp.pat_repcrazy) + mp.pat_repcrazy = 0; /* play 2 times row 0 */ + else + mp.patpos++; + mp.vbtick = 0; + + /* process pattern-delay. mp.patdly2 is the counter and mp.patdly is + the command memory. */ + if (mp.patdly) + mp.patdly2 = mp.patdly, mp.patdly = 0; + if (mp.patdly2) + { + /* patterndelay active */ + if (--mp.patdly2) + /* so turn back mp.patpos by 1 */ + if (mp.patpos) + mp.patpos--; + } + + /* do we have to get a new patternpointer ? (when mp.patpos reaches the + pattern size, or when a patternbreak is active) */ + if (((mp.patpos >= mp.numrow) && (mp.numrow > 0)) && (!mp.posjmp)) + mp.posjmp = 3; + + if (mp.posjmp) + { + mp.patpos = mp.numrow ? (mp.patbrk % mp.numrow) : 0; + mp.pat_repcrazy = 0; + mp.sngpos += (mp.posjmp - 2); + for (mp.channel = 0; mp.channel < pf->numchn; mp.channel++) + mp.control[mp.channel].pat_reppos = -1; + + mp.patbrk = mp.posjmp = 0; + /* handle the "---" (end of song) pattern since it can occur + *inside* the module in .IT and .S3M */ + if ((mp.sngpos >= pf->numpos) || (pf->positions[mp.sngpos] == 255)) + { + return 0; + } + if (mp.sngpos < 0) + mp.sngpos = pf->numpos - 1; + } + + if (!mp.patdly2) + pt_Notes (); + } + + pt_EffectsPass1 (); + if (pf->flags & UF_NNA) + pt_NNA (); + pt_SetupVoices (); + pt_EffectsPass2 (); + + /* now set up the actual hardware channel playback information */ + pt_UpdateVoices (); + return 1; +} + +BOOL +mod_do_play (MODULE * mf) +{ + int t; + + /* make sure the player doesn't start with garbage */ + memset(&mp, 0, sizeof(mp)); + mp.control = (MP_CONTROL *) safe_malloc (mf->numchn * sizeof (MP_CONTROL)); + if (!mp.control) + return 1; + + memset (mp.control, 0, mf->numchn * sizeof (MP_CONTROL)); + for (t = 0; t < mf->numchn; t++) + { + mp.control[t].chanvol = mf->chanvol[t]; + mp.control[t].panning = mf->panning[t]; + } - return note + MOD_NOTE_OFFSET; + mp.pat_repcrazy = 0; + mp.sngpos = 0; + mp.sngspd = mf->initspeed ? (mf->initspeed < 32 ? mf->initspeed : 32) : 6; + mp.volume = mf->initvolume > 128 ? 128 : mf->initvolume; + + mp.oldsngspd = mp.sngspd; + mp.vbtick = mp.sngspd; + mp.patdly = 0; + mp.patdly2 = 0; + mp.bpm = mf->inittempo < 32 ? 32 : mf->inittempo; + mp.newbpm = mp.bpm; + + mp.patpos = 0; + mp.posjmp = 2; /* make sure the player fetches the first note */ + mp.numrow = -1; + mp.patbrk = 0; + pf = mf; + + Voice_StartPlaying (); + Voice_NewTempo (mp.bpm, mp.sngspd); + do + Voice_TickDone (); + while (HandleTick ()); + Voice_TickDone (); + Voice_EndPlaying (); + + /* Done! */ + free (mp.control); + return 0; } diff -ruN TiMidity++-2.8.2/timidity/mod.h TiMidity++-2.9.0/timidity/mod.h --- TiMidity++-2.8.2/timidity/mod.h Mon Feb 7 07:58:16 2000 +++ TiMidity++-2.9.0/timidity/mod.h Thu Feb 17 23:22:26 2000 @@ -1,105 +1,31 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999,2000 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef ___MOD_H_ -#define ___MOD_H_ - -/* - Clock -SampleRate := ---------- - Period -*/ - -#define NTSC_CLOCK 3579545.25 -#define NTSC_RATE (NTSC_CLOCK/428) - -#define PAL_CLOCK 3546894.6 -#define PAL_RATE (PAL_CLOCK/428) - - -#define MIDI_CLOCK 3499241.93589551 /* for freq_table[] - * freq_table[0] := MIDI_CLOCK/428 - */ -#define NTSC_MIDI_FINETUNE -101 -#define PAL_MIDI_FINETUNE -60 - -#define MOD_BASE_NOTE 60 -#define MOD_NOTE_OFFSET 36 -#define MOD_BEND_SENSITIVE 60 - -#define MOD_EFX_PORTAMENT_UP 0x01 -#define MOD_EFX_PORTAMENT_DOWN 0x02 -#define MOD_EFX_PORTAMENT 0x03 -#define MOD_EFX_VIBRATO 0x04 -#define MOD_EFX_PORTANOTEVOLSLIDE 0x05 -#define MOD_EFX_VIBRATOVOLSLIDE 0x06 -#define MOD_EFX_TREMOLO 0x07 -#define MOD_EFX_SAMPOFFS 0x09 -#define MOD_EFX_VOLSLIDE 0x0a -#define MOD_EFX_VOLCHNG 0x0c -#define MOD_EFX_E 0x0e - -/* MOD_EFX_E */ -#define MOD_EFXE_FILTER 0x00 -#define MOD_EFXE_FINESLIDE_UP 0x01 -#define MOD_EFXE_FINESLIDE_DOWN 0x02 -#define MOD_EFXE_GLISSANDO 0x03 -#define MOD_EFXE_VIBWAVEFORM 0x04 -#define MOD_EFXE_FINETUNE 0x05 -#define MOD_EFXE_LOOP 0x06 -#define MOD_EFXE_TREMWAVEFORM 0x07 -#define MOD_EFXE_RETRIGGER 0x09 -#define MOD_EFXE_FINEVOLSLIDE_UP 0x0a -#define MOD_EFXE_FINEVOLSLIDE_DOWN 0x0b -#define MOD_EFXE_NOTECUT 0x0c -#define MOD_EFXE_NOTEDELAY 0x0d -#define MOD_EFXE_PATTERNDELAY 0x0e -#define MOD_EFXE_INVERTEDLOOP 0x0f - - -typedef struct _ModVoice -{ - int sample; /* current sample ID */ - int noteon; /* (-1 means OFF status) */ - int period; - int efx, arg; /* Effect & Argument */ - int tune, tuneon; /* note fine tune */ - int vol, lastvol; /* current volume, last volume */ - int retrig; /* retrigger */ - int skipon; - int32 start, starttmp; /* sample offset */ - int period_start, period_todo, period_step; /* For portamento */ -} ModVoice; - -extern int get_module_type(char *fn); -extern int load_module_file(struct timidity_file *tf, int mod_type); - -extern void mod_change_tempo(int32 at, int bpm); -extern void mod_new_effect(int v, int period, int efx, int arg); -extern void mod_update_effect(int32 at, int v, int mul); -extern void mod_pitchbend(int at, int v, int tune); -extern void mod_start_note(int32 at, int v, int period); -extern void mod_period_move(int32 at, int v, int diff); -extern int period2note(int period, int *finetune); - -extern ModVoice *ModV; - -#endif /* ___MOD_H_ */ +/* + TiMidity++ -- MIDI to WAVE converter and player + Copyright (C) 1999,2000 Masanao Izumo + Copyright (C) 1995 Tuukka Toivonen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef ___MOD_H_ +#define ___MOD_H_ + +#define MOD_NUM_VOICES MAX_CHANNELS + +extern int get_module_type (char *fn); +extern int load_module_file (struct timidity_file *tf, int mod_type); +extern char *get_module_title (struct timidity_file *tf, int mod_type); + +#endif /* ___MOD_H_ */ diff -ruN TiMidity++-2.8.2/timidity/mod2midi.c TiMidity++-2.9.0/timidity/mod2midi.c --- TiMidity++-2.8.2/timidity/mod2midi.c Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/timidity/mod2midi.c Fri Feb 18 03:21:25 2000 @@ -0,0 +1,456 @@ +/* + TiMidity++ -- MIDI to WAVE converter and player + Copyright (C) 1999,2000 Masanao Izumo + Copyright (C) 1995 Tuukka Toivonen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + mod2midi.c + + Sample info -> MIDI event conversion + + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ +#ifndef NO_STRING_H +#include +#else +#include +#endif +#include "timidity.h" +#include "common.h" +#include "instrum.h" +#include "playmidi.h" +#include "readmidi.h" +#include "tables.h" +#include "mod.h" +#include "output.h" +#include "controls.h" +#include "unimod.h" +#include "mod2midi.h" + + +#define SETMIDIEVENT(e, at, t, ch, pa, pb) \ + { (e).time = (at); (e).type = (t); \ + (e).channel = (uint8)(ch); (e).a = (uint8)(pa); (e).b = (uint8)(pb); } + +#define MIDIEVENT(at, t, ch, pa, pb) \ + { MidiEvent event; SETMIDIEVENT(event, at, t, ch, pa, pb); \ + readmidi_add_event(&event); } + +/* + Clock + SampleRate := ---------- + Period + */ + + +#define NTSC_CLOCK 3579545.25 +#define NTSC_RATE (NTSC_CLOCK/428) /* <-- 428 = period for c2 */ + +#define PAL_CLOCK 3546894.6 +#define PAL_RATE (PAL_CLOCK/428) + +#define MOD_NOTE_OFFSET 60 + +#define MOD_BEND_SENSITIVE 60 + +typedef struct _ModVoice + { + int sample; /* current sample ID */ + int noteon; /* (-1 means OFF status) */ + int period; /* current frequency */ + int tuneon; /* note fine tune */ + int pan; /* current panning */ + int vol; /* current volume */ + int start; /* sample start */ + } +ModVoice; + +static void mod_change_tempo (int32 at, int bpm); +static int mod_pitch_bend (int tune); +static int period2note (int period, int *finetune); + +static ModVoice ModV[MOD_NUM_VOICES]; +static int at; + +static int period_table[84] = +{ +/* C C# D D# E F F# G G# A A# B */ +/* 0 */ 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906, +/* 1 */ 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, +/* 2 */ 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, +/* 3 */ 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, +/* 4 */ 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56, +/* 5 */ 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28, +/* 6 */ 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14 +}; + +void +mod_change_tempo (int32 at, int bpm) +{ + int32 tempo; + int c, a, b; + + tempo = 60000000 / bpm; + c = (tempo & 0xff); + a = ((tempo >> 8) & 0xff); + b = ((tempo >> 16) & 0xff); + MIDIEVENT (at, ME_TEMPO, c, b, a); +} + +int +mod_pitch_bend(int tune) +{ + int bend; + + bend = tune * (8192 / 256) / MOD_BEND_SENSITIVE + 8192; + if (bend <= 0) + bend = 1; + else if (bend >= 2 * 8192) + bend = 2 * 8192 - 1; + + return bend; +} + +int +period2note (int period, int *finetune) +{ + int note; + int l, r, m; + + if (period < 14 || period > 1712) + return -1; + + /* bin search */ + l = 0; + r = 84; + while (l < r) + { + m = (l + r) / 2; + if (period_table[m] >= period) + l = m + 1; + else + r = m; + } + note = l - 1; + + /* + * 83 >= note >= 0 + * period_table[note] >= period > period_table[note + 1] + */ + + if (period_table[note] == period) + { + *finetune = 0; + } + else + { + /* fine tune completion */ + *finetune = (int) (256.0 * + (period_table[note] - period) / + (period_table[note] - period_table[note + 1])); + } + + return note + MOD_NOTE_OFFSET; +} + +/********** Interface to mod.c */ + +void +Voice_SetVolume (UBYTE v, UWORD vol) +{ + if (v >= MOD_NUM_VOICES) + return; + + if (vol != ModV[v].vol) { + ModV[v].vol = vol; + vol = vol > 254 ? 127 : vol >> 1; + MIDIEVENT (at, ME_EXPRESSION, v, vol, 0); + } +} + +void +Voice_SetPeriod (UBYTE v, ULONG period) +{ + int tune, new_noteon, bend; + + if (v >= MOD_NUM_VOICES) + return; + + ModV[v].period = period; + new_noteon = period2note (ModV[v].period, &tune); + if (new_noteon < 0) + { + return; + } + + if (ModV[v].noteon != new_noteon) + MIDIEVENT(at, ME_NOTEOFF, v, ModV[v].noteon, 0); + + if (ModV[v].tuneon != tune) + { + ModV[v].tuneon = tune; + bend = mod_pitch_bend(tune); + MIDIEVENT (at, ME_PITCHWHEEL, v, bend & 0x7F, (bend >> 7) & 0x7F); + } + + if (ModV[v].noteon != new_noteon) + { + ModV[v].noteon = new_noteon; + MIDIEVENT(at, ME_NOTEON, v, ModV[v].noteon, 0x7f); + } +} + +void +Voice_SetPanning (UBYTE v, ULONG pan) +{ + if (v >= MOD_NUM_VOICES) + return; + if (pan == PAN_SURROUND) + pan = PAN_CENTER; /* :-( */ + + if (pan != ModV[v].pan) { + ModV[v].pan = pan; + MIDIEVENT(at, ME_PAN, v, pan * 127 / PAN_RIGHT, 0); + } +} + +void +Voice_Play (UBYTE v, SAMPLE * s, ULONG start) +{ + int tune, new_noteon, new_sample, bend; + if (v >= MOD_NUM_VOICES) + return; + + new_noteon = period2note (ModV[v].period, &tune); + new_sample = s->id; + + ModV[v].noteon = new_noteon; + if (ModV[v].noteon < 0) + { + return; + } + + if (ModV[v].sample != new_sample) + { + ModV[v].sample = new_sample; + MIDIEVENT(at, ME_SET_PATCH, v, ModV[v].sample, 0); + } + + if (ModV[v].start != start) + { + int a, b; + ModV[v].start = start; + a = (ModV[v].start & 0xff); + b = ((ModV[v].start >> 8) & 0xff); + MIDIEVENT (at, ME_PATCH_OFFS, v, a, b); + } + + if (ModV[v].tuneon != tune) + { + ModV[v].tuneon = tune; + bend = mod_pitch_bend(tune); + MIDIEVENT (at, ME_PITCHWHEEL, v, bend & 0x7F, (bend >> 7) & 0x7F); + } + + MIDIEVENT (at, ME_NOTEON, v, ModV[v].noteon, 0x7f); +} + +void +Voice_Stop (UBYTE v) +{ + if (v >= MOD_NUM_VOICES) + return; + + if (ModV[v].noteon != -1) + { + MIDIEVENT (at, ME_NOTEOFF, v, ModV[v].noteon, 0); + ModV[v].noteon = -1; + } +} + +BOOL +Voice_Stopped (UBYTE v) +{ + return (v >= MOD_NUM_VOICES) ? 1 : (ModV[v].noteon == -1); +} + +void +Voice_TickDone () +{ + at++; +} + +void +Voice_NewTempo (UWORD bpm, UWORD sngspd) +{ + mod_change_tempo(at, bpm); +} + +void +Voice_EndPlaying () +{ + int v; + + at += 48 / (60.0/125.0); /* 1 second */ + for(v = 0; v < MOD_NUM_VOICES; v++) + MIDIEVENT(at, ME_ALL_NOTES_OFF, v, 0, 0); +} + +void +Voice_StartPlaying () +{ + int v; + + readmidi_set_track(0, 1); + + current_file_info->divisions = 24; + + for(v = 0; v < MOD_NUM_VOICES; v++) + { + ModV[v].sample = -1; + ModV[v].noteon = -1; + ModV[v].period = 0; + ModV[v].tuneon = 0; + ModV[v].pan = (v & 1) ? 127 : 0; + ModV[v].vol = 64; + ModV[v].start = 0; + + MIDIEVENT(0, ME_PAN, v, ModV[v].pan, 0); + MIDIEVENT(0, ME_SET_PATCH, v, 1, 0); + MIDIEVENT(0, ME_MAINVOLUME, v, 127, 0); + MIDIEVENT(0, ME_RPN_LSB, v, 0, 0); + MIDIEVENT(0, ME_RPN_MSB, v, 0, 0); + MIDIEVENT(0, ME_DATA_ENTRY_MSB, v, MOD_BEND_SENSITIVE, 0); + MIDIEVENT(0, ME_DRUMPART, v, 0, 0); + } + + at = 1; +} + +/* convert from 8bit value to fractional offset (15.15) */ +static int32 env_offset(int offset) +{ + return (int32)offset << (7+15); +} + +/* calculate ramp rate in fractional unit; + * diff = 8bit, time = msec + */ +static int32 env_rate(int diff, double msec) +{ + double rate; + + if(msec < 6) + msec = 6; + if(diff == 0) + diff = 255; + diff <<= (7+15); + rate = ((double)diff / play_mode->rate) * control_ratio * 1000.0 / msec; + if(fast_decay) + rate *= 2; + return (int32)rate; +} + + +void load_module_samples (SAMPLE * s, int numsamples) +{ + int i; + + for(i = 1; numsamples--; i++, s++) + { + Sample *sp; + char name[23]; + + if(!s->data) + continue; + + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "MOD Sample %d (%.22s)", i, s->samplename); + + special_patch[i] = + (SpecialPatch *)safe_malloc(sizeof(SpecialPatch)); + special_patch[i]->type = INST_MOD; + special_patch[i]->samples = 1; + special_patch[i]->sample = sp = + (Sample *)safe_malloc(sizeof(Sample)); + memset(sp, 0, sizeof(Sample)); + strncpy(name, s->samplename, 22); + name[22] = '\0'; + code_convert(name, NULL, 23, NULL, "ASCII"); + if(name[0] == '\0') + special_patch[i]->name = NULL; + else + special_patch[i]->name = safe_strdup(name); + special_patch[i]->sample_offset = 0; + + sp->data = (sample_t *)s->data; + sp->data_alloced = 1; + sp->data_length = s->length; + sp->loop_start = s->loopstart; + sp->loop_end = s->loopend; + + /* Stereo instruments (SF_STEREO) are dithered by libunimod into mono */ + sp->modes = MODES_UNSIGNED; + if (s->flags & SF_SIGNED) sp->modes ^= MODES_UNSIGNED; + if (s->flags & SF_LOOP) sp->modes ^= MODES_LOOPING; + if (s->flags & SF_BIDI) sp->modes ^= MODES_PINGPONG; + if (s->flags & SF_REVERSE) sp->modes ^= MODES_REVERSE; + if (s->flags & SF_16BITS) sp->modes ^= MODES_16BIT; + + /* libunimod sets *both* SF_LOOP and SF_BIDI/SF_REVERSE */ + if (sp->modes & (MODES_PINGPONG | MODES_REVERSE)) + sp->modes &= ~MODES_LOOPING; + + /* envelope (0,1:attack, 2:sustain, 3,4,5:release) */ + sp->modes |= MODES_ENVELOPE; + /* attack */ + sp->envelope_offset[0] = env_offset(255); + sp->envelope_rate[0] = env_rate(255, 0.0); /* fastest */ + sp->envelope_offset[1] = sp->envelope_offset[0]; + sp->envelope_rate[1] = 0; /* skip this stage */ + /* sustain */ + sp->envelope_offset[2] = sp->envelope_offset[1]; + sp->envelope_rate[2] = 0; + /* release */ + sp->envelope_offset[3] = env_offset(0); + sp->envelope_rate[3] = env_rate(255, 200.0); /* 200 msec */ + sp->envelope_offset[4] = sp->envelope_offset[3]; + sp->envelope_rate[4] = 0; /* skip this stage */ + sp->envelope_offset[5] = sp->envelope_offset[4]; + sp->envelope_rate[5] = 0; /* skip this stage, then the voice is + disappeared */ + + sp->sample_rate = ((int32)PAL_RATE) >> s->divfactor; + sp->low_freq = 0; + sp->high_freq = 0x7fffffff; + sp->root_freq = freq_table[MOD_NOTE_OFFSET]; + sp->volume = 1.0; /* I guess it should use globvol... */ + sp->panning = s->panning == PAN_SURROUND ? 64 : s->panning * 128 / 255; + sp->low_vel = 0; + sp->high_vel = 127; + sp->data_length <<= FRACTION_BITS; + sp->loop_start <<= FRACTION_BITS; + sp->loop_end <<= FRACTION_BITS; + + s->data = NULL; /* Avoid free-ing */ + s->id = i; + } +} + +/* ex:set ts=4: */ diff -ruN TiMidity++-2.8.2/timidity/mod2midi.h TiMidity++-2.9.0/timidity/mod2midi.h --- TiMidity++-2.8.2/timidity/mod2midi.h Thu Jan 1 09:00:00 1970 +++ TiMidity++-2.9.0/timidity/mod2midi.h Sat Feb 19 20:51:18 2000 @@ -0,0 +1,39 @@ +/* + TiMidity++ -- MIDI to WAVE converter and player + Copyright (C) 1999,2000 Masanao Izumo + Copyright (C) 1995 Tuukka Toivonen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + mod2midi.h + + Header file for sample info -> MIDI event conversion + + */ + +#include "unimod.h" + +void Voice_SetVolume (UBYTE, UWORD); +void Voice_SetFrequency (UBYTE, ULONG); +void Voice_SetPanning (UBYTE, ULONG); +void Voice_Play (UBYTE, SAMPLE *, ULONG); +void Voice_Stop (UBYTE); +BOOL Voice_Stopped (UBYTE); +void Voice_NewTempo (UWORD, UWORD); +void Voice_TickDone (); +void Voice_StartPlaying (); +void Voice_EndPlaying (); +void load_module_samples (SAMPLE *, int); +void Voice_SetPeriod (UBYTE v, ULONG period); diff -ruN TiMidity++-2.8.2/timidity/playmidi.c TiMidity++-2.9.0/timidity/playmidi.c --- TiMidity++-2.8.2/timidity/playmidi.c Mon Feb 7 07:57:24 2000 +++ TiMidity++-2.9.0/timidity/playmidi.c Sat Feb 19 22:40:30 2000 @@ -293,7 +293,7 @@ { int i; - if(opt_overlap_voice_allow) + if(opt_overlap_voice_allow && !IS_CURRENT_MOD_FILE) { i = ch * 128 + note; return vidq_head[i]++; @@ -305,7 +305,7 @@ { int i; - if(opt_overlap_voice_allow) + if(opt_overlap_voice_allow && !IS_CURRENT_MOD_FILE) { i = ch * 128 + note; if(vidq_head[i] == vidq_tail[i]) @@ -1142,7 +1142,7 @@ note = MIDI_EVENT_NOTE(e); ch = e->channel; - if(opt_overlap_voice_allow) + if(opt_overlap_voice_allow && !IS_CURRENT_MOD_FILE) status_check = (VOICE_OFF | VOICE_SUSTAINED); else status_check = 0xFF; @@ -1308,7 +1308,12 @@ channel[ch].special_sample); return 0; } - return select_play_sample(s->sample, s->samples, e->a, vlist, e); + note = e->a + note_key_offset; + if(note < 0) + note = 0; + else if(note > 127) + note = 127; + return select_play_sample(s->sample, s->samples, note, vlist, e); } bk = channel[ch].bank; @@ -4146,8 +4151,9 @@ { /* Update bank information */ midi_program_change(ch, channel[ch].program); + ctl_mode_event(CTLE_DRUMPART, 1, ch, ISDRUMCHANNEL(ch)); + ctl_prog_event(ch); } - ctl_prog_event(ch); break; case ME_KEYSHIFT: @@ -4598,10 +4604,26 @@ static void ctl_prog_event(int ch) { CtlEvent ce; + int bank, prog; + + if(IS_CURRENT_MOD_FILE) + { + bank = 0; + prog = channel[ch].special_sample; + } + else + { + bank = channel[ch].bank; + prog = channel[ch].program; + } + ce.type = CTLE_PROGRAM; ce.v1 = ch; - ce.v2 = channel[ch].program; + ce.v2 = prog; ce.v3 = (long)channel_instrum_name(ch); + ce.v4 = (bank | + (channel[ch].bank_lsb << 8) | + (channel[ch].bank_msb << 16)); if(ctl->trace_playing) push_midi_trace_ce(ctl->event, &ce); else @@ -4618,7 +4640,7 @@ char *channel_instrum_name(int ch) { char *comm; - int bank; + int bank, prog; if(ISDRUMCHANNEL(ch)) return ""; @@ -4637,11 +4659,13 @@ } bank = channel[ch].bank; + prog = channel[ch].program; + instrument_map(channel[ch].mapID, &bank, &prog); if(tonebank[bank] == NULL) bank = 0; - comm = tonebank[bank]->tone[channel[ch].program].comment; + comm = tonebank[bank]->tone[prog].comment; if(comm == NULL) - comm = tonebank[0]->tone[channel[ch].program].comment; + comm = tonebank[0]->tone[prog].comment; return comm; } diff -ruN TiMidity++-2.8.2/timidity/readmidi.c TiMidity++-2.9.0/timidity/readmidi.c --- TiMidity++-2.8.2/timidity/readmidi.c Mon Feb 7 07:57:09 2000 +++ TiMidity++-2.9.0/timidity/readmidi.c Fri Feb 18 11:27:56 2000 @@ -2606,9 +2606,9 @@ if(tf == NULL) return NULL; + mtype = get_module_type(filename); check_cache = check_need_cache(tf->url, filename); - - if(check_cache) + if(check_cache || mtype > 0) { if(!IS_URL_SEEK_SAFE(tf->url)) { @@ -2620,17 +2620,19 @@ } } - if((mtype = get_module_type(filename)) > 0) + if(mtype > 0) { - char title[32], *str; + char *title, *str; - switch(mtype) + title = get_module_title(tf, mtype); + if(title == NULL) { - case IS_MOD_FILE: - tf_read(title, 1, 20, tf); - title[19] = '\0'; - break; + /* No title */ + p->seq_name = NULL; + p->format = 0; + goto end_of_parse; } + len = (int32)strlen(title); len = SAFE_CONVERT_LENGTH(len); str = (char *)new_segment(&tmpbuffer, len); @@ -2638,6 +2640,7 @@ p->seq_name = (char *)safe_strdup(str); reuse_mblock(&tmpbuffer); p->format = 0; + free (title); goto end_of_parse; } diff -ruN TiMidity++-2.8.2/timidity/resample.c TiMidity++-2.9.0/timidity/resample.c --- TiMidity++-2.8.2/timidity/resample.c Mon Feb 7 14:17:18 2000 +++ TiMidity++-2.9.0/timidity/resample.c Mon Feb 21 10:20:22 2000 @@ -117,7 +117,8 @@ # define INTERPVARS #endif -#define FINALINTERP if (ofs == le) *dest++=src[(ofs>>FRACTION_BITS)-1]/2; +/* #define FINALINTERP if (ofs < le) *dest++=src[(ofs>>FRACTION_BITS)-1]/2; */ +#define FINALINTERP /* Nothing to do after TiMidity++ 2.9.0 */ /* So it isn't interpolation. At least it's final. */ static sample_t resample_buffer[AUDIO_BUFFER_SIZE]; diff -ruN TiMidity++-2.8.2/timidity/timidity.c TiMidity++-2.9.0/timidity/timidity.c --- TiMidity++-2.8.2/timidity/timidity.c Mon Feb 7 07:35:40 2000 +++ TiMidity++-2.9.0/timidity/timidity.c Fri Feb 18 10:19:50 2000 @@ -76,6 +76,7 @@ #include "mid.defs" #include "aq.h" #include "mix.h" +#include "unimod.h" #ifdef IA_W32GUI #include "w32g.h" @@ -2835,6 +2836,7 @@ init_midi_trace(); int_rand(-1); /* initialize random seed */ int_rand(42); /* the 1st number generated is not very random */ + ML_RegisterAllLoaders (); } is_first = 0;