1 // Copyright (c) <2012> <Leif Asbrink>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without restriction,
6 // including without limitation the rights to use, copy, modify,
7 // merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 
24 #include <stdio.h>
25 #include <math.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include "globdef.h"
31 
32 #if(IA64 == 0)
33 #define QWORD long
34 #else
35 #define QWORD int
36 #endif
37 
38 
39 #if(OSNUM == OSNUM_WINDOWS)
40 #include <windows.h>
41 #endif
42 
43 
44 #if(OSNUM == OSNUM_LINUX)
45 #define INVSOCK -1
46 #define WORD unsigned short int
47 #define DWORD u_int32_t
48 
49 typedef struct _SYSTEMTIME {
50 	WORD wYear;
51 	WORD wMonth;
52 	WORD wDayOfWeek;
53 	WORD wDay;
54 	WORD wHour;
55 	WORD wMinute;
56 	WORD wSecond;
57 	WORD wMilliseconds;
58 } SYSTEMTIME;
59 
60 #endif
61 
62 typedef struct rcvr_hdr{
63   char           chunkID[4];         // ="rcvr" (chunk perseus beta0.2)
64   QWORD          chunkSize;          // chunk length
65   QWORD          nCenterFrequencyHz; // center frequency
66   QWORD          SamplingRateIdx;    // 0=125K, 1=250K, 2=500K, 3=1M, 4=2M
67   time_t         timeStart;          // start time of the recording (time(&timeStart))
68   unsigned short wAttenId;           // 0=0dB, 1=10dB, 2=20dB, 3=30dB
69   char           bAdcPresel;         // 0=Presel Off, 1=Presel On
70   char           bAdcPreamp;         // 0=ADC Preamp Off, 1=ADC Preamp ON
71   char           bAdcDither;         // 0=ADC Dither Off, 1=ADC Dither ON
72   char           bSpare;             // for future use (default = 0)
73   char           rsrvd[16];          // for future use (default = 000..0)
74   char           extra[16];          // QS1R and others may use longer chunks
75   }RCVR;
76 
77 
78 // "auxi" chunk as used in the SpectraVue WAV files
79 typedef struct auxi_hdr{
80   char       chunkID[4];  // ="auxi" (chunk rfspace)
81   QWORD      chunkSize;   // chunk length
82   SYSTEMTIME StartTime;
83   SYSTEMTIME StopTime;
84   DWORD      CenterFreq;  //receiver center frequency
85   DWORD      ADFrequency; //A/D sample frequency before downsampling
86   DWORD      IFFrequency; //IF freq if an external down converter is used
87   DWORD      Bandwidth;   //displayable BW if you want to limit the display to less than Nyquist band
88   DWORD      IQOffset;    //DC offset of the I and Q channels in 1/1000's of a count
89   DWORD      Unused2;
90   DWORD      Unused3;
91   DWORD      Unused4;
92   DWORD      Unused5;
93   }AUXI;
94 RCVR perseus_hdr;
95 AUXI sdr14_hdr;
96 
main(int argc,char * argv[])97 int main(int argc, char *argv[])
98 {
99 int rx_ad_speed;
100 short int rx_ad_channels, block_align;
101 int i, j, k, m, errnr;
102 unsigned int file_bytes, data_bytes, bytes_per_second;
103 unsigned int chunk_size;
104 short int format_tag;
105 char s[200];
106 char *ich;
107 FILE *save_rd_file, *save_wr_file;
108 double dt1;
109 sdr14_hdr.chunkID[0]='a';
110 sdr14_hdr.chunkID[1]='u';
111 sdr14_hdr.chunkID[2]='x';
112 sdr14_hdr.chunkID[3]='i';
113 sdr14_hdr.chunkSize=sizeof(sdr14_hdr)-8;
114 sdr14_hdr.StartTime.wYear=2011;
115 sdr14_hdr.StartTime.wMonth=1;
116 sdr14_hdr.StartTime.wDayOfWeek=5;
117 sdr14_hdr.StartTime.wDay=1;
118 sdr14_hdr.StartTime.wHour=8;
119 sdr14_hdr.StartTime.wMinute=1;
120 sdr14_hdr.StartTime.wSecond=1;
121 sdr14_hdr.ADFrequency=66666666;
122 sdr14_hdr.IFFrequency=0;
123 sdr14_hdr.Bandwidth=0;
124 sdr14_hdr.IQOffset=0;
125 sdr14_hdr.Unused2=0;
126 sdr14_hdr.Unused3=0;
127 sdr14_hdr.Unused4=0;
128 sdr14_hdr.Unused5=0;
129 sdr14_hdr.CenterFreq=10000000;
130 
131 
132 if(argc != 2)
133   {
134   printf("Give a single filename as argument to this program. (ex sim.wav)");
135   exit(0);
136   }
137 i=0;
138 while(i<180 && argv[1][i]!=0)i++;
139 argv[1][i]=0;
140 sprintf(s,"spectravue-%s",argv[1]);
141 printf("\n Convert %s to Spectravue format (%s)\n\n",argv[1],s);
142 save_rd_file = fopen(argv[1], "rb");
143 if (save_rd_file == NULL)
144   {
145   printf("Could not open %s",argv[1]);
146   exit(1);
147   }
148 save_wr_file = fopen(s, "wb");
149 if (save_wr_file == NULL)
150   {
151   printf("Could not open %s\n",s);
152   exit(1);
153   }
154 // Read the WAV file header.
155 // First 4 bytes should be "RIFF"
156 k=fread(&i,sizeof(int),1,save_rd_file);
157 errnr=0;
158 if(k !=1)
159   {
160 headerr:;
161   printf("Error in .wav file header [%d]",errnr);
162   exit(1);
163   }
164 if(i != 0x46464952)
165   {
166   errnr=1;
167   goto headerr;
168   }
169 k=fwrite(&i,sizeof(int),1,save_wr_file);
170 if(k != 1)goto wrerr;
171 // Read file size (we do not need it)
172 k=fread(&file_bytes,sizeof(int),1,save_rd_file);
173 if(k!=1)
174   {
175   errnr=2;
176   goto headerr;
177   }
178 k=fwrite(&file_bytes,sizeof(int),1,save_wr_file);
179 if(k != 1)goto wrerr;
180 // Now we should read "WAVE"
181 k=fread(&i,sizeof(int),1,save_rd_file);
182 errnr=2;
183 if(k !=1 || i != 0x45564157)goto headerr;
184 k=fwrite(&i,sizeof(int),1,save_wr_file);
185 if(k != 1)goto wrerr;
186 // Now we should read "fmt "
187 k=fread(&i,sizeof(int),1,save_rd_file);
188 errnr=3;
189 if(k !=1 || i != 0x20746d66)goto headerr;
190 k=fwrite(&i,sizeof(int),1,save_wr_file);
191 if(k != 1)goto wrerr;
192 // read the size of the format chunk.
193 k=fread(&chunk_size,sizeof(int),1,save_rd_file);
194 errnr=4;
195 if(k !=1 )goto headerr;
196 k=fwrite(&chunk_size,sizeof(int),1,save_wr_file);
197 if(k != 1)goto wrerr;
198 // read the type of data (Format Tag). We only recognize PCM data!
199 k=fread(&format_tag,sizeof(short int),1,save_rd_file);
200 errnr=5;
201 if(k !=1 || (format_tag != 1 && format_tag != 3))
202   {
203   printf("Unknown wFormatTag.");
204   goto headerr;
205   }
206 k=fwrite(&format_tag,sizeof(short int),1,save_wr_file);
207 if(k != 1)goto wrerr;
208 // Read no of channels
209 k=fread(&rx_ad_channels,sizeof(short int),1,save_rd_file);
210 errnr=6;
211 if(k !=1 || rx_ad_channels < 1 || rx_ad_channels > 2)goto headerr;
212 k=fwrite(&rx_ad_channels,sizeof(short int),1,save_wr_file);
213 if(k != 1)goto wrerr;
214 // Read the sampling speed.
215 k=fread(&rx_ad_speed,sizeof(int),1,save_rd_file);
216 errnr=7;
217 sdr14_hdr.Bandwidth=rx_ad_speed;
218 if(k !=1 )goto headerr;
219 k=fwrite(&rx_ad_speed,sizeof(int),1,save_wr_file);
220 if(k != 1)goto wrerr;
221 // Read average bytes per second (do not care what it is)
222 errnr=8;
223 k=fread(&bytes_per_second,sizeof(int),1,save_rd_file);
224 if(k !=1 )goto headerr;
225 k=fwrite(&bytes_per_second,sizeof(int),1,save_wr_file);
226 if(k != 1)goto wrerr;
227 // Read block align to get 8 or 16 bit format .
228 k=fread(&block_align,sizeof(short int),1,save_rd_file);
229 errnr=9;
230 if(k !=1 )goto headerr;
231   switch (block_align/rx_ad_channels)
232   {
233   case 1:
234   errnr=10;
235   if(format_tag != 1)goto headerr;
236   break;
237 
238   case 2:
239   errnr=11;
240   if(format_tag != 1)goto headerr;
241   break;
242 
243   case 3:
244   errnr=12;
245   if(format_tag != 1)goto headerr;
246   break;
247 
248   case 4:
249   errnr=13;
250   if(format_tag != 3)goto headerr;
251   break;
252 
253   default:
254   goto headerr;
255   }
256 k=fwrite(&block_align,sizeof(short int),1,save_wr_file);
257 if(k != 1)goto wrerr;
258 // Skip extra bytes if present.
259 chunk_size-=14;
260 errnr=11;
261 while(chunk_size != 0)
262   {
263   k=fread(&i,1,1,save_rd_file);
264   if(k !=1 )goto headerr;
265   k=fwrite(&i,1,1,save_wr_file);
266   if(k != 1)goto wrerr;
267   chunk_size--;
268   }
269 // Read chunks until we encounter the "data" string (=0x61746164).
270 // Look for Perseus or SDR-14 headers.
271 errnr=12;
272 next_chunk:;
273 k=fread(&i,sizeof(int),1,save_rd_file);
274 if(k !=1 )goto headerr;
275 errnr=13;
276 // test for "rcvr"
277 if(i==0x72766372)
278   {
279   k=fread(&chunk_size,sizeof(int),1,save_rd_file);
280   if(k !=1 )goto headerr;
281   k=fread(&perseus_hdr.nCenterFrequencyHz,1,chunk_size,save_rd_file);
282   if(k != (int)chunk_size)goto headerr;
283 // Put the data into the sdr14 data structure
284   sdr14_hdr.CenterFreq=perseus_hdr.nCenterFrequencyHz;
285   goto next_chunk;
286   }
287 errnr=25;
288 // Look for DATA
289 if(i != 0x61746164)
290   {
291 // Unknown. Get the size and skip.
292   k=fread(&chunk_size,sizeof(int),1,save_rd_file);
293   if(k !=1 )goto headerr;
294   while(chunk_size != 0)
295     {
296     k=fread(&i,1,1,save_rd_file);
297     if(k !=1 )goto headerr;
298     chunk_size--;
299     }
300   goto next_chunk;
301   }
302 // Read how much data we have ( do not care)
303 k=fread(&data_bytes,sizeof(int),1,save_rd_file);
304 if(k !=1 )goto headerr;
305 j=data_bytes/bytes_per_second;
306 dt1=j+sdr14_hdr.StartTime.wSecond+60*sdr14_hdr.StartTime.wMinute+
307      sdr14_hdr.StartTime.wHour*3600;
308 sdr14_hdr.StopTime.wYear=sdr14_hdr.StartTime.wYear;
309 sdr14_hdr.StopTime.wMonth=sdr14_hdr.StartTime.wMonth;
310 sdr14_hdr.StopTime.wDayOfWeek=sdr14_hdr.StartTime.wDayOfWeek;
311 sdr14_hdr.StopTime.wDay=sdr14_hdr.StartTime.wDay;
312 sdr14_hdr.StopTime.wHour=dt1/3600;
313 dt1-=sdr14_hdr.StopTime.wHour*3600;
314 sdr14_hdr.StopTime.wMinute=dt1/60;
315 dt1-=sdr14_hdr.StopTime.wMinute*60;
316 sdr14_hdr.StopTime.wSecond=dt1;
317 k=fwrite(&sdr14_hdr.chunkID[0],sizeof(sdr14_hdr),1,save_wr_file);
318 if(k != 1)goto wrerr;
319 k=fwrite(&i,sizeof(int),1,save_wr_file);
320 if(k != 1)goto wrerr;
321 k=fwrite(&data_bytes,sizeof(int),1,save_wr_file);
322 if(k != 1)goto wrerr;
323 // (Unorthodox. Slow but easy.) read byte by byte until end of file.
324 ich=(char*)&i;
325 k=fread(&ich[1],3,1,save_rd_file);
326 while(k == 1)
327   {
328   m=fwrite(&ich[1],3,1,save_wr_file);
329   if(m != 1)goto wrerr;
330   k=fread(&ich[1],3,1,save_rd_file);
331   }
332 return 0;
333 wrerr:;
334 printf("\nERROR: Failed to write output file.\n");
335 return 1;
336 }
337