1 /*
2     music.c
3 
4     Copyright (C) 1986  Eckhard Kruse
5     Copyright (C) 2011  Thomas Huth
6 
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 /*********************************************************************
22  *                  Abspielen von Musik-Editor St�cken               *
23  *                                                                   *
24  * Gleich einmal vorweg wie ein Programm aussieht, das die hier      *
25  * definierten Routinen verwendet:                                   *
26  *                                                                   *
27  * extern void m_laden(), m_musik(), m_wloop();                      *
28  * main()                                                            *
29  * {                                                                 *
30  *    int save_ssp;                                                  *
31  *    m_laden("DATEI.MUS");             Datei laden                  *
32  *    m_musik();                        Musik abspielen              *
33  * }                                                                 *
34  * int m_wait()                         Warteschleife                *
35  * {                                                                 *
36  *    m_wloop();                                                     *
37  *    return 0;                         return 1 um abzubrechen      *
38  * }                                                                 *
39  *********************************************************************/
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <SDL.h>
44 #include <SDL_endian.h>
45 #include "psg.h"
46 #include "music.h"
47 #include "paths.h"
48 
49 extern int m_wait(void);  /* Diese Funktion muss in Ihrem Hauptprogramm stehen,  *
50  * sie wird von m_musik() nach jedem 1/96 Takt aufgerufen, und sie sollte    *
51  * immer eine bestimmte Zeitspanne warten ( bestimmt die Ablaufgeschwindig-  *
52  * keit der Musik ). Dies kann durch den Aufruf von m_wloop() geschehen.     */
53 
54 unsigned short *takte;
55 short buffer[100], *liste,
56       max_abl, max_tkt, walz, tempo, temp,
57       w_len, save7, reg7, kanal,
58       tra[3], lau[3];
59 
60 /**************** Tabellen f�r Noten- und Frequenzwerte **********************/
61 short st_wert[] =
62 {
63 	15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 28, 30,
64 	32, 34, 36, 38, 40, 42, 45, 47, 50, 53, 56, 60,
65 	63, 67, 71, 75, 80, 84, 89, 95, 100, 106, 113, 119,
66 	127, 134, 142, 150, 159, 169, 179, 190, 201, 213, 226, 239,
67 	253, 268, 284, 301, 319, 338, 358, 379, 402, 426, 451, 478,
68 	506, 536, 568, 602, 638, 676, 716, 759, 804, 852, 903, 956,
69 	1013, 1073, 1136, 1204, 1276, 1351, 1432, 1517, 1607, 1703, 1804, 1911,
70 	2025, 2145, 2273, 2408, 2553, 2703, 2864, 3034, 3214, 3405, 3608, 3823
71 } ;
72 
73 char  st_ton[] =
74 {
75 	0, 1, 3, 5, 7, 8, 10, 12, 13, 15, 17, 19, 20, 22, 24, 25,
76 	27, 29, 31, 32, 34, 36,  37, 39, 41, 43, 44, 46, 48, 49, 51, 53,
77 	55, 56, 58, 60, 61, 63, 65, 67, 68, 70, 72, 73,
78 	75, 77, 79, 80, 82, 84, 85, 87, 89, 91, 92, 94, 96
79 } ;
80 
81 /******************** Laden und Speicher reservieren *************************/
m_laden(const char * string)82 void m_laden(const char * string)
83 {
84 	FILE *f_handle;
85 	int i;
86 	char *fname;
87 
88 	fname = malloc(FILENAME_MAX);
89 	if (!fname)
90 	{
91 		perror("m_laden");
92 		return;
93 	}
94 	snprintf(fname, FILENAME_MAX, "%s/%s",
95 	         Paths_GetDataDir(), string);
96 
97 	/* Open file in data directory */
98 	f_handle = fopen(fname, "rb");
99 	free(fname); fname = NULL;
100 	if (!f_handle)
101 	{
102 		/* Try local directory instead */
103 		f_handle = fopen(string, "rb");
104 		if (!f_handle)
105 		{
106 			perror("Loading music failed");
107 			return;
108 		}
109 	}
110 
111 	if (fread(buffer, 16, 1, f_handle) != 1)
112 	{
113 		perror("Failed to read music file");
114 		goto out;
115 	}
116 	for (i = 0; i < 16/2; i++)
117 	{
118 		buffer[i] = SDL_SwapBE16(buffer[i]);
119 	}
120 
121 	tempo=buffer[2];
122 	max_abl=buffer[3];
123 	max_tkt=buffer[4];
124 	walz=buffer[7];
125 	if( walz )
126 		w_len=72;
127 	else
128 		w_len=96;
129 
130 	liste=( short *)malloc((max_abl+2)<<3 );
131 	/* Reserviere Speicherbereich der Gr��e (w_len*2)*(max_tkt+2) und l�sch ihn. */
132 	takte=( unsigned short *)calloc( w_len*2, max_tkt+2+2 );
133 
134 	if (fread(buffer, 1, 36, f_handle) != 36)
135 	{
136 		perror("Failed to read music file");
137 		goto out;
138 	}
139 	for (i = 0; i < 36/2; i++)
140 	{
141 		buffer[i] = SDL_SwapBE16(buffer[i]);
142 	}
143 
144 	if (fread(liste, (max_abl+1)<<3, 1, f_handle) != 1)
145 	{
146 		perror("Failed to read music file");
147 		goto out;
148 	}
149 	for (i = 0; i < ((max_abl+1)<<3)/2; i++)
150 	{
151 		liste[i] = SDL_SwapBE16(liste[i]);
152 	}
153 
154 	if (fread(&takte[100], (max_tkt+1)*w_len, 2, f_handle) != 2)
155 	{
156 		perror("Failed to read music file");
157 		goto out;
158 	}
159 	for (i = 0; i < (max_tkt+1)*w_len; i++)
160 	{
161 		takte[100+i] = SDL_SwapBE16(takte[100+i]);
162 	}
163 
164 out:
165 	fclose(f_handle);
166 }
167 
m_quit(void)168 void m_quit(void)
169 {
170 	free(liste); liste = NULL;
171 	free(takte); takte = NULL;
172 }
173 
174 /************************ St�ck spielen **************************************/
m_musik(void)175 void m_musik(void)
176 {
177 	short  buf_ptr, lis_ptr, ende, help,
178 	    kan1, kan2, kan3, rau;
179 
180 	if (!liste || !takte)
181 		return;
182 
183 	s_init();
184 	buffer[0]=0;
185 	buffer[1]=-2;
186 	buf_ptr=2;
187 	lis_ptr=0;
188 	temp=100;
189 	lau[0]=lau[1]=lau[2]=100;
190 	tra[0]=tra[1]=tra[2]=0;
191 	ende=0;
192 
193 	while( !ende )
194 	{
195 		switch( liste[lis_ptr] )
196 		{
197 		case -1:
198 			if( buffer[--buf_ptr]==-2 ) ende=1;
199 			lis_ptr=buffer[--buf_ptr];
200 			break;
201 		case -2:
202 			tra[0]=liste[++lis_ptr];
203 			tra[1]=liste[++lis_ptr];
204 			tra[2]=liste[++lis_ptr];
205 			lis_ptr++;
206 			break;
207 		case -3:
208 			lau[0]=liste[++lis_ptr];
209 			lau[1]=liste[++lis_ptr];
210 			lau[2]=liste[++lis_ptr];
211 			lis_ptr++;
212 			break;
213 		case -4:
214 			temp=liste[++lis_ptr];
215 			lis_ptr+=3;
216 			break;
217 		case -5:
218 			lis_ptr+=4;
219 			buffer[buf_ptr++]=lis_ptr;
220 			buffer[buf_ptr++]=0;
221 			break;
222 		case -6:
223 			lis_ptr+=4;
224 			if( buffer[buf_ptr-1]==liste[lis_ptr-3] )
225 			{
226 				buf_ptr-=2;
227 				help=0;
228 				while( help>=0 )
229 				{
230 					if( liste[lis_ptr]==-1 )  help=-1;
231 					help+=( liste[lis_ptr]==-5 )-( liste[lis_ptr]==-7 );
232 					lis_ptr+=4;
233 				}
234 			}
235 			break;
236 		case -7:
237 			buffer[buf_ptr-1]++;
238 			lis_ptr=buffer[buf_ptr-2];
239 			break;
240 		case -8:
241 			if( liste[++lis_ptr]<0 )
242 				lis_ptr+=3;
243 			else
244 			{
245 				buffer[buf_ptr++]=lis_ptr+3;
246 				buffer[buf_ptr++]=-5;
247 				lis_ptr=(liste[lis_ptr]-1)<<2;
248 			}
249 			break;
250 		default:
251 			rau =( liste[lis_ptr]>=0 )*(( liste[lis_ptr+0] )*w_len +100);
252 			lis_ptr++;
253 			kan1=( liste[lis_ptr]>=0 )*(( liste[lis_ptr+0] )*w_len +100);
254 			lis_ptr++;
255 			kan2=( liste[lis_ptr]>=0 )*(( liste[lis_ptr+0] )*w_len +100);
256 			lis_ptr++;
257 			kan3=( liste[lis_ptr]>=0 )*(( liste[lis_ptr+0] )*w_len +100);
258 			lis_ptr++;
259 			for( help=0; help<w_len; help++ )
260 			{
261 				s_rausch( takte[rau++]&255 );
262 				kanal=0;
263 				s_note( takte[kan1++] );
264 				kanal++;
265 				s_note( takte[kan2++] );
266 				kanal++;
267 				s_note( takte[kan3++] );
268 
269 				if (m_wait())
270 				{
271 					help=100;
272 					ende++;  /* Bei Taste Abbruch */
273 				}
274 			}
275 		}
276 	}
277 	s_quit();
278 }
279 
280 /************* Standardroutine f�r m_wait(): Pause machen ********************/
m_wloop(void)281 void m_wloop(void)
282 {
283 	SDL_Delay(1800/w_len);
284 }
285 
286 /*****************************************************************************
287  * Und nun die Routinen zur eigentlichen Tonerzeugung; sie brauchen von      *
288  * Ihrem Programm nicht aufgerufen zu werden.                                */
289 /****************************** Note spielen *********************************/
s_note(unsigned int wert)290 void s_note(unsigned int wert)
291 {
292 	short ton_nr;
293 	ton_nr=st_ton[ wert>>2 & 63 ];
294 	if( wert & 0x4000 ) ton_nr--;
295 	if( wert & 0x8000 ) ton_nr++;
296 	if( ( wert & 0xc000 ) == 0xc000 )
297 	{
298 		s_rausch( wert&255 );
299 	}
300 	else
301 	{
302 		ton_nr-=tra[kanal];
303 		if( ton_nr<0   ) ton_nr=0;
304 		if( ton_nr>95 ) ton_nr=95;
305 		s_freq( (st_wert[ton_nr]*(4-(wert&3))+st_wert[ton_nr+1]*(wert&3) )>>2 );
306 		if( wert & 0x1000 )  s_t_an();
307 		else  s_t_aus();
308 		if( wert & 0x2000 )  s_r_an();
309 		else  s_r_aus();
310 		s_laut( (wert>>8 & 15)*lau[kanal]/100 );
311 	}
312 }
313 
314 /*************************** Sound Ansteuerung *******************************/
315 
316 /**************************** Initialisierung ********************************/
s_init(void)317 void s_init(void)
318 {
319 	reg7=save7=Giaccess( 0, 0x07 );
320 	s_rausch( 0 );
321 }
322 
323 /*********************** Wiederherstellen vor Ende ***************************/
s_quit(void)324 void s_quit(void)
325 {
326 	s_aus();
327 	Giaccess( save7, 0x87 );
328 }
329 
330 /************************** Tonfrequenz setzen *******************************/
s_freq(unsigned short freq)331 void s_freq(unsigned short freq)
332 {
333 	short kan;
334 	kan=kanal<<1;
335 	Giaccess( freq&0xff, kan+0x80 );
336 	Giaccess( freq>>8, kan+0x81 );
337 }
338 
339 /************************** Lautst�rke setzen ********************************/
s_laut(short laut)340 void s_laut(short laut)
341 {
342 	Giaccess( laut, kanal+0x88 );
343 }
344 
345 /************************* Rauschperiode setzen ******************************/
s_rausch(short periode)346 void s_rausch(short periode)
347 {
348 	Giaccess( periode, 0x86 );
349 }
350 
351 /**************************** Ton einschalten ********************************/
s_t_an(void)352 void s_t_an(void)
353 {
354 	reg7&=( 254-kanal-( kanal==2 ) );
355 	Giaccess( reg7, 0x87 );
356 }
357 
358 /**************************** Ton ausschalten ********************************/
s_t_aus(void)359 void s_t_aus(void)
360 {
361 	reg7|=( 1+kanal+( kanal==2 ) );
362 	Giaccess( reg7, 0x87 );
363 }
364 
365 /*************************** Rauschen einschalten ****************************/
s_r_an(void)366 void s_r_an(void)
367 {
368 	reg7 &= 255 -((1 + kanal + (kanal == 2)) << 3);
369 	Giaccess(reg7, 0x87);
370 }
371 
372 /*************************** Rauschen ausschalten ****************************/
s_r_aus(void)373 void s_r_aus(void)
374 {
375 	reg7 |= ((1 + kanal + (kanal == 2)) << 3);
376 	Giaccess(reg7, 0x87);
377 }
378 
379 /*************************** Sound abschalten ********************************/
s_aus(void)380 void s_aus(void)
381 {
382 	kanal=0;
383 	s_laut( 0 );
384 	kanal=1;
385 	s_laut( 0 );
386 	kanal=2;
387 	s_laut( 0 );
388 }
389