diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
commit | 26f2bfde03420edad4de1f22cb3d515dc063b20d (patch) | |
tree | 4a8c4abaf4795f38da70a4657c1a0fb3ba9debeb /apps/plugins/mikmod/munitrk.c | |
parent | d192bdf11e06e50645ecb5726658d4b691480a9a (diff) | |
download | rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.gz rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.zip |
Add MikMod plugin, ported by Jason Yu, with some minor work by Craig Mann and William Peters (FS#8806)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28810 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mikmod/munitrk.c')
-rw-r--r-- | apps/plugins/mikmod/munitrk.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/munitrk.c b/apps/plugins/mikmod/munitrk.c new file mode 100644 index 0000000000..f0a8f58af7 --- /dev/null +++ b/apps/plugins/mikmod/munitrk.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS | ||
3 | for complete list. | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU Library General Public License as | ||
7 | published by the Free Software Foundation; either version 2 of | ||
8 | the License, or (at your option) any later version. | ||
9 | |||
10 | This program 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 | ||
13 | GNU Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library 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 | ||
18 | 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /*============================================================================== | ||
22 | |||
23 | $Id: munitrk.c,v 1.2 2005/03/30 19:11:46 realtech Exp $ | ||
24 | |||
25 | All routines dealing with the manipulation of UNITRK streams | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #include "mikmod_internals.h" | ||
34 | |||
35 | #include <string.h> | ||
36 | |||
37 | /* Unibuffer chunk size */ | ||
38 | #define BUFPAGE 128 | ||
39 | |||
40 | UWORD unioperands[UNI_LAST]={ | ||
41 | 0, /* not used */ | ||
42 | 1, /* UNI_NOTE */ | ||
43 | 1, /* UNI_INSTRUMENT */ | ||
44 | 1, /* UNI_PTEFFECT0 */ | ||
45 | 1, /* UNI_PTEFFECT1 */ | ||
46 | 1, /* UNI_PTEFFECT2 */ | ||
47 | 1, /* UNI_PTEFFECT3 */ | ||
48 | 1, /* UNI_PTEFFECT4 */ | ||
49 | 1, /* UNI_PTEFFECT5 */ | ||
50 | 1, /* UNI_PTEFFECT6 */ | ||
51 | 1, /* UNI_PTEFFECT7 */ | ||
52 | 1, /* UNI_PTEFFECT8 */ | ||
53 | 1, /* UNI_PTEFFECT9 */ | ||
54 | 1, /* UNI_PTEFFECTA */ | ||
55 | 1, /* UNI_PTEFFECTB */ | ||
56 | 1, /* UNI_PTEFFECTC */ | ||
57 | 1, /* UNI_PTEFFECTD */ | ||
58 | 1, /* UNI_PTEFFECTE */ | ||
59 | 1, /* UNI_PTEFFECTF */ | ||
60 | 1, /* UNI_S3MEFFECTA */ | ||
61 | 1, /* UNI_S3MEFFECTD */ | ||
62 | 1, /* UNI_S3MEFFECTE */ | ||
63 | 1, /* UNI_S3MEFFECTF */ | ||
64 | 1, /* UNI_S3MEFFECTI */ | ||
65 | 1, /* UNI_S3MEFFECTQ */ | ||
66 | 1, /* UNI_S3MEFFECTR */ | ||
67 | 1, /* UNI_S3MEFFECTT */ | ||
68 | 1, /* UNI_S3MEFFECTU */ | ||
69 | 0, /* UNI_KEYOFF */ | ||
70 | 1, /* UNI_KEYFADE */ | ||
71 | 2, /* UNI_VOLEFFECTS */ | ||
72 | 1, /* UNI_XMEFFECT4 */ | ||
73 | 1, /* UNI_XMEFFECT6 */ | ||
74 | 1, /* UNI_XMEFFECTA */ | ||
75 | 1, /* UNI_XMEFFECTE1 */ | ||
76 | 1, /* UNI_XMEFFECTE2 */ | ||
77 | 1, /* UNI_XMEFFECTEA */ | ||
78 | 1, /* UNI_XMEFFECTEB */ | ||
79 | 1, /* UNI_XMEFFECTG */ | ||
80 | 1, /* UNI_XMEFFECTH */ | ||
81 | 1, /* UNI_XMEFFECTL */ | ||
82 | 1, /* UNI_XMEFFECTP */ | ||
83 | 1, /* UNI_XMEFFECTX1 */ | ||
84 | 1, /* UNI_XMEFFECTX2 */ | ||
85 | 1, /* UNI_ITEFFECTG */ | ||
86 | 1, /* UNI_ITEFFECTH */ | ||
87 | 1, /* UNI_ITEFFECTI */ | ||
88 | 1, /* UNI_ITEFFECTM */ | ||
89 | 1, /* UNI_ITEFFECTN */ | ||
90 | 1, /* UNI_ITEFFECTP */ | ||
91 | 1, /* UNI_ITEFFECTT */ | ||
92 | 1, /* UNI_ITEFFECTU */ | ||
93 | 1, /* UNI_ITEFFECTW */ | ||
94 | 1, /* UNI_ITEFFECTY */ | ||
95 | 2, /* UNI_ITEFFECTZ */ | ||
96 | 1, /* UNI_ITEFFECTS0 */ | ||
97 | 2, /* UNI_ULTEFFECT9 */ | ||
98 | 2, /* UNI_MEDSPEED */ | ||
99 | 0, /* UNI_MEDEFFECTF1 */ | ||
100 | 0, /* UNI_MEDEFFECTF2 */ | ||
101 | 0, /* UNI_MEDEFFECTF3 */ | ||
102 | 2, /* UNI_OKTARP */ | ||
103 | }; | ||
104 | |||
105 | /* Sparse description of the internal module format | ||
106 | ------------------------------------------------ | ||
107 | |||
108 | A UNITRK stream is an array of bytes representing a single track of a pattern. | ||
109 | It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly | ||
110 | language): | ||
111 | |||
112 | rrrlllll | ||
113 | [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND].. | ||
114 | ^ ^ ^ | ||
115 | |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track... | ||
116 | |||
117 | The rep/len byte contains the number of bytes in the current row, _including_ | ||
118 | the length byte itself (So the LENGTH byte of row 0 in the previous example | ||
119 | would have a value of 5). This makes it easy to search through a stream for a | ||
120 | particular row. A track is concluded by a 0-value length byte. | ||
121 | |||
122 | The upper 3 bits of the rep/len byte contain the number of times -1 this row | ||
123 | is repeated for this track. (so a value of 7 means this row is repeated 8 times) | ||
124 | |||
125 | Opcodes can range from 1 to 255 but currently only opcodes 1 to 62 are being | ||
126 | used. Each opcode can have a different number of operands. You can find the | ||
127 | number of operands to a particular opcode by using the opcode as an index into | ||
128 | the 'unioperands' table. | ||
129 | |||
130 | */ | ||
131 | |||
132 | /*========== Reading routines */ | ||
133 | |||
134 | static UBYTE *rowstart; /* startadress of a row */ | ||
135 | static UBYTE *rowend; /* endaddress of a row (exclusive) */ | ||
136 | static UBYTE *rowpc; /* current unimod(tm) programcounter */ | ||
137 | |||
138 | static UBYTE lastbyte; /* for UniSkipOpcode() */ | ||
139 | |||
140 | void UniSetRow(UBYTE* t) | ||
141 | { | ||
142 | rowstart = t; | ||
143 | rowpc = rowstart; | ||
144 | rowend = t?rowstart+(*(rowpc++)&0x1f):t; | ||
145 | } | ||
146 | |||
147 | UBYTE UniGetByte(void) | ||
148 | { | ||
149 | return lastbyte = (rowpc<rowend)?*(rowpc++):0; | ||
150 | } | ||
151 | |||
152 | UWORD UniGetWord(void) | ||
153 | { | ||
154 | return ((UWORD)UniGetByte()<<8)|UniGetByte(); | ||
155 | } | ||
156 | |||
157 | void UniSkipOpcode(void) | ||
158 | { | ||
159 | if (lastbyte < UNI_LAST) { | ||
160 | UWORD t = unioperands[lastbyte]; | ||
161 | |||
162 | while (t--) | ||
163 | UniGetByte(); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | /* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns | ||
168 | NULL if the row can't be found. */ | ||
169 | UBYTE *UniFindRow(UBYTE* t,UWORD row) | ||
170 | { | ||
171 | UBYTE c,l; | ||
172 | |||
173 | if(t) | ||
174 | while(1) { | ||
175 | c = *t; /* get rep/len byte */ | ||
176 | if(!c) return NULL; /* zero ? -> end of track.. */ | ||
177 | l = (c>>5)+1; /* extract repeat value */ | ||
178 | if(l>row) break; /* reached wanted row? -> return pointer */ | ||
179 | row -= l; /* haven't reached row yet.. update row */ | ||
180 | t += c&0x1f; /* point t to the next row */ | ||
181 | } | ||
182 | return t; | ||
183 | } | ||
184 | |||
185 | /*========== Writing routines */ | ||
186 | |||
187 | static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */ | ||
188 | static UWORD unimax; /* buffer size */ | ||
189 | |||
190 | static UWORD unipc; /* buffer cursor */ | ||
191 | static UWORD unitt; /* current row index */ | ||
192 | static UWORD lastp; /* previous row index */ | ||
193 | |||
194 | /* Resets index-pointers to create a new track. */ | ||
195 | void UniReset(void) | ||
196 | { | ||
197 | unitt = 0; /* reset index to rep/len byte */ | ||
198 | unipc = 1; /* first opcode will be written to index 1 */ | ||
199 | lastp = 0; /* no previous row yet */ | ||
200 | unibuf[0] = 0; /* clear rep/len byte */ | ||
201 | } | ||
202 | |||
203 | /* Expands the buffer */ | ||
204 | static int UniExpand(int wanted) | ||
205 | { | ||
206 | if ((unipc+wanted)>=unimax) { | ||
207 | UBYTE *newbuf; | ||
208 | |||
209 | /* Expand the buffer by BUFPAGE bytes */ | ||
210 | newbuf=(UBYTE*)MikMod_realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE)); | ||
211 | |||
212 | /* Check if MikMod_realloc succeeded */ | ||
213 | if(newbuf) { | ||
214 | unibuf = newbuf; | ||
215 | unimax+=BUFPAGE; | ||
216 | return 1; | ||
217 | } else | ||
218 | return 0; | ||
219 | } | ||
220 | return 1; | ||
221 | } | ||
222 | |||
223 | /* Appends one byte of data to the current row of a track. */ | ||
224 | void UniWriteByte(UBYTE data) | ||
225 | { | ||
226 | if (UniExpand(1)) | ||
227 | /* write byte to current position and update */ | ||
228 | unibuf[unipc++]=data; | ||
229 | } | ||
230 | |||
231 | void UniWriteWord(UWORD data) | ||
232 | { | ||
233 | if (UniExpand(2)) { | ||
234 | unibuf[unipc++]=data>>8; | ||
235 | unibuf[unipc++]=data&0xff; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static int MyCmp(UBYTE* a,UBYTE* b,UWORD l) | ||
240 | { | ||
241 | UWORD t; | ||
242 | |||
243 | for(t=0;t<l;t++) | ||
244 | if(*(a++)!=*(b++)) return 0; | ||
245 | return 1; | ||
246 | } | ||
247 | |||
248 | /* Closes the current row of a unitrk stream (updates the rep/len byte) and sets | ||
249 | pointers to start a new row. */ | ||
250 | void UniNewline(void) | ||
251 | { | ||
252 | UWORD n,l,len; | ||
253 | |||
254 | n = (unibuf[lastp]>>5)+1; /* repeat of previous row */ | ||
255 | l = (unibuf[lastp]&0x1f); /* length of previous row */ | ||
256 | |||
257 | len = unipc-unitt; /* length of current row */ | ||
258 | |||
259 | /* Now, check if the previous and the current row are identical.. when they | ||
260 | are, just increase the repeat field of the previous row */ | ||
261 | if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) { | ||
262 | unibuf[lastp]+=0x20; | ||
263 | unipc = unitt+1; | ||
264 | } else { | ||
265 | if (UniExpand(unitt-unipc)) { | ||
266 | /* current and previous row aren't equal... update the pointers */ | ||
267 | unibuf[unitt] = len; | ||
268 | lastp = unitt; | ||
269 | unitt = unipc++; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* Terminates the current unitrk stream and returns a pointer to a copy of the | ||
275 | stream. */ | ||
276 | UBYTE* UniDup(void) | ||
277 | { | ||
278 | UBYTE *d; | ||
279 | |||
280 | if (!UniExpand(unitt-unipc)) return NULL; | ||
281 | unibuf[unitt] = 0; | ||
282 | |||
283 | if(!(d=(UBYTE *)MikMod_malloc(unipc))) return NULL; | ||
284 | memcpy(d,unibuf,unipc); | ||
285 | |||
286 | return d; | ||
287 | } | ||
288 | |||
289 | int UniInit(void) | ||
290 | { | ||
291 | unimax = BUFPAGE; | ||
292 | |||
293 | if(!(unibuf=(UBYTE*)MikMod_malloc(unimax*sizeof(UBYTE)))) return 0; | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | void UniCleanup(void) | ||
298 | { | ||
299 | if(unibuf) MikMod_free(unibuf); | ||
300 | unibuf = NULL; | ||
301 | } | ||
302 | |||
303 | /* ex:set ts=4: */ | ||