1 /* OpenCP Module Player
2 * copyright (c) '94-'21 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * GMDPlay loader for Oktalyzer modules
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * revision history: (please note changes here)
21 * -nb980510 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
22 * -first release
23 */
24
25 #include "config.h"
26 #include <sys/types.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include "types.h"
31 #include "boot/plinkman.h"
32 #include "dev/mcp.h"
33 #include "filesel/filesystem.h"
34 #include "gmdplay.h"
35 #include "stuff/err.h"
36
putcmd(uint8_t ** p,uint8_t c,uint8_t d)37 static inline void putcmd(uint8_t **p, uint8_t c, uint8_t d)
38 {
39 *(*p)++=c;
40 *(*p)++=d;
41 }
42
43 struct LoadOKTResources
44 {
45 uint8_t *temptrack;
46 uint8_t *buffer;
47 };
48
FreeResources(struct LoadOKTResources * r)49 static void FreeResources(struct LoadOKTResources *r)
50 {
51 if (r->temptrack)
52 {
53 free(r->temptrack);
54 r->temptrack = 0;
55 }
56 if (r->buffer)
57 {
58 free(r->buffer);
59 r->buffer = 0;
60 }
61 }
62
_mpLoadOKT(struct gmdmodule * m,struct ocpfilehandle_t * file)63 static int _mpLoadOKT(struct gmdmodule *m, struct ocpfilehandle_t *file)
64 {
65
66 uint8_t hsig[8];
67 struct __attribute__((packed))
68 {
69 uint8_t sig[4];
70 uint32_t blen;
71 } chunk;
72 uint16_t cflags[4];
73 uint8_t cflag2[8];
74 unsigned int i,t;
75 uint16_t orgticks;
76 uint16_t pn;
77 uint16_t ordn;
78 uint8_t orders[128];
79 struct gmdpattern *pp;
80 struct LoadOKTResources r;
81
82 r.temptrack = 0;
83 r.buffer = 0;
84
85 mpReset(m);
86
87 if (file->read (file, hsig, 8) != 8)
88 {
89 fprintf(stderr, __FILE__ ": read failed #1\n");
90 return errFormSig;
91 }
92 #ifdef OKT_LOAD_DEBUG
93 fprintf(stderr, __FILE__ ": comparing sig \"%c%c%c%c%c%c%c%c\" against \"OKTASONG\"\n", hsig[0], hsig[1], hsig[2], hsig[3], hsig[4], hsig[5], hsig[6], hsig[7]);
94 #endif
95 if (memcmp(hsig, "OKTASONG", 8))
96 {
97 fprintf(stderr, __FILE__ ": invalid header\n");
98 return errFormSig;
99 }
100
101 *m->name=0;
102 m->message=0;
103
104 m->options=MOD_TICK0;
105
106 if (file->read (file, &chunk, sizeof(chunk)) != sizeof(chunk))
107 {
108 fprintf(stderr, __FILE__ ": read failed #3\n");
109 return errFormStruc;
110 }
111 #ifdef OKT_LOAD_DEBUG
112 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"CMOD\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
113 #endif
114 if (memcmp(chunk.sig, "CMOD", 4))
115 {
116 fprintf(stderr, __FILE__ ": invalid \"SAMP\" header\n");
117 return errFormStruc;
118 }
119 chunk.blen=uint32_big(chunk.blen);
120 if (chunk.blen!=8)
121 {
122 fprintf(stderr, __FILE__ ": invalid blen %d, should had been 8\n", (int)chunk.blen);
123 return errFormStruc;
124 }
125 if (file->read (file, cflags, 8) != 8)
126 {
127 fprintf(stderr, __FILE__ ": read failed #4\n");
128 return errFormStruc;
129 }
130 #ifdef OKT_LOAD_DEBUG
131 fprintf(stderr, __FILE__ ": chan_flags[4]: 0x%04x 0x%04x 0x%04x 0x%04x\n", uint16_big(cflags[0]), uint16_big(cflags[1]), uint16_big(cflags[2]), uint16_big(cflags[3]));
132 #endif
133 t=0;
134 for (i=0; i<4; i++)
135 {
136 cflag2[t]=(uint16_big(cflags[i])&1)|((i+i+i)&2);
137 if (cflag2[t++]&1)
138 cflag2[t++]=(uint16_big(cflags[i])&1)|((i+i+i)&2);
139 }
140 m->channum=t;
141 #ifdef OKT_LOAD_DEBUG
142 fprintf(stderr, __FILE__ ": channels: %d\n", (int)t);
143 fprintf(stderr, __FILE__ ": %d %d %d %d %d %d %d %d\n", (int)cflag2[0], (int)cflag2[1], (int)cflag2[2], (int)cflag2[3], (int)cflag2[4], (int)cflag2[5], (int)cflag2[6], (int)cflag2[7]);
144 #endif
145
146 if (file->read (file, &chunk, sizeof(chunk)) != sizeof (chunk))
147 {
148 fprintf(stderr, __FILE__ ": read failed #5\n");
149 return errFormStruc;
150 }
151 #ifdef OKT_LOAD_DEBUG
152 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"SAMP\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
153 #endif
154 if (memcmp(chunk.sig, "SAMP", 4))
155 {
156 fprintf(stderr, __FILE__ ": invalid \"SAMP\" header\n");
157 return errFormStruc;
158 }
159 chunk.blen=uint32_big(chunk.blen);
160 #ifdef OKT_LOAD_DEBUG
161 fprintf(stderr, __FILE__ ": checking chunk length.. samples=%d module=%d (last should be zero)\n", (int)chunk.blen/32, (int)chunk.blen%32);
162 #endif
163 if (chunk.blen&31)
164 {
165 fprintf(stderr, __FILE__ ": invalid SAMP chunk length (modulo 32 test failed)\n");
166 return errFormStruc;
167 }
168 m->modsampnum=m->sampnum=m->instnum=(chunk.blen)>>5;
169
170 if (!mpAllocInstruments(m, m->instnum)||!mpAllocSamples(m, m->sampnum)||!mpAllocModSamples(m, m->modsampnum))
171 return errAllocMem;
172
173 for (i=0; i<m->instnum; i++)
174 {
175 struct gmdinstrument *ip;
176 struct gmdsample *sp;
177 struct sampleinfo *sip;
178
179 struct __attribute__((packed))
180 {
181 char name[20];
182 uint32_t length;
183 uint16_t repstart;
184 uint16_t replen;
185 uint8_t pad1;
186 uint8_t vol;
187 uint16_t pad2;
188 } mi;
189 if (file->read(file, &mi, sizeof (mi)) != sizeof (mi))
190 {
191 fprintf(stderr, __FILE__ ": read failed #7\n");
192 return errFormStruc;
193 }
194 mi.length=uint32_big(mi.length);
195 mi.repstart=uint16_big(mi.repstart);
196 mi.replen=uint16_big(mi.replen);
197 #ifdef OKT_LOAD_DEBUG
198 fprintf(stderr, __FILE__ ": sample[%d]\n", i);
199 fprintf(stderr, __FILE__ ": length=%d\n", (int)mi.length);
200 fprintf(stderr, __FILE__ ": repstart=%d\n", (int)mi.repstart);
201 fprintf(stderr, __FILE__ ": replen=%d\n", (int)mi.replen);
202 fprintf(stderr, __FILE__ ": pad1=%d\n", (int)mi.pad1);
203 fprintf(stderr, __FILE__ ": vol=%d\n", (int)mi.vol);
204 fprintf(stderr, __FILE__ ": pad2=%d\n", (int)mi.pad2);
205 #endif
206 if (mi.length<4)
207 mi.length=0;
208 if (mi.replen<4)
209 mi.replen=0;
210 if (!mi.replen||(mi.repstart>=mi.length))
211 mi.replen=0;
212 else
213 if ((mi.repstart+mi.replen)>mi.length)
214 mi.replen=mi.length-mi.repstart;
215
216 ip=&m->instruments[i];
217 sp=&m->modsamples[i];
218 sip=&m->samples[i];
219
220 memcpy(ip->name, mi.name, 20);
221 ip->name[20]=0;
222 if (!mi.length)
223 continue;
224
225 for (t=0; t<128; t++)
226 ip->samples[t]=i;
227
228 *ip->name=0;
229 sp->handle=i;
230 sp->normnote=0;
231 sp->stdvol=(mi.vol>0x3F)?0xFF:(mi.vol<<2);
232 sp->stdpan=-1;
233 sp->opt=0;
234
235 sip->length=mi.length;
236 sip->loopstart=mi.repstart;
237 sip->loopend=mi.repstart+mi.replen;
238 sip->samprate=8363;
239 sip->type=mi.replen?mcpSampLoop:0;
240 }
241
242 if (file->read (file, &chunk, sizeof(chunk)) != sizeof(chunk))
243 {
244 fprintf(stderr, __FILE__ ": read failed #8\n");
245 return errFormStruc;
246 }
247 #ifdef OKT_LOAD_DEBUG
248 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"SPEE\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
249 #endif
250 if (memcmp(chunk.sig, "SPEE", 4))
251 {
252 fprintf(stderr, __FILE__ ": header \"SPEE\" failed\n");
253 return errFormStruc;
254 }
255 chunk.blen=uint32_big(chunk.blen);
256 #ifdef OKT_LOAD_DEBUG
257 fprintf(stderr, __FILE__ ": chunk length should be 2, checking (%d)\n", (int)chunk.blen);
258 #endif
259 if (chunk.blen!=2)
260 {
261 fprintf(stderr, __FILE__ ": invalid length of sub chunk \"SPEE\": %d\n", (int)chunk.blen);
262 return errFormStruc;
263 }
264
265 if (ocpfilehandle_read_uint16_be (file, &orgticks))
266 {
267 fprintf(stderr, __FILE__ ": read failed #10\n");
268 return errFormStruc;
269 }
270 #ifdef OKT_LOAD_DEBUG
271 fprintf(stderr, __FILE__ ": orgticks: %d\n", (int)orgticks);
272 #endif
273
274 if (file->read (file, &chunk, sizeof(chunk)) != sizeof (chunk))
275 {
276 fprintf(stderr, __FILE__ ": read failed #11\n");
277 return errFormStruc;
278 }
279 #ifdef OKT_LOAD_DEBUG
280 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"SLEN\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
281 #endif
282 if (memcmp(chunk.sig, "SLEN", 4))
283 {
284 fprintf(stderr, __FILE__ ": header \"SLEN\" failed\n");
285 return errFormStruc;
286 }
287 chunk.blen=uint32_big(chunk.blen);
288 #ifdef OKT_LOAD_DEBUG
289 fprintf(stderr, __FILE__ ": chunk length should be 2, checking (%d)\n", (int)chunk.blen);
290 #endif
291 if (chunk.blen!=2)
292 {
293 fprintf(stderr, __FILE__ ": invalid length of sub chunk \"SPEE\": %d\n", (int)chunk.blen);
294 return errFormStruc;
295 }
296 if (ocpfilehandle_read_uint16_be (file, &pn))
297 {
298 fprintf(stderr, __FILE__ ": read failed #13\n");
299 return errFormStruc;
300 }
301 #ifdef OKT_LOAD_DEBUG
302 fprintf(stderr, __FILE__ ": song length (patterns): %d\n", (int)pn);
303 #endif
304
305 if (file->read (file, &chunk, sizeof(chunk)) != sizeof (chunk))
306 {
307 fprintf(stderr, __FILE__ ": read failed #14\n");
308 return errFormStruc;
309 }
310 #ifdef OKT_LOAD_DEBUG
311 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"PLEN\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
312 #endif
313 if (memcmp(chunk.sig, "PLEN", 4))
314 {
315 fprintf(stderr, __FILE__ ": header \"PLEN\" failed\n");
316 return errFormStruc;
317 }
318 chunk.blen = uint32_big(chunk.blen);
319 #ifdef OKT_LOAD_DEBUG
320 fprintf(stderr, __FILE__ ": chunk length should be 2, checking (%d)\n", (int)chunk.blen);
321 #endif
322 if (chunk.blen!=2)
323 {
324 fprintf(stderr, __FILE__ ": invalid length of sub chunk \"PLEN\": %d\n", (int)chunk.blen);
325 return errFormStruc;
326 }
327 if (ocpfilehandle_read_uint16_be (file, &ordn))
328 {
329 fprintf(stderr, __FILE__ ": warning, read failed #16\n");
330 }
331 #ifdef OKT_LOAD_DEBUG
332 fprintf(stderr, __FILE__ ": orders: %d\n", (int)ordn);
333 #endif
334
335 if (file->read (file, &chunk, sizeof(chunk)) != sizeof (chunk))
336 {
337 fprintf(stderr, __FILE__ ": read failed #17\n");
338 return errFormStruc;
339 }
340 #ifdef OKT_LOAD_DEBUG
341 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"PATT\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
342 #endif
343 if (memcmp(chunk.sig, "PATT", 4))
344 {
345 fprintf(stderr, __FILE__ ": header \"PATT\" failed\n");
346 return errFormStruc;
347 }
348 chunk.blen=uint32_big(chunk.blen);
349 #ifdef OKT_LOAD_DEBUG
350 fprintf(stderr, __FILE__ ": checking chunk length (should less than or equal to 128): %d\n", (int)chunk.blen);
351 #endif
352 if (chunk.blen>128)
353 {
354 fprintf(stderr, __FILE__ ": invalid length of sub chunk \"PATT\": %d\n", (int)chunk.blen);
355 return errFormStruc;
356 }
357
358 if (file->read (file, orders, chunk.blen) != chunk.blen)
359 {
360 fprintf(stderr, __FILE__ ": read failed #19\n");
361 return errFormStruc;
362 }
363 if (chunk.blen<ordn)
364 ordn=chunk.blen;
365 m->loopord=0;
366
367 m->patnum=ordn;
368 m->ordnum=ordn;
369 m->endord=m->patnum;
370 m->tracknum=pn*(m->channum+1);
371
372 if (!mpAllocPatterns(m, m->patnum)||!mpAllocTracks(m, m->tracknum)||!mpAllocOrders(m, m->ordnum))
373 return errAllocMem;
374
375 for (i=0; i<m->ordnum; i++)
376 m->orders[i]=i;
377
378 for (pp=m->patterns, t=0; t<m->patnum; pp++, t++)
379 {
380 for (i=0; i<m->channum; i++)
381 pp->tracks[i]=orders[t]*(m->channum+1)+i;
382 pp->gtrack=orders[t]*(m->channum+1)+m->channum;
383 }
384
385 r.temptrack=malloc(sizeof(uint8_t)*3000);
386 r.buffer=malloc(sizeof(uint8_t)*(1024*m->channum));
387 if (!r.buffer||!r.temptrack)
388 {
389 FreeResources (&r);
390 return errAllocMem;
391 }
392
393 for (t=0; t<pn; t++)
394 {
395 uint16_t patlen;
396 uint16_t q;
397 uint8_t *tp;
398 uint8_t *buf;
399 uint8_t row;
400 struct gmdtrack *trk;
401 uint16_t len;
402
403 if (file->read (file, &chunk, sizeof(chunk)) != sizeof (chunk))
404 {
405 fprintf(stderr, __FILE__ ": read failed #20\n");
406 FreeResources (&r);
407 return errFormStruc;
408 }
409 #ifdef OKT_LOAD_DEBUG
410 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"PBOD\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
411 #endif
412 if (memcmp(chunk.sig, "PBOD", 4))
413 {
414 fprintf(stderr, __FILE__ ": header \"PBOD\" failed\n");
415 FreeResources (&r);
416 return errFormStruc;
417 }
418 chunk.blen=uint32_big(chunk.blen);
419 if (ocpfilehandle_read_uint16_be (file, &patlen))
420 {
421 fprintf(stderr, __FILE__ ": warning, read failed #22\n");
422 }
423 #ifdef OKT_LOAD_DEBUG
424 fprintf(stderr, __FILE__ ": patlen red is %d. It should not be bigger than 256, and this should match:\n (blen!=(2+4*m->channum*patlen)\n %d!=2+4*%d*%d\n %d!=%d\n", (int)patlen, (int)chunk.blen, (int)m->channum, (int)patlen, (int)chunk.blen, (int)(2+4*m->channum*patlen));
425 #endif
426 if ((chunk.blen!=(2+4*m->channum*patlen))||(patlen>256))
427 {
428 fprintf(stderr, __FILE__ ": invalid patlen: %d\n", (int)patlen);
429 FreeResources (&r);
430 return errFormStruc;
431 }
432
433 for (q=0; q<m->patnum; q++)
434 if (t==orders[q])
435 m->patterns[q].patlen=patlen;
436
437 if (file->read (file, r.buffer, 4 * m->channum * patlen) != (4 * m->channum * patlen))
438 {
439 fprintf(stderr, __FILE__ ": read failed #23\n");
440 FreeResources (&r);
441 return errFormStruc;
442 }
443 for (q=0; q<m->channum; q++)
444 {
445 uint8_t *tp=r.temptrack;
446 uint8_t *buf=r.buffer+4*q;
447
448 struct gmdtrack *trk;
449 uint16_t len;
450
451 uint8_t row;
452 for (row=0; row<patlen; row++, buf+=m->channum*4)
453 {
454 uint8_t *cp=tp+2;
455
456 uint8_t command=buf[2];
457 uint8_t data=buf[3];
458 int16_t nte=buf[0]?(buf[0]+60-17+4):-1;
459 int16_t ins=buf[0]?buf[1]:-1;
460 int16_t pan=-1;
461 int16_t vol=-1;
462
463 if (!row&&(t==orders[0]))
464 pan=(cflag2[q]&2)?0xFF:0x00;
465
466 if ((command==31)&&(data<=0x40))
467 {
468 vol=(data>0x3F)?0xFF:(data<<2);
469 command=0;
470 }
471 if ((ins!=-1)||(nte!=-1)||(vol!=-1)||(pan!=-1))
472 {
473 unsigned char *act=cp;
474 *cp++=cmdPlayNote;
475 if (ins!=-1)
476 {
477 *act|=cmdPlayIns;
478 *cp++=ins;
479 }
480 if (nte!=-1)
481 {
482 *act|=cmdPlayNte;
483 *cp++=nte;
484 }
485 if (vol!=-1)
486 {
487 *act|=cmdPlayVol;
488 *cp++=vol;
489 }
490 if (pan!=-1)
491 {
492 *act|=cmdPlayPan;
493 *cp++=pan;
494 }
495 }
496 switch (command)
497 {
498 case 13: /* note down */
499 case 17: /* note up */
500 case 21: /* note - */
501 case 30: /* note + */
502 break;
503 case 10: /* LNH */
504 case 11: /* NHNL */
505 case 12: /* HHNLL */
506 break;
507 case 31:
508 if (data<=0x50)
509 putcmd(&cp, cmdVolSlideDown, (data&0xF)<<2);
510 else
511 if (data<=0x60)
512 putcmd(&cp, cmdVolSlideUp, (data&0xF)<<2);
513 else
514 if (data<=0x70)
515 putcmd(&cp, cmdRowVolSlideDown, (data&0xF)<<2);
516 else
517 if (data<=0x80)
518 putcmd(&cp, cmdRowVolSlideUp, (data&0xF)<<2);
519 break;
520 case 27: /* release!!! */
521 putcmd(&cp, cmdSetLoop, 0);
522 break;
523 case 0x1:
524 putcmd(&cp, cmdPitchSlideDown, data);
525 break;
526 case 0x2:
527 putcmd(&cp, cmdPitchSlideUp, data);
528 break;
529 }
530
531 if (cp!=(tp+2))
532 {
533 tp[0]=row;
534 tp[1]=cp-tp-2;
535 tp=cp;
536 }
537 }
538 trk=&m->tracks[t*(m->channum+1)+q];
539 len=tp-r.temptrack;
540
541 if (!len)
542 trk->ptr=trk->end=0;
543 else {
544 trk->ptr=malloc(sizeof(uint8_t)*len);
545 trk->end=trk->ptr+len;
546 if (!trk->ptr)
547 {
548 FreeResources (&r);
549 return errAllocMem;
550 }
551 memcpy(trk->ptr, r.temptrack, len);
552 }
553 }
554
555 tp=r.temptrack;
556 buf=r.buffer;
557 for (row=0; row<patlen; row++)
558 {
559 uint8_t *cp=tp+2;
560
561 if (!row&&(t==orders[0]))
562 putcmd(&cp, cmdTempo, orgticks);
563
564 for (q=0; q<m->channum; q++, buf+=4)
565 {
566 uint8_t command=buf[2];
567 uint8_t data=buf[3];
568
569 switch (command)
570 {
571 case 25:
572 putcmd(&cp, cmdGoto, data);
573 break;
574 case 28:
575 if (data)
576 putcmd(&cp, cmdTempo, data);
577 break;
578 }
579 }
580
581 if (cp!=(tp+2))
582 {
583 tp[0]=row;
584 tp[1]=cp-tp-2;
585 tp=cp;
586 }
587 }
588
589 trk=&m->tracks[t*(m->channum+1)+m->channum];
590 len=tp-r.temptrack;
591
592 if (!len)
593 trk->ptr=trk->end=0;
594 else {
595 trk->ptr=malloc(sizeof(uint8_t)*len);
596 trk->end=trk->ptr+len;
597 if (!trk->ptr)
598 {
599 FreeResources (&r);
600 return errAllocMem;
601 }
602 memcpy(trk->ptr, r.temptrack, len);
603 }
604 }
605 FreeResources (&r);
606
607 for (i=0; i<m->instnum; i++)
608 {
609 /*
610 struct gmdinstrument *ip=&m->instruments[i]; NOT USED */
611 struct gmdsample *sp=&m->modsamples[i];
612 struct sampleinfo *sip=&m->samples[i];
613 if (sp->handle==0xFFFF)
614 continue;
615
616 if (file->read (file, &chunk, sizeof(chunk)) != sizeof (chunk))
617 {
618 fprintf(stderr, __FILE__ ": read failed #24\n");
619 return errFormStruc;
620 }
621 #ifdef OKT_LOAD_DEBUG
622 fprintf(stderr, __FILE__ ": comparing header \"%c%c%c%c\" against \"SBOD\"\n", chunk.sig[0], chunk.sig[1], chunk.sig[2], chunk.sig[3]);
623 #endif
624 if (memcmp(chunk.sig, "SBOD", 4))
625 return errFormStruc;
626 chunk.blen=uint32_big(chunk.blen);
627
628 sip->ptr=malloc(sizeof(char)*(chunk.blen+8));
629 if (!sip->ptr)
630 return errAllocMem;
631
632 if (file->read (file, sip->ptr, chunk.blen) != chunk.blen)
633 {
634 fprintf(stderr, __FILE__ ": warning, read failed #26\n");
635 }
636 if (sip->length>chunk.blen)
637 sip->length=chunk.blen;
638 if (sip->loopend>chunk.blen)
639 sip->loopend=chunk.blen;
640 if (sip->loopstart>=sip->loopend)
641 sip->type&=~mcpSampLoop;
642 }
643
644 return errOk;
645 }
646
647 struct gmdloadstruct mpLoadOKT = { _mpLoadOKT };
648
649 struct linkinfostruct dllextinfo = {.name = "gmdlokt", .desc = "OpenCP Module Loader: *.OKT (c) 1994-21 Niklas Beisert, Stian Skjelstad", .ver = DLLVERSION, .size = 0};
650