1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  *
4  * XMPlay time routines 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  *  -th980717   Tammo Hinrichs <opencp@gmx.net>
24  *    -removed all references to gmd structures to make this more flexible
25  */
26 
27 #include "config.h"
28 #include "types.h"
29 #include "xmplay.h"
30 #include "err.h"
31 
32 static uint8_t chPatLoopCount[256];
33 static uint8_t chPatLoopStart[256];
34 
35 static uint8_t curtick;
36 static uint8_t curtempo;
37 
38 static int looped;
39 static int currow;
40 static uint8_t (*patptr)[5];
41 static int patlen;
42 static int curord;
43 
44 static int nord;
45 static int nchan;
46 static int loopord;
47 static uint8_t (**patterns)[5];
48 static uint16_t *orders;
49 static uint16_t *patlens;
50 
51 static int jumptoord;
52 static int jumptorow;
53 static int patdelay;
54 
55 static int timerval;
56 static int timerfrac;
57 static int speed;
58 
59 static int (*calctimer)[2];
60 static int calcn;
61 static int sync;
62 
xmpFindTick(void)63 static int xmpFindTick(void)
64 {
65 	int i;
66 	int p;
67 
68 	curtick++;
69 	if (curtick>=curtempo)
70 		curtick=0;
71 
72 	if (!curtick&&patdelay)
73 	{
74 		if (jumptoord!=-1)
75 		{
76 			if (jumptoord!=curord)
77 				for (i=0; i<nchan; i++)
78 				{
79 					chPatLoopCount[i]=0;
80 					chPatLoopStart[i]=0;
81 				}
82 
83 			if (jumptoord>=nord)
84 				jumptoord=loopord;
85 
86 			curord=jumptoord;
87 			currow=jumptorow;
88 			jumptoord=-1;
89 			patlen=patlens[orders[curord]];
90 			patptr=patterns[orders[curord]];
91 		}
92 	}
93 
94 	if (!curtick&&patdelay)
95 	{
96 		patdelay--;
97 	} else if (!curtick)
98 	{
99 		currow++;
100 		if ((jumptoord==-1)&&(currow>=patlen))
101 		{
102 			jumptoord=curord+1;
103 			jumptorow=0;
104 		}
105 		if (jumptoord!=-1)
106 		{
107 			if (jumptoord!=curord)
108 				for (i=0; i<nchan; i++)
109 				{
110 					chPatLoopCount[i]=0;
111 					chPatLoopStart[i]=0;
112 				}
113 
114 			if (jumptoord>=nord)
115 				jumptoord=loopord;
116 			if (jumptoord<curord)
117 				looped=1;
118 
119 			curord=jumptoord;
120 			currow=jumptorow;
121 			jumptoord=-1;
122 			patlen=patlens[orders[curord]];
123 			patptr=patterns[orders[curord]];
124 		}
125 
126 		for (i=0; i<nchan; i++)
127 		{
128 			int procdat=patptr[nchan*currow+i][4];
129 
130 			switch (patptr[nchan*currow+i][3])
131 			{
132 				case xmpCmdSync1: case xmpCmdSync2: case xmpCmdSync3:
133 					sync=procdat;
134 					break;
135 				case xmpCmdJump:
136 					jumptoord=procdat;
137 					jumptorow=0;
138 					break;
139 				case xmpCmdBreak:
140 					if (jumptoord==-1)
141 						jumptoord=curord+1;
142 					jumptorow=(procdat&0xF)+(procdat>>4)*10;
143 					break;
144 				case xmpCmdSpeed:
145 					if (!procdat)
146 					{
147 						jumptoord=procdat;
148 						jumptorow=0;
149 						break;
150 					}
151 					if (procdat>=0x20)
152 						speed=procdat;
153 					else
154 						curtempo=procdat;
155 					break;
156 				case xmpCmdPatLoop:
157 					if (!procdat)
158 						chPatLoopStart[i]=currow;
159 					else {
160 						chPatLoopCount[i]++;
161 						if (chPatLoopCount[i]<=procdat)
162 						{
163 							jumptorow=chPatLoopStart[i];
164 							jumptoord=curord;
165 						} else {
166 							chPatLoopCount[i]=0;
167 							chPatLoopStart[i]=currow+1;
168 						}
169 					}
170 					break;
171 				case xmpCmdPatDelay:
172 					patdelay=procdat;
173 					break;
174 			}
175 		}
176 	}
177 
178 	p=(curord<<16)|(currow<<8)|curtick;
179 	for (i=0; i<calcn; i++)
180 		if ((p==calctimer[i][0])&&(calctimer[i][1]<0))
181 			if (!++calctimer[i][1])
182 				calctimer[i][1]=timerval;
183 
184 	if (sync!=-1)
185 		for (i=0; i<calcn; i++)
186 			if ((calctimer[i][0]==(-256-sync))&&(calctimer[i][1]<0))
187 				if (!++calctimer[i][1])
188 					calctimer[i][1]=timerval;
189 
190 	sync=-1;
191 
192 	if (looped)
193 		for (i=0; i<calcn; i++)
194 			if ((calctimer[i][0]==-1)&&(calctimer[i][1]<0))
195 				if (!++calctimer[i][1])
196 					calctimer[i][1]=timerval;
197 
198 	looped=0;
199 
200 	timerfrac+=4096*163840/speed;
201 	timerval+=timerfrac>>12;
202 	timerfrac&=4095;
203 
204 	for (i=0; i<calcn; i++)
205 		if (calctimer[i][1]<0)
206 			return 0;
207 
208 	return 1;
209 }
210 
xmpPrecalcTime(struct xmodule * m,int startpos,int (* calc)[2],int n,int ite)211 int __attribute__ ((visibility ("internal"))) xmpPrecalcTime(struct xmodule *m, int startpos, int (*calc)[2], int n, int ite)
212 {
213 	int i;
214 
215 	patdelay=0;
216 	sync=-1;
217 	looped=0;
218 	calcn=n;
219 	calctimer=calc;
220 	jumptorow=(startpos>>8)&0xFF;
221 	jumptoord=startpos&0xFF;
222 	curord=-1;
223 	currow=-1;
224 	nord=m->nord;
225 	patterns=m->patterns;
226 	orders=m->orders;
227 	patlens=m->patlens;
228 	nchan=m->nchan;
229 	loopord=m->loopord;
230 
231 	curtempo=m->initempo;
232 	curtick=m->initempo-1;
233 
234 	speed=m->inibpm;
235 	timerval=0;
236 	timerfrac=0;
237 
238 	for (i=0; i<ite; i++)
239 		if (xmpFindTick())
240 			break;
241 
242 	return 1;
243 }
244