1 /*--------------------------------------------------------------------------*
2   Project:  Revolution Audio sound file converter
3   File:     output.c
4 
5   Copyright (C)1998-2006 Nintendo  All Rights Reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Log: output.c,v $
14   Revision 1.2  02/09/2006 06:26:26  aka
15   Changed copyright.
16 
17 
18  *--------------------------------------------------------------------------*/
19 #include <stdio.h>
20 #include <memory.h>
21 #include <string.h>
22 #include "soundconv.h"
23 #include "endian.h"
24 #include "types.h"
25 
26 
27 /*--------------------------------------------------------------------------*
28     exports for dsptool.dll
29  *--------------------------------------------------------------------------*/
30 typedef int (*FUNCTION3)(int);
31 extern FUNCTION3 getNibbleAddress;
32 
33 
34 /*--------------------------------------------------------------------------*
35     local variables
36  *--------------------------------------------------------------------------*/
37 u32         soundEntries;
38 u32         soundAdpcmEntries;
39 u32         soundByteOffset;
40 
41 SNDCONVDATA soundConvdata[0xFFFF];
42 ADPCMINFO   soundAdpcminfo[0xFFFF];
43 
44 FILE        *outputHeader;
45 FILE        *outputTable;
46 FILE        *outputSamples;
47 
48 /*--------------------------------------------------------------------------*
49     add an entry
50  *--------------------------------------------------------------------------*/
soundOutputAddEntry(u32 format,u32 dataBytes,void * buffer,u32 samples,u32 sampleRate,u32 loopStart,u32 loopEnd,ADPCMINFO * adpcminfo,char * headerId)51 void soundOutputAddEntry(
52         u32         format,
53         u32         dataBytes,
54         void        *buffer,
55         u32         samples,
56         u32         sampleRate,
57         u32         loopStart,
58         u32         loopEnd,
59         ADPCMINFO   *adpcminfo,
60         char        *headerId
61         )
62 {
63     SNDCONVDATA *sndconvdata = &soundConvdata[soundEntries];
64 
65     switch (format)
66     {
67     case SOUND_FORMAT_ADPCM:
68 
69         // 8 byte-aligned ADPCM buffers
70         while (soundByteOffset % 8)
71         {
72             char ch = 0;
73             fwrite(&ch, 1, 1, outputSamples);
74             soundByteOffset++;
75         }
76 
77         // looped sound
78         if (loopEnd)
79         {
80             sndconvdata->type           = SP_TYPE_ADPCM_LOOPED;
81             sndconvdata->sampleRate     = sampleRate;
82             sndconvdata->loopAddr       = (soundByteOffset << 1) + getNibbleAddress(loopStart);
83             sndconvdata->loopEndAddr    = (soundByteOffset << 1) + getNibbleAddress(loopEnd);
84             sndconvdata->endAddr        = (soundByteOffset << 1) + getNibbleAddress(samples - 1);
85             sndconvdata->currentAddr    = (soundByteOffset << 1) + getNibbleAddress(0);
86             sndconvdata->adpcm          = 0;
87         }
88         else
89         {
90             sndconvdata->type           = SP_TYPE_ADPCM_ONESHOT;
91             sndconvdata->sampleRate     = sampleRate;
92             sndconvdata->loopAddr       = 0;
93             sndconvdata->loopEndAddr    = 0;
94             sndconvdata->endAddr        = (soundByteOffset << 1) + getNibbleAddress(samples - 1);
95             sndconvdata->currentAddr    = (soundByteOffset << 1) + getNibbleAddress(0);
96             sndconvdata->adpcm          = 0;
97         }
98 
99         // write the buffer to data file
100         fwrite(buffer, 1, dataBytes, outputSamples);
101         soundByteOffset += dataBytes;
102 
103         // store the ADPCMINFO
104         memcpy(
105             &soundAdpcminfo[soundAdpcmEntries],
106             adpcminfo,
107             sizeof(ADPCMINFO)
108             );
109 
110         soundAdpcmEntries++;
111 
112         break;
113 
114     case SOUND_FORMAT_PCM8:
115 
116         // looped sound
117         if (loopEnd)
118         {
119             sndconvdata->type           = SP_TYPE_PCM8_LOOPED;
120             sndconvdata->sampleRate     = sampleRate;
121             sndconvdata->loopAddr       = soundByteOffset + loopStart;
122             sndconvdata->loopEndAddr    = soundByteOffset + loopEnd;
123             sndconvdata->endAddr        = soundByteOffset + samples - 1;
124             sndconvdata->currentAddr    = soundByteOffset;
125             sndconvdata->adpcm          = 0;
126         }
127         else
128         {
129             sndconvdata->type           = SP_TYPE_PCM8_ONESHOT;
130             sndconvdata->sampleRate     = sampleRate;
131             sndconvdata->loopAddr       = 0;
132             sndconvdata->loopEndAddr    = 0;
133             sndconvdata->endAddr        = soundByteOffset + samples - 1;
134             sndconvdata->currentAddr    = soundByteOffset;
135             sndconvdata->adpcm          = 0;
136         }
137 
138         // write the buffer to data file
139         fwrite(buffer, 1, dataBytes, outputSamples);
140         soundByteOffset += dataBytes;
141 
142         break;
143 
144     case SOUND_FORMAT_PCM16:
145 
146         // 16 bit-aligned the data
147         if (soundByteOffset & 1)
148         {
149             char ch = 0;
150             fwrite(&ch, 1, 1, outputSamples);
151             soundByteOffset++;
152         }
153 
154         // looped sound
155         if (loopEnd)
156         {
157             sndconvdata->type           = SP_TYPE_PCM16_LOOPED;
158             sndconvdata->sampleRate     = sampleRate;
159             sndconvdata->loopAddr       = (soundByteOffset >> 1) + loopStart;
160             sndconvdata->loopEndAddr    = (soundByteOffset >> 1) + loopEnd;
161             sndconvdata->endAddr        = (soundByteOffset >> 1) + samples - 1;
162             sndconvdata->currentAddr    = soundByteOffset >> 1;
163             sndconvdata->adpcm          = 0;
164         }
165         else
166         {
167             sndconvdata->type           = SP_TYPE_PCM16_ONESHOT;
168             sndconvdata->sampleRate     = sampleRate;
169             sndconvdata->loopAddr       = 0;
170             sndconvdata->loopEndAddr    = 0;
171             sndconvdata->endAddr        = (soundByteOffset >> 1) + samples - 1;
172             sndconvdata->currentAddr    = soundByteOffset >> 1;
173             sndconvdata->adpcm          = 0;
174         }
175 
176         // reverse the endian then write the buffer to data file
177         reverse_buffer_16(buffer, samples);
178         fwrite(buffer, 1, dataBytes, outputSamples);
179         soundByteOffset += dataBytes;
180 
181         break;
182     }
183 
184     if (outputHeader)
185         fprintf(outputHeader, "#define %s\t\t%d\n", headerId, soundEntries);
186 
187     soundEntries++;
188 }
189 
190 
191 /*--------------------------------------------------------------------------*
192     print the table file ... call this once at end of program
193  *--------------------------------------------------------------------------*/
soundOutputWriteTable(void)194 void soundOutputWriteTable(void)
195 {
196     if (outputTable)
197     {
198         u32         data;
199         SNDCONVDATA *sndconvdata;
200         ADPCMINFO   *adpcminfo;
201 
202         // write number of entries
203         data = reverse_endian_32(soundEntries);
204         fwrite(&data, 1, sizeof(u32), outputTable);
205 
206         // write sound entries
207         sndconvdata = soundConvdata;
208         while (soundEntries)
209         {
210             sndconvdata->type           = reverse_endian_32(sndconvdata->type);
211             sndconvdata->sampleRate     = reverse_endian_32(sndconvdata->sampleRate);
212             sndconvdata->loopAddr       = reverse_endian_32(sndconvdata->loopAddr);
213             sndconvdata->loopEndAddr    = reverse_endian_32(sndconvdata->loopEndAddr);
214             sndconvdata->endAddr        = reverse_endian_32(sndconvdata->endAddr);
215             sndconvdata->currentAddr    = reverse_endian_32(sndconvdata->currentAddr);
216             sndconvdata->adpcm          = 0;
217 
218             fwrite(sndconvdata, 1, sizeof(SNDCONVDATA), outputTable);
219 
220             sndconvdata++;
221             soundEntries--;
222         }
223 
224         // write apdcm entries
225         adpcminfo = soundAdpcminfo;
226         while (soundAdpcmEntries)
227         {
228             u16 *p;
229             int i;
230 
231             p = (u16*)adpcminfo;
232 
233             for (i = 0; i < sizeof(ADPCMINFO) / 2; i++)
234             {
235                 *p = reverse_endian_16(*p);
236                 p++;
237             }
238 
239             fwrite(adpcminfo, 1, sizeof(ADPCMINFO), outputTable);
240 
241             adpcminfo++;
242             soundAdpcmEntries--;
243         }
244     }
245 }
246 
247 
248 /*--------------------------------------------------------------------------*
249     print comment to header file
250  *--------------------------------------------------------------------------*/
soundOutputComment(char * ch)251 void soundOutputComment(char *ch)
252 {
253     if (outputHeader)
254         fwrite(ch, strlen(ch), 1, outputHeader);
255 }
256 
257 
258 /*--------------------------------------------------------------------------*
259     quit code module
260  *--------------------------------------------------------------------------*/
soundOutputQuit(void)261 void soundOutputQuit(void)
262 {
263     soundOutputWriteTable();
264 
265     if (outputHeader)   fclose(outputHeader);
266     if (outputTable)    fclose(outputTable);
267     if (outputSamples)  fclose(outputSamples);
268 }
269 
270 
271 /*--------------------------------------------------------------------------*
272     init code module
273  *--------------------------------------------------------------------------*/
soundOutputInit(char * name)274 int soundOutputInit(char *name)
275 {
276     char ch[1024];
277 
278     soundEntries        = 0;
279     soundAdpcmEntries   = 0;
280     soundByteOffset     = 0;
281 
282     sprintf(ch, "%s.h", name);
283     outputHeader = fopen(ch, "w");
284 
285     sprintf(ch, "%s.spt", name);
286     outputTable = fopen(ch, "wb");
287 
288     sprintf(ch, "%s.spd", name);
289     outputSamples = fopen(ch, "wb");
290 
291     if (outputHeader && outputTable && outputSamples)
292         return STATUS_SUCCESS;
293 
294     soundOutputQuit();
295 
296     if (outputHeader == NULL)
297     {
298         printf("Error: Can't open %s.h\n", name);
299     }
300 
301     if (outputTable == NULL)
302     {
303         printf("Error: Can't open %s.spt\n", name);
304     }
305 
306     if (outputSamples == NULL)
307     {
308         printf("Error: Can't open %s.spd\n", name);
309     }
310 
311     return STATUS_ERROR;
312 }
313