1 // This file contains utilities for writing a wave file.
2 
3 #include <ctype.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <stddef.h>
8 #include "CrossPlatformFileIO.h"
9 #include "IgorBin.h"
10 #include "PackedFileDemo.h"
11 
12 /*	Checksum(data,oldcksum,numbytes)
13 
14  	Returns shortwise simpleminded checksum over the data.
15 	ASSUMES data starts on an even boundary.
16 */
17 static int
Checksum(short * data,int oldcksum,int numbytes)18 Checksum(short *data, int oldcksum, int numbytes)
19 {
20 	numbytes >>= 1;				// 2 bytes to a short -- ignore trailing odd byte.
21 	while(numbytes-- > 0)
22 		oldcksum += *data++;
23 	return oldcksum&0xffff;
24 }
25 
26 /*	NumBytesPerPoint(int type)
27 
28 	Given a numeric wave type, returns the number of data bytes per point.
29 */
30 static int
NumBytesPerPoint(int type)31 NumBytesPerPoint(int type)
32 {
33 	int numBytesPerPoint;
34 
35 	// Consider the number type, not including the complex bit or the unsigned bit.
36 	switch(type & ~(NT_CMPLX | NT_UNSIGNED)) {
37 		case NT_I8:
38 			numBytesPerPoint = 1;		// char
39 			break;
40 		case NT_I16:
41 			numBytesPerPoint = 2;		// short
42 			break;
43 		case NT_I32:
44 			numBytesPerPoint = 4;		// long
45 			break;
46 		case NT_FP32:
47 			numBytesPerPoint = 4;		// float
48 			break;
49 		case NT_FP64:
50 			numBytesPerPoint = 8;		// double
51 			break;
52 		default:
53 			return 0;
54 			break;
55 	}
56 
57 	if (type & NT_CMPLX)
58 		numBytesPerPoint *= 2;			// Complex wave - twice as many points.
59 
60 	return numBytesPerPoint;
61 }
62 
63 /*	WriteVersion2NumericWave(fr, whp, data, waveNote, noteSize)
64 
65 	Writes an Igor version 2 binary wave with the properties specified in
66 	whp, the data specified by data, and the wave note specified by waveNote
67 	and noteSize.
68 
69 	Returns 0 or an error code.
70 */
71 int
WriteVersion2NumericWave(CP_FILE_REF fr,WaveHeader2 * whp,const void * data,const char * waveNote,long noteSize)72 WriteVersion2NumericWave(CP_FILE_REF fr, WaveHeader2* whp, const void* data, const char* waveNote, long noteSize)
73 {
74 	unsigned long numBytesToWrite;
75 	unsigned long numBytesWritten;
76 	unsigned long waveDataSize;
77 	int numBytesPerPoint;
78 	short cksum;
79 	BinHeader2 bh;
80 	char padding[16];
81 	int err;
82 
83 	numBytesPerPoint = NumBytesPerPoint(whp->type);
84 	if (numBytesPerPoint <= 0) {
85 		printf("Invalid wave type (0x%x).\n", whp->type);
86 		return -1;
87 	}
88 	waveDataSize = whp->npnts * numBytesPerPoint;
89 
90 	// Prepare the BinHeader structure.
91 	memset(&bh,0,sizeof(struct BinHeader2));
92 	bh.version = 2;
93 	bh.wfmSize = offsetof(WaveHeader2, wData) + waveDataSize + 16;	// Includes 16 bytes padding.
94 	bh.noteSize = noteSize;
95 
96 	/*	The checksum is over the BinHeader2 structure and the WaveHeader2 structure.
97 		The wData field of the WaveHeader2 structure is assumed to contain the same
98 		data as the first 16 bytes of the actual wave data. This is necessary
99 		to get the correct checksum.
100 	*/
101 	cksum = Checksum((short *)&bh, 0, sizeof(struct BinHeader2));
102 	cksum = Checksum((short *)whp, cksum, sizeof(struct WaveHeader2));
103 	bh.checksum = -cksum;
104 
105 	do {
106 		// Write the BinHeader.
107 		numBytesToWrite = sizeof(struct BinHeader2);
108 		if (err = CPWriteFile(fr, numBytesToWrite, &bh, &numBytesWritten))
109 			break;
110 
111 		// Write the WaveHeader, up to but not including the wData field.
112 		numBytesToWrite = offsetof(WaveHeader2, wData);
113 		if (err = CPWriteFile(fr, numBytesToWrite, whp, &numBytesWritten))
114 			break;
115 
116 		// Write the wave data.
117 		numBytesToWrite = waveDataSize;
118 		if (err = CPWriteFile(fr, numBytesToWrite, data, &numBytesWritten))
119 			break;
120 
121 		// Write the 16 byte padding.
122 		memset(padding, 0, 16);								// Write padding at the end of the wave data.
123 		numBytesToWrite = 16;
124 		if (err = CPWriteFile(fr, numBytesToWrite, padding, &numBytesWritten))
125 			break;
126 
127 		// Now write optional data, in the correct order.
128 
129 		// Write the wave note.
130 		numBytesToWrite = noteSize;
131 		if (numBytesToWrite > 0) {
132 			if (err = CPWriteFile(fr, numBytesToWrite, waveNote, &numBytesWritten))
133 				break;
134 		}
135 
136 	} while(0);
137 
138 	return err;
139 }
140 
141 /*	WriteVersion5NumericWave(fr, whp, data, waveNote, noteSize)
142 
143 	Writes an Igor version 5 binary wave with the properties specified in
144 	whp, the data specified by data, and the wave note specified by waveNote
145 	and noteSize.
146 
147 	Returns 0 or an error code.
148 */
149 int
WriteVersion5NumericWave(CP_FILE_REF fr,WaveHeader5 * whp,const void * data,const char * waveNote,long noteSize)150 WriteVersion5NumericWave(CP_FILE_REF fr, WaveHeader5* whp, const void* data, const char* waveNote, long noteSize)
151 {
152 	unsigned long numBytesToWrite;
153 	unsigned long numBytesWritten;
154 	unsigned long waveDataSize;
155 	int numBytesPerPoint;
156 	short cksum;
157 	BinHeader5 bh;
158 	int err;
159 
160 	numBytesPerPoint = NumBytesPerPoint(whp->type);
161 	if (numBytesPerPoint <= 0) {
162 		printf("Invalid wave type (0x%x).\n", whp->type);
163 		return -1;
164 	}
165 	waveDataSize = whp->npnts * numBytesPerPoint;
166 
167 	// Prepare the BinHeader structure.
168 	memset(&bh,0,sizeof(struct BinHeader5));
169 	bh.version = 5;
170 	bh.wfmSize = offsetof(WaveHeader5, wData) + waveDataSize;
171 	bh.noteSize = noteSize;
172 
173 	/*	The checksum is over the BinHeader5 structure and the WaveHeader5 structure,
174 		excluding the wData field.
175 	*/
176 	cksum = Checksum((short *)&bh, 0, sizeof(BinHeader5));
177 	cksum = Checksum((short *)whp, cksum, offsetof(WaveHeader5, wData));
178 	bh.checksum = -cksum;
179 
180 	do {
181 		// Write the BinHeader.
182 		numBytesToWrite = sizeof(struct BinHeader5);
183 		if (err = CPWriteFile(fr, numBytesToWrite, &bh, &numBytesWritten))
184 			break;
185 
186 		// Write the WaveHeader, up to but not including the wData field.
187 		numBytesToWrite = offsetof(WaveHeader5, wData);
188 		if (err = CPWriteFile(fr, numBytesToWrite, whp, &numBytesWritten))
189 			break;
190 
191 		// Write the wave data.
192 		numBytesToWrite = waveDataSize;
193 		if (err = CPWriteFile(fr, numBytesToWrite, data, &numBytesWritten))
194 			break;
195 
196 		// Now write optional data, in the correct order.
197 
198 		// Write the wave note.
199 		numBytesToWrite = noteSize;
200 		if (numBytesToWrite > 0) {
201 			if (err = CPWriteFile(fr, numBytesToWrite, waveNote, &numBytesWritten))
202 				break;
203 		}
204 
205 	} while(0);
206 
207 	return err;
208 }
209 
210