1 #include "newpacket.hpp"
2 #include "timecounter.hpp"
10 #define BMODE_DEFAULT -1
12 #define BMODE_16BIT_LE 1
13 #define BMODE_16BIT_BE 2
15 #define CMODE_DEFAULT -1
17 #define CMODE_STEREO 1
18 #define CMODE_STEREO_SWAPPED 2
20 #define SMODE_DEFAULT -1
21 #define SMODE_SIGNED 0
22 #define SMODE_UNSIGNED 1
24 int bit_mode
= BMODE_DEFAULT
;
25 int channel_mode
= CMODE_DEFAULT
;
26 int signed_mode
= SMODE_DEFAULT
;
27 bool rate_given
= false;
28 timecounter
curtime(44100);
36 if(x
== BMODE_DEFAULT
)
37 return BMODE_16BIT_LE
;
43 if(x
== CMODE_DEFAULT
)
50 if(x
== SMODE_DEFAULT
)
57 if(x
== BMODE_DEFAULT
)
60 throw std::runtime_error("Multiple bit width specifications present");
65 if(x
== CMODE_DEFAULT
)
68 throw std::runtime_error("Multiple channel specifications present");
73 if(x
== SMODE_DEFAULT
)
76 throw std::runtime_error("Multiple signedness specifications present");
79 void set_rate(const std::string
& s
)
82 curtime
= timecounter(s
);
85 throw std::runtime_error("Multiple rate specifications present");
88 void set_chan_volume(const std::string
& spec
, uint32_t& n
, uint32_t& d
)
95 throw std::runtime_error("Empty volume spec is not legal");
97 for(size_t i
= 0; i
< spec
.length(); i
++) {
98 if(readfpu
> 1844674407370955160ULL)
99 throw std::runtime_error("Overflow reading number");
101 if(spec
[i
] >= '0' && spec
[i
] <= '9')
102 readfpu
= 10 * readfpu
+ (spec
[i
] - '0');
103 else if(spec
[i
] == '.')
106 std::stringstream str
;
107 str
<< "Expected number or '.', got '" << spec
[i
] << "'";
108 throw std::runtime_error(str
.str());
111 if(spec
[i
] >= '0' && spec
[i
] <= '9') {
112 if(base
== 10000000000000000000ULL) {
113 std::stringstream str
;
114 str
<< "volume number has more than 19 decimal digits";
115 throw std::runtime_error(str
.str());
118 readfpu
= 10 * readfpu
+ (spec
[i
] - '0');
120 std::stringstream str
;
121 str
<< "Expected number, got '" << spec
[i
] << "'";
122 throw std::runtime_error(str
.str());
126 while(base
> 0xFFFFFFFFULL
|| readfpu
> 0xFFFFFFFFULL
) {
131 n
= (uint32_t)readfpu
;
135 void set_volume(const std::string
& s
)
137 uint32_t ln
, ld
, rn
, rd
;
138 std::string s2
, sl
, sr
;
141 throw std::runtime_error("Initial volume already given");
144 size_t split
= s2
.find_first_of(",");
145 if(split
> s2
.length()) {
149 sl
= s2
.substr(0, split
);
150 sr
= s2
.substr(split
+ 1);
153 set_chan_volume(sl
, ln
, ld
);
154 set_chan_volume(sr
, rn
, rd
);
161 void process_argument(const char* s
, std::string
& input
, std::string
& channel
, std::string
& output
)
164 if(!strcmp(s
, "--8bit"))
165 set_bmode(BMODE_8BIT
);
166 else if(!strcmp(s
, "--16bit"))
167 set_bmode(BMODE_16BIT_LE
);
168 else if(!strcmp(s
, "--16bit-little-endian"))
169 set_bmode(BMODE_16BIT_LE
);
170 else if(!strcmp(s
, "--16bit-big-endian"))
171 set_bmode(BMODE_16BIT_BE
);
172 else if(!strcmp(s
, "--mono"))
173 set_bmode(CMODE_MONO
);
174 else if(!strcmp(s
, "--stereo"))
175 set_bmode(CMODE_STEREO
);
176 else if(!strcmp(s
, "--stereo-swapped"))
177 set_bmode(CMODE_STEREO_SWAPPED
);
178 else if(!strcmp(s
, "--signed"))
179 set_bmode(SMODE_SIGNED
);
180 else if(!strcmp(s
, "--unsigned"))
181 set_bmode(SMODE_UNSIGNED
);
182 else if(!strncmp(s
, "--rate=", 7))
184 else if(!strncmp(s
, "--volume=", 9))
186 else if(!strncmp(s
, "--", 2))
187 throw std::runtime_error("Unknown option");
191 else if(channel
== "")
193 else if(output
== "")
196 throw std::runtime_error("Only three non-options may be present");
198 } catch(std::exception
& e
) {
199 std::cerr
<< "Error processing argument '" << s
<< "': " << e
.what() << std::endl
;
206 bool readsample(FILE* filp
, short& left
, short& right
)
208 int _bmode
= bmode(bit_mode
);
209 int _cmode
= cmode(channel_mode
);
210 int _smode
= smode(signed_mode
);
211 unsigned char sample
[MAXSAMPLE
];
221 throw std::runtime_error("Internal error: Unknown bit mode!");
227 case CMODE_STEREO_SWAPPED
:
230 throw std::runtime_error("Internal error: Unknown channel mode!");
233 int r
= fread(sample
, 1, bytes
, filp
);
234 if(r
> 0 && r
< bytes
)
235 throw std::runtime_error("Error reading input file");
239 //Now, we have sample to decode. First get it to 16-bit little-endian layout.
240 //First, swap channels in swapped stereo.
241 if(_cmode
== CMODE_STEREO_SWAPPED
)
242 for(int i
= 0; i
< bytes
/ 2; i
++)
243 std::swap(sample
[i
], sample
[bytes
/ 2 + i
]);
244 //If mono, copy the samples for stereo.
245 if(_cmode
== CMODE_MONO
)
246 for(int i
= 0; i
< bytes
; i
++)
247 sample
[bytes
+ i
] = sample
[i
];
248 //Expand 8-bit samples.
249 if(_bmode
== BMODE_8BIT
) {
250 sample
[3] = sample
[1];
252 sample
[1] = sample
[0];
255 //Byteswap 16-bit BE samples.
256 if(_bmode
== BMODE_16BIT_BE
) {
257 std::swap(sample
[0], sample
[1]);
258 std::swap(sample
[2], sample
[3]);
261 if(_smode
== SMODE_UNSIGNED
) {
262 left
= (short)(((int)sample
[1] << 8) + (int)sample
[0] - 32768);
263 right
= (short)(((int)sample
[1] << 8) + (int)sample
[0] - 32768);
265 left
= (short)(((int)sample
[1] << 8) + (int)sample
[0]);
266 right
= (short)(((int)sample
[1] << 8) + (int)sample
[0]);
273 void encode32(unsigned char* buf
, uint32_t value
)
275 buf
[0] = (value
>> 24) & 0xFF;
276 buf
[1] = (value
>> 16) & 0xFF;
277 buf
[2] = (value
>> 8) & 0xFF;
278 buf
[3] = (value
) & 0xFF;
282 void write_volume_change(write_channel
& wchan
)
288 p
.rp_minor
= 0; //Set volume.
289 p
.rp_payload
.resize(16);
290 encode32(&p
.rp_payload
[0], lvoln
);
291 encode32(&p
.rp_payload
[4], lvold
);
292 encode32(&p
.rp_payload
[8], rvoln
);
293 encode32(&p
.rp_payload
[12], rvold
);
294 p
.rp_timestamp
= curtime
;
298 void copy_loop(FILE* filp
, write_channel
& wchan
)
303 p
.rp_minor
= 1; //PCM sample.
304 p
.rp_payload
.resize(4);
305 while(readsample(filp
, left
, right
)) {
306 p
.rp_timestamp
= curtime
;
307 p
.rp_payload
[0] = (unsigned char)((unsigned char)left
>> 8);
308 p
.rp_payload
[1] = (unsigned char)((unsigned char)left
& 0xFF);
309 p
.rp_payload
[2] = (unsigned char)((unsigned char)right
>> 8);
310 p
.rp_payload
[3] = (unsigned char)((unsigned char)right
& 0xFF);
314 //Write the end-of-clip sample.
316 p
.rp_timestamp
= curtime
;
320 int real_main(int argc
, char** argv
)
322 std::string input
, channel
, output
;
324 for(int i
= 1; i
< argc
; i
++)
325 process_argument(argv
[i
], input
, channel
, output
);
328 std::cerr
<< "Syntax: audiotodump.exe <options> <input> <channel> <output>" << std::endl
;
329 std::cerr
<< "--8bit: 8-bit samples." << std::endl
;
330 std::cerr
<< "--16bit: 16-bit little-endian samples." << std::endl
;
331 std::cerr
<< "--16bit-little-endian: 16-bit little-endian samples (default)." << std::endl
;
332 std::cerr
<< "--16bit-big-endian: 16-bit big-endian samples." << std::endl
;
333 std::cerr
<< "--mono: Mono sound." << std::endl
;
334 std::cerr
<< "--stereo: Stereo sound (default)." << std::endl
;
335 std::cerr
<< "--stereo-swapped: Stereo sound with swapped channels." << std::endl
;
336 std::cerr
<< "--signed: Signed samples (default)." << std::endl
;
337 std::cerr
<< "--unsigned: Unsigned samples." << std::endl
;
338 std::cerr
<< "--rate=<rate>: Use specified sampling rate (default 44100)." << std::endl
;
339 std::cerr
<< "--volume=<vol>: Write initial volume." << std::endl
;
340 std::cerr
<< "--volume=<lvol>,<rvol>: Write initial volume (unbalanced)." << std::endl
;
345 in
= fopen(input
.c_str(), "rb");
347 std::cerr
<< "Error opening input file '" << input
<< "'." << std::endl
;
351 std::vector
<struct channel
> channels
;
353 channels
[0].c_channel
= 0; //Channel #0.
354 channels
[0].c_type
= 1; //audio channel.
355 channels
[0].c_channel_name
= channel
; //Channel name.
356 channels
[1].c_channel
= 1; //Channel #1.
357 channels
[1].c_type
= 3; //dummy channel.
358 channels
[1].c_channel_name
= "<DUMMY>"; //Channel name.
360 write_channel
wchan(output
);
361 wchan
.start_segment(channels
);
363 write_volume_change(wchan
);
364 copy_loop(in
, wchan
);
365 } catch(std::exception
& e
) {
366 std::cerr
<< "Error converting audio: " << e
.what() << std::endl
;