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