source: vital-to8-sdk/music/mod/convert/mod_convert.c @ 1

Last change on this file since 1 was 1, checked in by svn, 5 years ago

Import initial

File size: 19.0 KB
Line 
1/***********************************************************************/
2/*                                                                     */
3/* str.c - plays sound/noisetracker files on a SparcStation            */
4/* modified for thomson 6bit D/A                                       */
5/* corrected core dump on                                              */
6/* Authors  : Liam Corner - zenith@dcs.warwick.ac.uk                   */
7/*            Marc Espie - espie@dmi.ens.fr                            */
8/* Version  : 1.20 - 3 November 1991                                   */
9/*                                                                     */
10/*                                                                     */
11/***********************************************************************/
12
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <malloc.h>
17
18
19/**********************************************************/
20/* uS is the number of uSeconds that a byte is played for */
21/* Sparc plays at 8000 bytes/sec  =>  1 byte = 125 uSec   */
22/* VSYNC is the number of bytes played in 1/50 sec        */
23/* ie 0.02/(uS * 10**-6)                                  */
24/**********************************************************/
25#define uS 125
26#define VSYNC 160
27#define AUDIO "./out.raw"
28 
29#define MIN(A,B) ((A)<(B) ? (A) : (B))
30#define MAX(A,B) ((A)>(B) ? (A) : (B))
31 
32 
33typedef struct {    /***********************************/
34  signed char *info;       /* Sample                          */
35  int length;       /* Length of sample                */
36  float volume;     /* Fractional volume 0-1 (min-max) */
37  int rep_start;    /* Byte offset of repeat start     */
38  int rep_end;      /* Byte offset of repeat end       */
39} Voice;            /***********************************/
40 
41 
42typedef struct {                 /**************************/
43  char sample [64][4];           /* Sample number          */
44  char effect [64][4];           /* Effect number          */
45  unsigned char params [64][4];  /* Effect parameters      */
46  int period [64][4];            /* Period (pitch) of note */
47} Pattern;                       /**************************/
48 
49 
50typedef struct {         /***********************************************/
51  char samp;             /* Sample number of current note               */
52  int pitch;             /* Current channel pitch (index to step_table) */
53  int slide;             /* Step size of pitch slide (if any)           */
54  int doslide;
55  unsigned int pointer;  /* Current sample position                     */
56  unsigned int step;     /* Sample offset increment (gives pitch)       */
57  float volume;          /* Fractional volume of current note           */
58  float volslide;
59  int doslidevol;
60  int doporta;
61  int pitchgoal;
62  int portarate;
63} Channel;               /***********************************************/
64 
65
66#define MX_CHUNKS_IN_SONG 80000
67#define MX_CHUNKS_NB 80000
68int song_chunks_index=0;
69int song_chunks[MX_CHUNKS_IN_SONG];
70int nb_chunk=0;
71char chunks[MX_CHUNKS_NB][VSYNC];
72int cur_chunk_index=0;
73char cur_chunk[VSYNC*10];
74
75int cmp_chunks(char *a, char *b, int size,int mask) {
76        int i;
77        int diff;
78        // 1st pass ok if equal with mask
79        for (i=0;i<size;i++) {
80                if ((a[i]&mask) != (b[i]&mask)) break;
81        }
82        // 2nd pass... very lossy :)
83        if (i==size) return 0;
84        diff=0;
85        for (i=0;i<size;i++) {
86                if ((a[i]&mask) != (b[i]&mask)) diff++;
87                if (diff>32) return -1;
88        }
89       
90        return 0;
91}
92
93void insert_cur_chunk(void) {
94        int i;
95        for (i=0;i<nb_chunk;i++) {
96//              if (memcmp(cur_chunk,chunks[i],VSYNC)==0) break;
97                if (cmp_chunks(cur_chunk,chunks[i],VSYNC,0xFF)==0) break;
98        }
99        if (i==nb_chunk) {
100                memcpy(chunks[i],cur_chunk,VSYNC);
101                song_chunks[song_chunks_index]=i;
102                song_chunks_index++;
103                nb_chunk++;
104               
105        } else {
106                song_chunks[song_chunks_index]=i;
107                song_chunks_index++;           
108                if (song_chunks_index>=MX_CHUNKS_NB)
109                {
110                        fprintf(stderr,"Argh I'm dead... %d %d\n",song_chunks_index,i);
111                        exit(-1);
112                }
113        }
114}
115
116void rebuild_from_chunks(char * fname) {
117        FILE *f;
118        int i,j;
119
120        f=fopen(fname,"w");
121       
122        for (i=0;i<song_chunks_index;i++) {
123                fwrite(chunks[song_chunks[i]],1,VSYNC,f);
124        }
125
126        fclose(f);
127}
128
129/*
130 reconstruit des fichiers par banque de 16ko
131 fichier 0 : patterns bank+offset (/128)
132 fichiers 1 à n : chunks
133*/
134
135void build_outfiles(char * base) {
136        int ficnum,i,j,k;
137        FILE *f;
138        char str[1024];
139       
140        ficnum=0;
141
142        sprintf(str,"%s%02d.BIN",base,ficnum);
143        f=fopen(str,"w");
144       
145        for (j=0;j<song_chunks_index;j++) {
146                fputc((song_chunks[j]/64)+6,f);
147                fputc(song_chunks[j]&0x3F,f);
148        }
149
150        fclose(f);
151
152        ficnum++;
153
154        for (j=0;j<(nb_chunk/64)+1;j++) {
155        sprintf(str,"%s%02d.BIN",base,ficnum);
156        f=fopen(str,"w");
157                for (k=0;k<64;k++) {
158                        for (i=0;i<160;i++) {
159                                        char c1;
160                                        c1=chunks[j*64+k][i];
161                                        fputc(c1,f);
162                        }
163                        for (i=160;i<256;i++) {
164                                fputc(0,f);
165                        }
166                } // of for k
167       
168        fclose(f);
169        ficnum++;       
170        } // of for j
171}
172
173/****************************************************************************/
174/* Skips the next 'n' input bytes - because fseek won't work on stdin       */
175/****************************************************************************/
176void byteskip (fp, bytes)
177FILE *fp;
178int bytes;
179    {
180    int loop;
181 
182    for (loop = 0; loop < bytes; loop++)
183        getc(fp);
184    }
185 
186 
187 
188char *getstring(f, len)
189FILE *f;
190int len;
191    {
192    static char s[150];
193    int i;
194 
195    for (i = 0; i < len; i++)
196        s[i] = fgetc(f);
197    s[len] = '\0';
198    return s;
199    }
200 
201#define OLD 0
202#define NEW 1
203 
204int main (argc, argv)
205int argc;
206char **argv;
207    {
208    FILE *fp, *audio;
209    int loop;
210    int notes, note, channel, vsync;
211    int pat, pat_num;
212    int byte, bytes;
213    int step_table[1024];
214    int speed=6;                      /* Default speed is 6 */
215    int end_pattern=0;
216    char songlength;
217    char tune[128];
218    char num_patterns=0;
219    unsigned char ulaw;
220    float dummy1, dummy2;
221    Voice voices[32];
222    Pattern patterns[64];
223    Channel ch[4];
224    int nvoices;
225    int effect;
226 
227    int type;   /* module type: old or new */
228    char *command;  /* the actual command name used */
229 
230    command = argv[0];
231
232        type = NEW;
233
234 
235    if (type == OLD)
236        nvoices = 15;
237    else
238        nvoices = 31;
239 
240    if (argc>2)
241        {
242        fprintf(stderr,"Usage: %s [<filename>]\n", command);
243        exit(1);
244        }
245 
246/***********************************************************************/
247/* Creates a table of the byte_step << 16 for a given pitch            */
248/* The step and pointer are stored << 16 to get accuracy without floats*/
249/* eg to get double pitch only play every other byte                   */
250/* so step of 0x10000 is normal pitch, 0x8000 is half,                 */
251/* 0x20000 is double.  Pointer is >> 16 when accessed,                 */
252/* so 0x10000 is 1st byte, 0x20000 2nd etc                             */
253/* I have no idea where the other numbers are from, I copied them from */
254/* a SoundTracker player for the Acorn Archimedes                      */
255/*                                                                     */
256/* Actually, these other numbers are highly dependent on the amiga hw. */
257/***********************************************************************/
258    step_table[0] = 0;
259    for (loop = 1; loop < 1024; loop++)
260        {
261        dummy1 = 3575872 / loop;
262        dummy2 = (dummy1 / (1000000 /uS) ) * 60000;
263        step_table[loop] = (int)dummy2;
264        }
265 
266    if (argc < 2)
267        fp = stdin;
268    else
269        fp = fopen(argv[1], "r");
270    if (fp == NULL)
271        {
272        fprintf(stderr, "%s: unable to open tune file %s\n",
273            command, argv[1]);
274        exit(1);
275        }
276 
277        /* read song name */
278    printf("Module : %s\n\n", getstring(fp, 20));
279 
280        /* Reads in the sample-information tables */
281    for (loop = 1; loop <= nvoices; loop++)
282        {
283        printf("%6d : %s\n", loop, getstring(fp, 22));
284        voices[loop].length = ( (getc(fp) << 8) | getc(fp) ) * 2;
285        getc(fp);
286        voices[loop].volume = getc(fp);
287        voices[loop].volume = MIN(voices[loop].volume, 64);
288        voices[loop].volume /= 64;   /* Volume is a fraction */
289        voices[loop].rep_start = ( (getc(fp) << 8) | getc(fp) ) * 2;
290        voices[loop].rep_end = ( (getc(fp) << 8) | getc(fp) ) * 2;
291        if (voices[loop].rep_end <= 4)
292            voices[loop].rep_end = 0;
293        else
294            {
295                /* If there is a repeat then end=start+length, but must be */
296                /* less than the sample length.  Not sure if this is 100%  */
297                /* correct, but it seems to work OK :-)                    */
298            if (voices[loop].rep_end + voices[loop].rep_start - 1
299                > voices[loop].length)
300                voices[loop].rep_start >>= 1;
301            voices[loop].rep_end += voices[loop].rep_start;
302            voices[loop].rep_end = MIN(voices[loop].rep_end,
303                voices[loop].length);
304            }
305        }
306    voices[0].length = 0;
307 
308    songlength = getc(fp);
309    byteskip(fp, 1);
310 
311        /* Reads in the tune */
312    for (loop = 0; loop < 128; loop++)
313        {
314        tune[loop] = getc(fp);
315        if (tune[loop] > num_patterns)
316            num_patterns = tune[loop];
317        }
318    num_patterns++;
319 
320        /* skip over sig (usually M.K.) */
321    if (type == NEW)
322        byteskip(fp,4);
323 
324        /* Reads in the patterns */
325    for (pat_num = 0; pat_num < num_patterns; pat_num++)
326        {
327            /* 64 notes per pattern  */
328        for (notes = 0; notes < 64; notes++)
329            {
330                /* 4 channels per note   */
331            for (channel = 0; channel < 4; channel++)
332                {
333                note = (getc(fp) << 24) | (getc(fp) << 16) |
334                    (getc(fp) << 8) | getc(fp);
335                (patterns[pat_num]).effect[notes][channel] =
336                    (note & 0xF00) >> 8;
337                (patterns[pat_num]).params[notes][channel] = note & 0xFF;
338                (patterns[pat_num]).sample[notes][channel] =
339                    ( (note & 0xF000) >> 12) | ( (note >> 24) & 0x10);
340                (patterns[pat_num]).period[notes][channel] =
341                    MIN( (note & 0xFFF0000) >> 16, 1023);
342                }
343            }
344        }
345 
346        /* Stores the samples voices as an array of char */
347    for (loop = 1; loop <= nvoices; loop++)
348        {
349        voices[loop].info = malloc(voices[loop].length);
350        if (voices[loop].info == NULL)
351            {
352            fprintf(stderr, "%s: unable to allocate memory\n", command);
353            exit(1);
354            }
355        fread(voices[loop].info, 1, voices[loop].length, fp);
356        }
357    // audio = fopen(AUDIO, "w");
358    // if (audio == NULL)
359    //    {
360    //    fprintf(stderr, "%s: unable to access %s\n", command, AUDIO);
361    //    exit(1);
362    //    }
363 
364    for (loop = 0; loop < 4; loop++)
365        {
366        ch[loop].samp=0; /* GFE : added this to avoid nasty core dumps :) */
367        ch[loop].pointer = 0;
368        ch[loop].step = 0;
369        ch[loop].volume = 0;
370        ch[loop].pitch = 0;
371        }
372 
373    printf("\nPosition (%d):", songlength);
374    fflush(stdout);
375 
376    for (pat_num = 0; pat_num < songlength; pat_num++)
377        {
378        printf("\r\t\t%3d", pat_num);
379        fflush(stdout);
380        pat = tune[pat_num];
381        end_pattern = 0;
382        for (notes = 0; notes < 64; notes++)
383            {
384            for (channel = 0; channel < 4; channel++)
385                {
386                int samp, pitch, cmd, para;
387
388                samp = patterns[pat].sample[notes][channel];
389                pitch = patterns[pat].period[notes][channel];
390                cmd = patterns[pat].effect[notes][channel];
391                para = patterns[pat].params[notes][channel];
392                if (samp)
393                    {
394                    ch[channel].samp = samp;
395                        /* load new instrument */
396                    ch[channel].volume = voices[ch[channel].samp].volume;
397                    }
398                        /* If sample number=0 and no new period */
399                        /* continue last note */
400                if (pitch && cmd != 3)
401                    {
402                    ch[channel].pointer = 0;
403                    ch[channel].step = step_table[pitch];
404                    ch[channel].pitch = pitch;
405                    }
406                ch[channel].doslide = 0;
407                ch[channel].doslidevol = 0;
408                ch[channel].doporta = 0;
409                switch(cmd)  /* Do effects */
410                    {
411                case 0xF :
412                    speed = para;
413                    break;
414                case 0xD :
415                    end_pattern = 1;
416                    break;
417                case 0xC :
418                    ch[channel].volume= MIN(para, 64);
419                    ch[channel].volume /= 64;
420                    break;
421                    /* volume_slicur_chunk_indexde */
422  case 0xB :
423      pat_num = (para & 0xF) + (10 * (para >> 4));
424      break;
425                case 0xA :
426                    ch[channel].doslidevol = 1;
427                    if (para)
428                        {
429                        if (para & 15)
430                            ch[channel].volslide = - para / 64;
431                        else
432                            ch[channel].volslide = (para >> 4)/64;
433                        }
434                    break;
435                case 3   :
436                    ch[channel].doporta = 1;
437                    if (para)
438                        ch[channel].portarate = para;
439                    if (pitch)
440                        ch[channel].pitchgoal = pitch;
441                    break;
442                case 2   :
443                    ch[channel].doslide = 1;
444                    if (para)
445                        ch[channel].slide = para;
446                    break;
447                case 1   :
448                    ch[channel].doslide = 1;
449                    if (para)
450                        ch[channel].slide = -para;
451                    break;
452                case 0   :
453                    break;
454                default  :
455                    /* printf(" [%d][%d] ", cmd, para); */
456                    break;
457                    }
458                }
459                /* 1 vsync = 0.02 sec */
460            for (vsync = 0; vsync < speed; vsync++)
461                {
462                    /* 160*125uSec = 0.02 */
463                for (bytes = 0; bytes < VSYNC; bytes++)
464                    {
465                    byte = 0;
466                    for (channel = 0; channel < 4; channel++)
467                        {
468                        if (ch[channel].samp == 0)
469                            continue;
470                            /* If at end of sample jump to rep_start position */
471                        if (voices[ch[channel].samp].rep_end)
472                            {
473                            if ((ch[channel].pointer >> 16) >=
474                                voices[ch[channel].samp].rep_end)
475                                    ch[channel].pointer +=
476                                    (voices[ch[channel].samp].rep_start -
477                                    voices[ch[channel].samp].length)<< 16;
478                            }
479                        else
480                            if ((ch[channel].pointer >> 16) >=
481                                voices[ch[channel].samp].length)
482                                continue;
483                        /* byte = sum of (sample byte * volume) for each */
484                        /* of 4 channels which mixes the sounds          */
485                        if ((ch[channel].pointer >> 16) <
486                            voices[ch[channel].samp].length)
487                            {
488                            byte += (int) ( (voices[ch[channel].samp]
489                                .info[ch[channel].pointer >> 16])
490                                * (ch[channel].volume));
491                            ch[channel].pointer += ch[channel].step;
492                            }
493                        } // of for channel
494
495                                        // clip
496                    if (byte>127) byte=127;
497                    if (byte<-128) byte=-128;
498                   
499                    // make unsigned
500                    byte+=128;
501                    byte /= 4;
502
503                    // fputc(byte, audio);                /* and play the note */
504                    cur_chunk[cur_chunk_index]=byte;       
505                    cur_chunk_index++;
506                    } // of for bytes
507                    insert_cur_chunk();
508                    cur_chunk_index=0;
509                    /* Do end of vsync */
510                if (vsync == 0)
511                    continue;
512                for (channel = 0; channel < 4; channel++)
513                    {
514                    if (ch[channel].doslide)             /* effects */
515                        {
516                        ch[channel].pitch += ch[channel].slide;
517                        ch[channel].pitch = MIN(ch[channel].pitch, 1023);
518                        ch[channel].pitch = MAX(ch[channel].pitch, 113);
519                        ch[channel].step = step_table[ch[channel].pitch];
520                        }
521                    if (ch[channel].doslidevol)
522                        {
523                        ch[channel].volume += ch[channel].volslide;
524                        if (ch[channel].volume < 0.0)
525                            ch[channel].volume = 0.0;
526                        else if (ch[channel].volume >= 1.0)
527                            ch[channel].volume = 1.0;
528                        }
529                    if (ch[channel].doporta)
530                        {
531                        if (ch[channel].pitch < ch[channel].pitchgoal)
532                            {
533                            ch[channel].pitch += ch[channel].portarate;
534                            if (ch[channel].pitch > ch[channel].pitchgoal)
535                                ch[channel].pitch = ch[channel].pitchgoal;
536                            }
537                        else if (ch[channel].pitch > ch[channel].pitchgoal)
538                            {
539                            ch[channel].pitch -= ch[channel].portarate;
540                            if (ch[channel].pitch < ch[channel].pitchgoal)
541                                ch[channel].pitch = ch[channel].pitchgoal;
542                            }
543                        }
544                    }
545                }
546            if (end_pattern == 1)
547                break;
548            } // of for notes
549                    for (loop = 0; loop < 4; loop++)
550                    {
551                        ch[loop].samp=0; /* GFE : added this to avoid nasty core dumps :) */
552                        ch[loop].pointer = 0;
553                        ch[loop].step = 0;
554                        ch[loop].volume = 0;
555                        ch[loop].pitch = 0;
556                    }
557        } // of for pattern
558
559    // fclose(audio);
560    rebuild_from_chunks("out2.raw");
561    build_outfiles("MOD");
562    printf("\n");
563    fprintf(stdout,"%d chunks %d chunks in song\n",nb_chunk,song_chunks_index);
564    return (0);
565    }
Note: See TracBrowser for help on using the repository browser.