1 /*
2  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3  * Copyright (C) 1999 - 2008 Simon Peter, <dn.tlp@gmx.net>, et al.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * sa2.cpp - SAdT2 Loader by Simon Peter <dn.tlp@gmx.net>
20  *           SAdT Loader by Mamiya <mamiya@users.sourceforge.net>
21  */
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "sa2.h"
27 #include "debug.h"
28 
factory(Copl * newopl)29 CPlayer *Csa2Loader::factory(Copl *newopl)
30 {
31   return new Csa2Loader(newopl);
32 }
33 
load(const char * filename,const CFileProvider & fp)34 bool Csa2Loader::load(const char *filename, const CFileProvider &fp)
35 {
36   binistream *f = fp.open(filename); if(!f) return false;
37   struct {
38     unsigned char data[11],arpstart,arpspeed,arppos,arpspdcnt;
39   } insts;
40   unsigned char buf;
41   int i,j, k, notedis = 0;
42   const unsigned char convfx[16] = {0,1,2,3,4,5,6,255,8,255,10,11,12,13,255,15};
43   unsigned char sat_type;
44   enum SAT_TYPE {
45     HAS_ARPEGIOLIST = (1 << 7),
46     HAS_V7PATTERNS = (1 << 6),
47     HAS_ACTIVECHANNELS = (1 << 5),
48     HAS_TRACKORDER = (1 << 4),
49     HAS_ARPEGIO = (1 << 3),
50     HAS_OLDBPM = (1 << 2),
51     HAS_OLDPATTERNS = (1 << 1),
52     HAS_UNKNOWN127 = (1 << 0)
53   };
54 
55   // read header
56   f->readString(header.sadt, 4);
57   header.version = f->readInt(1);
58 
59   // file validation section
60   if(strncmp(header.sadt,"SAdT",4)) { fp.close(f); return false; }
61   switch(header.version) {
62   case 1:
63     notedis = +0x18;
64     sat_type = HAS_UNKNOWN127 | HAS_OLDPATTERNS | HAS_OLDBPM;
65     break;
66   case 2:
67     notedis = +0x18;
68     sat_type = HAS_OLDPATTERNS | HAS_OLDBPM;
69     break;
70   case 3:
71     notedis = +0x0c;
72     sat_type = HAS_OLDPATTERNS | HAS_OLDBPM;
73     break;
74   case 4:
75     notedis = +0x0c;
76     sat_type = HAS_ARPEGIO | HAS_OLDPATTERNS | HAS_OLDBPM;
77     break;
78   case 5:
79     notedis = +0x0c;
80     sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM;
81     break;
82   case 6:
83     sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM;
84     break;
85   case 7:
86     sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_V7PATTERNS;
87     break;
88   case 8:
89     sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER;
90     break;
91   case 9:
92     sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER | HAS_ACTIVECHANNELS;
93     break;
94   default:	/* unknown */
95     fp.close(f);
96     return false;
97   }
98 
99   // load section
100   // instruments
101   for(i = 0; i < 31; i++) {
102     if(sat_type & HAS_ARPEGIO) {
103       for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1);
104       insts.arpstart = f->readInt(1);
105       insts.arpspeed = f->readInt(1);
106       insts.arppos = f->readInt(1);
107       insts.arpspdcnt = f->readInt(1);
108       inst[i].arpstart = insts.arpstart;
109       inst[i].arpspeed = insts.arpspeed;
110       inst[i].arppos = insts.arppos;
111       inst[i].arpspdcnt = insts.arpspdcnt;
112     } else {
113       for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1);
114       inst[i].arpstart = 0;
115       inst[i].arpspeed = 0;
116       inst[i].arppos = 0;
117       inst[i].arpspdcnt = 0;
118     }
119     for(j=0;j<11;j++)
120       inst[i].data[j] = insts.data[j];
121     inst[i].misc = 0;
122     inst[i].slide = 0;
123   }
124 
125   // instrument names
126   for(i = 0; i < 29; i++) f->readString(instname[i], 17);
127 
128   f->ignore(3);		// dummy bytes
129   for(i = 0; i < 128; i++) order[i] = f->readInt(1);	// pattern orders
130   if(sat_type & HAS_UNKNOWN127) f->ignore(127);
131 
132   // infos
133   nop = f->readInt(2); length = f->readInt(1); restartpos = f->readInt(1);
134 
135   // bpm
136   bpm = f->readInt(2);
137   if(sat_type & HAS_OLDBPM) {
138     bpm = bpm * 125 / 50;		// cps -> bpm
139   }
140 
141   if(sat_type & HAS_ARPEGIOLIST) {
142     init_specialarp();
143     for(i = 0; i < 256; i++) arplist[i] = f->readInt(1);	// arpeggio list
144     for(i = 0; i < 256; i++) arpcmd[i] = f->readInt(1);	// arpeggio commands
145   }
146 
147   for(i=0;i<64;i++) {				// track orders
148     for(j=0;j<9;j++) {
149       if(sat_type & HAS_TRACKORDER)
150 	trackord[i][j] = f->readInt(1);
151       else
152 	{
153 	  trackord[i][j] = i * 9 + j;
154 	}
155     }
156   }
157 
158   if(sat_type & HAS_ACTIVECHANNELS)
159     activechan = f->readInt(2) << 16;		// active channels
160 
161   AdPlug_LogWrite("Csa2Loader::load(\"%s\"): sat_type = %x, nop = %d, "
162 		  "length = %d, restartpos = %d, activechan = %x, bpm = %d\n",
163 		  filename, sat_type, nop, length, restartpos, activechan, bpm);
164 
165   // track data
166   if(sat_type & HAS_OLDPATTERNS) {
167     i = 0;
168     while(!f->ateof()) {
169       for(j=0;j<64;j++) {
170 	for(k=0;k<9;k++) {
171 	  buf = f->readInt(1);
172 	  tracks[i+k][j].note = buf ? (buf + notedis) : 0;
173 	  tracks[i+k][j].inst = f->readInt(1);
174 	  tracks[i+k][j].command = convfx[f->readInt(1) & 0xf];
175 	  tracks[i+k][j].param1 = f->readInt(1);
176 	  tracks[i+k][j].param2 = f->readInt(1);
177 	}
178       }
179       i+=9;
180     }
181   } else
182     if(sat_type & HAS_V7PATTERNS) {
183       i = 0;
184       while(!f->ateof()) {
185 	for(j=0;j<64;j++) {
186 	  for(k=0;k<9;k++) {
187 	    buf = f->readInt(1);
188 	    tracks[i+k][j].note = buf >> 1;
189 	    tracks[i+k][j].inst = (buf & 1) << 4;
190 	    buf = f->readInt(1);
191 	    tracks[i+k][j].inst += buf >> 4;
192 	    tracks[i+k][j].command = convfx[buf & 0x0f];
193 	    buf = f->readInt(1);
194 	    tracks[i+k][j].param1 = buf >> 4;
195 	    tracks[i+k][j].param2 = buf & 0x0f;
196 	  }
197 	}
198 	i+=9;
199       }
200     } else {
201       i = 0;
202       while(!f->ateof()) {
203 	for(j=0;j<64;j++) {
204 	  buf = f->readInt(1);
205 	  tracks[i][j].note = buf >> 1;
206 	  tracks[i][j].inst = (buf & 1) << 4;
207 	  buf = f->readInt(1);
208 	  tracks[i][j].inst += buf >> 4;
209 	  tracks[i][j].command = convfx[buf & 0x0f];
210 	  buf = f->readInt(1);
211 	  tracks[i][j].param1 = buf >> 4;
212 	  tracks[i][j].param2 = buf & 0x0f;
213 	}
214 	i++;
215       }
216     }
217   fp.close(f);
218 
219   // fix instrument names
220   for(i=0;i<29;i++)
221     for(j=0;j<17;j++)
222       if(!instname[i][j])
223 	instname[i][j] = ' ';
224 
225   rewind(0);		// rewind module
226   return true;
227 }
228 
gettype()229 const char * Csa2Loader::gettype()
230 {
231   snprintf(filetype,sizeof(filetype),"Surprise! Adlib Tracker 2 (version %d)",header.version);
232   return filetype;
233 }
234 
gettitle()235 const char * Csa2Loader::gettitle()
236 {
237   char bufinst[29*17],buf[18];
238   int i,ptr;
239 
240   // parse instrument names for song name
241   memset(bufinst,'\0',29*17);
242   for(i=0;i<29;i++) {
243     buf[16] = ' '; buf[17] = '\0';
244     memcpy(buf,instname[i]+1,16);
245     for(ptr=16;ptr>0;ptr--)
246       if(buf[ptr] == ' ')
247 	buf[ptr] = '\0';
248       else {
249 	if(ptr<16)
250 	  buf[ptr+1] = ' ';
251 	break;
252       }
253     strcat(bufinst,buf);
254   }
255 
256   if(strchr(bufinst,'"')) {
257       const char *pos = strchr(bufinst,'"')+1;
258       int len = strrchr(bufinst,'"')-pos;
259       memcpy (title,pos,len);
260       title[len] = 0;
261       return title;
262   }
263   return "";
264 }
265