1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * ITPlay timing/sync handlers for IMS
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 <signal.h>
27 #include <string.h>
28 #include <stdio.h> /* FILE * in itplay.h */
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include "types.h"
33 #include "itplay.h"
34
it_precalctime(struct it_module * this,int startpos,int (* calctimer)[2],int calcn,int ite)35 int __attribute__ ((visibility ("internal"))) it_precalctime(struct it_module *this, int startpos, int (*calctimer)[2], int calcn, int ite)
36 {
37 uint8_t *patptr=0;
38
39 int patdelaytick=0;
40 int patdelayrow=0;
41 int sync=-1;
42 int looped=0;
43 int gotorow=(startpos>>8)&0xFF;
44 int gotoord=startpos&0xFF;
45 int curord=-1;
46 int currow=-1;
47
48 int curspeed=this->inispeed;
49 int curtick=this->inispeed-1;
50
51 /* int loopord=0; unused */
52 int tempo=this->initempo;
53 int timerval=0;
54 int timerfrac=0;
55
56 uint8_t tempos[64];
57 uint8_t cmds[64];
58 uint8_t specials[64];
59 uint8_t patloopcount[64];
60 uint8_t patloopstart[64];
61
62 int it;
63
64 memset(tempos, 0, this->nchan);
65 memset(specials, 0, this->nchan);
66 memset(cmds, 0, this->nchan);
67
68
69 for (it=0; it<ite; it++)
70 {
71 int i;
72 int p;
73
74 curtick++;
75 if ((curtick==(curspeed+patdelaytick))&&patdelayrow)
76 {
77 curtick=0;
78 patdelayrow--;
79 }
80 if (curtick==(curspeed+patdelaytick))
81 {
82 patdelaytick=0;
83 curtick=0;
84 currow++;
85 if ((gotoord==-1)&&(currow==this->patlens[this->orders[curord]]))
86 {
87 gotoord=curord+1;
88 gotorow=0;
89 }
90 if (gotoord!=-1)
91 {
92 if (gotoord!=curord)
93 {
94 memset(patloopcount, 0, this->nchan);
95 memset(patloopstart, 0, this->nchan);
96 }
97
98 if (gotoord>=this->endord)
99 gotoord=0;
100 while (this->orders[gotoord]==0xFFFF)
101 gotoord++;
102 if (gotoord==this->endord)
103 gotoord=0;
104 if (gotorow>=this->patlens[this->orders[gotoord]])
105 {
106 gotoord++;
107 gotorow=0;
108 while (this->orders[gotoord]==0xFFFF)
109 gotoord++;
110 if (gotoord==this->endord)
111 gotoord=0;
112 }
113 if (gotoord<curord)
114 looped=1;
115 curord=gotoord;
116 patptr=this->patterns[this->orders[curord]];
117 for (currow=0; currow<gotorow; currow++)
118 {
119 while (*patptr)
120 patptr+=6;
121 patptr++;
122 }
123 gotoord=-1;
124 }
125
126 for (i=0; i<this->nchan; i++)
127 cmds[i]=0;
128 if (!patptr)
129 {
130 fprintf(stderr, "playit: ittime.c: patptr not set\n");
131 kill(getpid(), SIGTERM);
132 abort();
133 }
134 while (*patptr)
135 {
136 int ch=*patptr++-1;
137
138 int data=patptr[4];
139
140 cmds[ch]=patptr[3];
141 switch (cmds[ch])
142 {
143 case cmdSpeed:
144 if (data)
145 curspeed=data;
146 break;
147 case cmdJump:
148 gotorow=0;
149 gotoord=data;
150 break;
151 case cmdBreak:
152 if (gotoord==-1)
153 gotoord=curord+1;
154 gotorow=data;
155 break;
156 case cmdSpecial:
157 if (data)
158 specials[ch]=data;
159 switch (specials[ch]>>4)
160 {
161 case cmdSPatDelayTick:
162 patdelaytick=specials[ch]&0xF;
163 break;
164 case cmdSPatLoop:
165 if (!(specials[ch]&0xF))
166 patloopstart[ch]=currow;
167 else {
168 patloopcount[ch]++;
169 if (patloopcount[ch]<=(specials[ch]&0xF))
170 {
171 gotorow=patloopstart[ch];
172 gotoord=curord;
173 } else {
174 patloopcount[ch]=0;
175 patloopstart[ch]=currow+1;
176 }
177 }
178 break;
179 case cmdSPatDelayRow:
180 patdelayrow=specials[ch]&0xF;
181 break;
182 }
183 break;
184 case cmdTempo:
185 if (data)
186 tempos[ch]=data;
187 if (tempos[ch]>=0x20)
188 tempo=tempos[ch];
189 break;
190 #if 0
191 TODO this upcode is invalid
192 case cmdSync:
193 sync=data;
194 break;
195 #endif
196 }
197 patptr+=5;
198 }
199 patptr++;
200 } else
201 for (i=0; i<this->nchan; i++)
202 if ((cmds[i]==cmdTempo)&&(tempos[i]<0x20))
203 {
204 tempo+=(tempos[i]<0x10)?-tempos[i]:(tempos[i]&0xF);
205 tempo=(tempo<0x20)?0x20:(tempo>0xFF)?0xFF:tempo;
206 }
207
208
209
210 p=(curord<<16)|(currow<<8)|curtick;
211 for (i=0; i<calcn; i++)
212 if ((p==calctimer[i][0])&&(calctimer[i][1]<0))
213 if (!++calctimer[i][1])
214 calctimer[i][1]=timerval;
215
216 if (sync!=-1)
217 for (i=0; i<calcn; i++)
218 if ((calctimer[i][0]==(-256-sync))&&(calctimer[i][1]<0))
219 if (!++calctimer[i][1])
220 calctimer[i][1]=timerval;
221
222 sync=-1;
223
224 if (looped)
225 for (i=0; i<calcn; i++)
226 if ((calctimer[i][0]==-1)&&(calctimer[i][1]<0))
227 if (!++calctimer[i][1])
228 calctimer[i][1]=timerval;
229
230 looped=0;
231
232 timerfrac+=4096*163840/tempo;
233 timerval+=timerfrac>>12;
234 timerfrac&=4095;
235
236 for (i=0; i<calcn; i++)
237 if (calctimer[i][1]<0)
238 break;
239
240 if (i==calcn)
241 break;
242 }
243
244 return 1;
245 }
246