#include #include #include #include #include #include #include #include "Arguments.h" #include "SampleStream.h" #include "SampleBlock.h" #include "FilterWorker.h" using std::vector; using std::counting_semaphore; using std::thread; using std::ref; #define SAMPLE_BLOCK_SIZE 1024 int main(int argc, char** argv) { // parse arguments Arguments args(argc, argv); // read input file to std::string std::fstream file_input(args.file_input, std::ios::in | std::ios::binary); std::stringstream file_input_content; file_input_content << file_input.rdbuf(); file_input.close(); // convert std::string to vector SampleStream input(file_input_content.str()); // split into 1024-sample blocks vector input_blocks = input.split(SAMPLE_BLOCK_SIZE); // do the same for output stream (input stream is later used as reference but not mutated) SampleStream output(file_input_content.str()); vector output_blocks = output.split(SAMPLE_BLOCK_SIZE); // c++20 semaphore for limiting active thread count counting_semaphore semaphore(args.max_threads); // thread array vector threads; for (size_t i = 0; i < input_blocks.size(); i++) { semaphore.acquire(); // wait until less than args.max_threads threads are running // create thread threads.push_back(thread([&args, &semaphore](SampleBlock& input, SampleBlock& output) { // apply filter to output FilterWorker(input, output).filter(args.bass, args.treble); // allow new thread to be created semaphore.release(); }, ref(input_blocks[i]), ref(output_blocks[i]))); } // make sure all threads are done for (thread& t : threads) t.join(); // write pcm stream to output file std::fstream file_output(args.file_output, std::ios::out | std::ios::binary); std::string edited_stream = output.save(); file_output.write(edited_stream.c_str(), edited_stream.size()); file_output.close(); return 0; }