|
|
1.1 root 1: /*
2: Hatari - wavFormat.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: WAV File output
8:
9: As well as YM file output we also have output in .WAV format. These .WAV
10: files can then be run through convertors to any other format, such as MP3.
11: We simply save out the WAVE format headers and then write the sample data
12: (at the current rate of playback) as we build it up each frame. When we stop
13: recording we complete the size information in the headers and close up.
14:
15:
16: RIFF Chunk (12 bytes in length total) Byte Number
17: 0 - 3 "RIFF" (ASCII Characters)
18: 4 - 7 Total Length Of Package To Follow (Binary, little endian)
19: 8 - 12 "WAVE" (ASCII Characters)
20:
21: FORMAT Chunk (24 bytes in length total) Byte Number
22: 0 - 3 "fmt_" (ASCII Characters)
23: 4 - 7 Length Of FORMAT Chunk (Binary, always 0x10)
24: 8 - 9 Always 0x01
25: 10 - 11 Channel Numbers (Always 0x01=Mono, 0x02=Stereo)
26: 12 - 15 Sample Rate (Binary, in Hz)
27: 16 - 19 Bytes Per Second
28: 20 - 21 Bytes Per Sample: 1=8 bit Mono, 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo
29: 22 - 23 Bits Per Sample
30:
31: DATA Chunk Byte Number
32: 0 - 3 "data" (ASCII Characters)
33: 4 - 7 Length Of Data To Follow
34: 8 - end Data (Samples)
35: */
36: const char WAVFormat_fileid[] = "Hatari wavFormat.c : " __DATE__ " " __TIME__;
37:
38: #include <SDL_endian.h>
39:
40: #include "main.h"
41: #include "audio.h"
42: #include "configuration.h"
43: #include "file.h"
44: #include "log.h"
45: #include "sound.h"
46: #include "wavFormat.h"
47:
48:
49: static FILE *WavFileHndl;
50: static int nWavOutputBytes; /* Number of samples bytes saved */
51: bool bRecordingWav = false; /* Is a WAV file open and recording? */
52:
53:
54: static Uint8 WavHeader[] =
55: {
56: /* RIFF chunk */
57: 'R', 'I', 'F', 'F', /* "RIFF" (ASCII Characters) */
58: 0, 0, 0, 0, /* Total Length Of Package To Follow (patched when file is closed) */
59: 'W', 'A', 'V', 'E', /* "WAVE" (ASCII Characters) */
60: /* Format chunk */
61: 'f', 'm', 't', ' ', /* "fmt_" (ASCII Characters) */
62: 0x10, 0, 0, 0, /* Length Of FORMAT Chunk (always 0x10) */
63: 0x01, 0, /* Always 0x01 */
64: 0x02, 0, /* Number of channels (2 for stereo) */
65: 0, 0, 0, 0, /* Sample rate (patched when file header is written) */
66: 0, 0, 0, 0, /* Bytes per second (patched when file header is written) */
67: 0x04, 0, /* Bytes per sample (4 = 16 bit stereo) */
68: 0x10, 0, /* Bits per sample (16 bit) */
69: /* Data chunk */
70: 'd', 'a', 't', 'a',
71: 0, 0, 0, 0, /* Length of data to follow (will be patched when file is closed) */
72: };
73:
74:
75: /**
76: * Open WAV output file and write header.
77: */
78: bool WAVFormat_OpenFile(char *pszWavFileName)
79: {
80:
81: Uint32 nSampleFreq, nBytesPerSec;
82:
83: bRecordingWav = false;
84: nWavOutputBytes = 0;
85:
86: /* Set frequency (11Khz, 22Khz or 44Khz) */
87: nSampleFreq = ConfigureParams.Sound.nPlaybackFreq;
88: /* multiply by 4 for 16 bit stereo */
89: nBytesPerSec = nSampleFreq * 4;
90:
91: /* Create our file */
92: WavFileHndl = fopen(pszWavFileName, "wb");
93: if (!WavFileHndl)
94: {
95: perror("WAVFormat_OpenFile");
96: Log_AlertDlg(LOG_ERROR, "WAV recording: Failed to open file!");
97: return false;
98: }
99:
100: /* Patch sample frequency in header structure */
101: WavHeader[24] = (Uint8)nSampleFreq;
102: WavHeader[25] = (Uint8)(nSampleFreq >> 8);
103: WavHeader[26] = (Uint8)(nSampleFreq >> 16);
104: WavHeader[27] = (Uint8)(nSampleFreq >> 24);
105:
106: /* Patch bytes per second in header structure */
107: WavHeader[28] = (Uint8)nBytesPerSec;
108: WavHeader[29] = (Uint8)(nBytesPerSec >> 8);
109: WavHeader[30] = (Uint8)(nBytesPerSec >> 16);
110: WavHeader[31] = (Uint8)(nBytesPerSec >> 24);
111:
112: /* Write header to file */
113: if (fwrite(&WavHeader, sizeof(WavHeader), 1, WavFileHndl) == 1)
114: {
115: bRecordingWav = true;
116: Log_AlertDlg(LOG_INFO, "WAV sound data recording has been started.");
117: }
118: else
119: {
120: perror("WAVFormat_OpenFile");
121: Log_AlertDlg(LOG_ERROR, "WAV recording: Failed to write header!");
122: }
123:
124: /* Ok, or failed? */
125: return bRecordingWav;
126: }
127:
128:
129: /**
130: * Write sizes to WAV header, then close the WAV file.
131: */
132: void WAVFormat_CloseFile(void)
133: {
134: if (bRecordingWav)
135: {
136: Uint32 nWavFileBytes;
137: Uint32 nWavLEOutBytes;
138:
139: bRecordingWav = false;
140:
141: /* Update headers with sizes */
142: nWavFileBytes = SDL_SwapLE32((12+24+8+nWavOutputBytes)-8); /* File length, less 8 bytes for 'RIFF' and length */
143: fseek(WavFileHndl, 4, SEEK_SET); /* 'Total Length Of Package' element */
144: /* Write total length of package in 'RIFF' chunk */
145: if (fwrite(&nWavFileBytes, sizeof(Uint32), 1, WavFileHndl) != 1)
146: {
147: perror("WAVFormat_CloseFile");
148: fclose(WavFileHndl);
149: WavFileHndl = NULL;
150: return;
151: }
152:
153: fseek(WavFileHndl, 12+24+4, SEEK_SET); /* 'Length' element */
154: nWavLEOutBytes = SDL_SwapLE32(nWavOutputBytes);
155: /* Write length of data in 'DATA' chunk */
156: if (fwrite(&nWavLEOutBytes, sizeof(Uint32), 1, WavFileHndl) != 1)
157: {
158: perror("WAVFormat_CloseFile");
159: }
160:
161: /* Close file */
162: fclose(WavFileHndl);
163: WavFileHndl = NULL;
164:
165: /* And inform user */
166: Log_AlertDlg(LOG_INFO, "WAV Sound data recording has been stopped.");
167: }
168: }
169:
170:
171: /**
172: * Update WAV file with current samples
173: */
174: void WAVFormat_Update(Sint16 pSamples[][2], int Index, int Length)
175: {
176: Sint16 sample[2];
177: int i;
178:
179: if (bRecordingWav)
180: {
181: /* Output, better if did in two section if wrap */
182: for(i = 0; i < Length; i++)
183: {
184: /* Convert sample to little endian */
185: sample[0] = SDL_SwapLE16(pSamples[(Index+i)%MIXBUFFER_SIZE][0]);
186: sample[1] = SDL_SwapLE16(pSamples[(Index+i)%MIXBUFFER_SIZE][1]);
187: /* And store */
188: if (fwrite(&sample, sizeof(sample), 1, WavFileHndl) != 1)
189: {
190: perror("WAVFormat_Update");
191: WAVFormat_CloseFile();
192: return;
193: }
194: }
195:
196: /* Add samples to wav file length counter */
197: nWavOutputBytes += Length * 4;
198: }
199: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.