forked from jks-prv/kiwiclient
-
Notifications
You must be signed in to change notification settings - Fork 3
/
read_kiwi_iq_wav.cc
180 lines (162 loc) · 4.6 KB
/
read_kiwi_iq_wav.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// -*- C++ -*-
#include <fstream>
#include <octave/oct.h>
#include <octave/oct-map.h>
#if defined(__GNUC__) && not defined(__MINGW32__)
# define _PACKED __attribute__((__packed__))
#else
# define _PACKED
# define _USE_PRAGMA_PACK
#endif
#ifdef _USE_PRAGMA_PACK
# pragma pack(push, 1)
#endif
class chunk_base {
public:
chunk_base()
: _id()
, _size() {
static_assert(sizeof(chunk_base) == 8, "chunk_base has wrong packed size");
}
std::string id() const { return std::string((char*)(_id), 4); }
std::streampos size() const { return _size; }
private:
int8_t _id[4];
uint32_t _size;
} _PACKED;
class chunk_riff : public chunk_base {
public:
chunk_riff()
: _format() {
static_assert(sizeof(chunk_riff) == 8+4, "chunk_riff has wrong packed size");
}
std::string format() const { return std::string((char*)(_format), 4); }
private:
int8_t _format[4];
} _PACKED;
class chunk_fmt : public chunk_base {
public:
chunk_fmt()
: _format()
, _num_channels()
, _sample_rate()
, _byte_rate()
, _block_align()
, _dummy() {
static_assert(sizeof(chunk_fmt) == 8+16, "chunk_fmt has wrong packed size");
}
uint16_t format() const { return _format; }
uint16_t num_channels() const { return _num_channels; }
uint32_t sample_rate() const { return _sample_rate; }
uint32_t byte_rate() const { return _byte_rate; }
uint16_t block_align() const { return _block_align; }
protected:
uint16_t _format;
uint16_t _num_channels;
uint32_t _sample_rate;
uint32_t _byte_rate;
uint16_t _block_align;
uint16_t _dummy;
} _PACKED;
class chunk_kiwi : public chunk_base {
public:
chunk_kiwi()
: _last()
, _dummy()
, _gpssec()
, _gpsnsec() {
static_assert(sizeof(chunk_kiwi) == 8+10, "chunk_kiwi has wrong packed size");
}
uint8_t last() const { return _last; }
uint32_t gpssec() const { return _gpssec; }
uint32_t gpsnsec() const { return _gpsnsec; }
private:
uint8_t _last, _dummy;
uint32_t _gpssec, _gpsnsec;
} _PACKED;
#ifdef _USE_PRAGMA_PACK
# pragma pack(pop)
# undef _USE_PRAGMA_PACK
#endif
#undef _PACKED
DEFUN_DLD (read_kiwi_iq_wav, args, nargout, "[d,sample_rate]=read_kiwi_wav(\"<wav file name\");")
{
octave_value_list retval;
const std::string filename = args(0).string_value();
if (error_state)
return retval;
std::ifstream file(filename.c_str(), std::ios::binary);
if (!file)
error("file '%s' does not exist", filename.c_str());
octave_value_list cell_z, cell_last, cell_gpssec, cell_gpsnsec;
chunk_base c;
chunk_fmt fmt;
int data_counter=0;
while (file) {
const std::streampos pos = file.tellg();
file.read((char*)(&c), sizeof(c));
if (!file) {
// end of file
break;
}
if (c.id() == "RIFF") {
chunk_riff cr;
file.seekg(pos);
file.read((char*)(&cr), sizeof(cr));
if (!file || cr.format() != "WAVE") {
error("'WAVE' chunk expected");
break;
}
const int n = (int(cr.size())-sizeof(chunk_riff)-4)/2074;
cell_z.resize(n);
cell_last.resize(n);
cell_gpssec.resize(n);
cell_gpsnsec.resize(n);
} else if (c.id() == "fmt ") {
file.seekg(pos);
file.read((char*)(&fmt), sizeof(fmt));
if (!file ||
fmt.format() != 1 ||
fmt.num_channels() != 2) {
error("unsupported WAVE format");
break;
}
retval(1) = fmt.sample_rate();
} else if (c.id() == "data") {
const int n = c.size()/4;
FloatComplexNDArray a(dim_vector(n, 1));
int16_t i=0, j=0, q=0;
for (; j<n && file; ++j) {
file.read((char*)(&i), sizeof(i));
file.read((char*)(&q), sizeof(q));
a(j) = std::complex<float>(i/32768.0f, q/32768.0f);
}
if (j != n)
error("incomplete 'data' chunk");
cell_z(data_counter++) = a;
} else if (c.id() == "kiwi") {
file.seekg(pos);
chunk_kiwi kiwi;
file.read((char*)(&kiwi), sizeof(kiwi));
if (!file)
error("incomplete 'kiwi' chunk");
cell_last(data_counter) = kiwi.last();
cell_gpssec(data_counter) = kiwi.gpssec();
cell_gpsnsec(data_counter) = kiwi.gpsnsec();
} else {
octave_stdout << "skipping unknown chunk '" << c.id() << "'" << std::endl;
file.seekg(file.tellg() + c.size());
}
}
octave_map map;
map.setfield("z", cell_z);
if (cell_last.length() == cell_z.length()) {
map.setfield("gpslast", cell_last);
map.setfield("gpssec", cell_gpssec);
map.setfield("gpsnsec", cell_gpsnsec);
} else {
error("number of GNSS timestamps does not match number of IQ samples");
}
retval(0) = map;
return retval;
}