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