@@ -28,64 +28,88 @@ int main(int argc, char** argv)
2828
2929 // Initialize WAV reader and get file sample rate
3030 audio_reader_wav<double > reader (open_file_for_reading (argv[1 ]));
31+ const size_t channels = reader.format ().channels ;
3132 const size_t input_sr = static_cast <size_t >(reader.format ().samplerate );
3233
33- // Read channels of audio
34- univector2d<double > input_channels = reader.read_channels (reader.format ().length );
35-
36- // Prepare conversion
37- univector2d<double > output_channels;
38- println (" Input channels: " , reader.format ().channels );
34+ println (" Input channels: " , channels);
3935 println (" Input sample rate: " , reader.format ().samplerate );
4036 println (" Input bit depth: " , audio_sample_bit_depth (reader.format ().type ));
4137
42- for (size_t ch = 0 ; ch < input_channels.size (); ++ch)
43- {
44- println (" Processing " , ch, " of " , reader.format ().channels );
45- const univector<double >& input = input_channels[ch];
38+ // Initialize WAV writer
39+ audio_writer_wav<double > writer (open_file_for_writing (argv[2 ]),
40+ audio_format{ channels, reader.format ().type , kfr::fmax (output_sr) });
4641
47- // Initialize resampler
48- auto r = resampler<double >(resample_quality::high, output_sr, input_sr);
42+ std::vector<samplerate_converter<double >> resamplers (channels);
43+ for (size_t ch = 0 ; ch < channels; ++ch)
44+ {
45+ resamplers[ch] = resampler<double >(resample_quality::high, output_sr, input_sr);
46+ }
47+ auto & resampler0 = resamplers.front ();
48+
49+ constexpr size_t output_chunk_size = 16384 ;
50+ univector2d<double > output_chunk (channels, univector<double >(output_chunk_size));
51+ univector<double > output_chunk_interleaved (output_chunk_size * channels);
52+
53+ const size_t input_delay_compensation = resampler0.input_size_for_output (resampler0.get_delay ());
54+ const size_t input_chunk_size = output_chunk_size * input_sr / output_sr + 1 + input_delay_compensation;
55+ univector<double > input_chunk_interleaved (input_chunk_size * channels);
56+ univector2d<double > input_chunk (channels, univector<double >(input_chunk_size));
57+
58+ bool first_chunk = true ;
59+ bool last_chunk = false ;
60+ std::chrono::high_resolution_clock::duration resampling_time{};
61+ // Process audio in chunks
62+ println (" Resampling..." );
63+ fflush (stdout);
64+ for (;;)
65+ {
66+ const size_t frames_to_read =
67+ resampler0.input_size_for_output (output_chunk_size + (first_chunk ? resampler0.get_delay () : 0 ));
4968
50- // Calculate output size and initialize output buffer
51- const size_t output_size = input.size () * output_sr / input_sr;
52- univector<double > output (output_size);
69+ // Read channels of audio
70+ const size_t samples_read = reader.read (input_chunk_interleaved.truncate (frames_to_read * channels));
71+ const size_t frames_read = samples_read / channels;
72+ deinterleave (input_chunk, input_chunk_interleaved.truncate (samples_read));
5373
54- // Skip the first r.get_delay() samples (FIR filter delay). Returns new input pos
55- size_t input_pos = r.skip (r.get_delay (), input.slice ());
74+ size_t frames_to_write = output_chunk_size;
75+ if (frames_read < frames_to_read)
76+ {
77+ last_chunk = true ;
78+ frames_to_write = resampler0.output_size_for_input (frames_read) + resampler0.get_delay ();
79+ }
80+ if (frames_to_write <= resampler0.get_delay ())
81+ {
82+ println (" Error: input file is too short for resampling" );
83+ return 2 ;
84+ }
5685
57- std::chrono::high_resolution_clock::time_point start_time = std::chrono::high_resolution_clock::now ();
58- size_t output_pos = 0 ;
59- for (;;)
86+ const std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now ();
87+ for (size_t ch = 0 ; ch < channels; ++ch)
6088 {
61- const size_t block_size = std::min (size_t (16384 ), output.size () - output_pos);
62- if (block_size == 0 )
63- break ;
89+ auto & r = resamplers[ch];
90+ auto && output = output_chunk[ch].truncate (frames_to_write).ref ();
91+ auto && input = input_chunk[ch].truncate (frames_read);
92+ if (first_chunk)
93+ {
94+ // Skip the first r.get_delay() samples (FIR filter delay).
95+ r.skip (r.get_delay (), input);
96+ }
6497
6598 // Process new block of audio
66- input_pos += r.process (output.slice (output_pos, block_size).ref (), input.slice (input_pos));
67- output_pos += block_size;
99+ r.process (output, input);
68100 }
69-
70- std::chrono::high_resolution_clock::duration time =
71- std::chrono::high_resolution_clock::now () - start_time;
72- const double duration = static_cast <double >(output.size ()) / output_sr;
73- println (" time: " ,
74- fmt<' f' , 6 , 2 >(std::chrono::duration_cast<std::chrono::microseconds>(time).count () /
75- duration * 0.001 ),
76- " ms per 1 second of audio" );
77-
78- // Place buffer to the list of output channels
79- output_channels.push_back (std::move (output));
101+ resampling_time += std::chrono::high_resolution_clock::now () - t1;
102+ interleave (output_chunk_interleaved.truncate (frames_to_write * channels).ref (), output_chunk);
103+
104+ // Write audio
105+ writer.write (output_chunk_interleaved.truncate (frames_to_write * channels));
106+ first_chunk = false ;
107+ if (last_chunk)
108+ break ;
80109 }
81-
82- // Initialize WAV writer
83- audio_writer_wav<double > writer (
84- open_file_for_writing (argv[2 ]),
85- audio_format{ reader.format ().channels , reader.format ().type , kfr::fmax (output_sr) });
86-
87- // Write audio
88- writer.write_channels (output_channels);
110+ double duration = std::chrono::duration_cast<std::chrono::nanoseconds>(resampling_time).count () / 1e9 ;
111+ double length = reader.format ().length / reader.format ().samplerate ;
112+ println (" done in " , duration, " seconds" , " (" , fmt<' f' , 4 , 1 >(length / duration), " x real-time)" );
89113
90114 return 0 ;
91115}
0 commit comments