converter.cpp (4385B)
1 #include "decoder.hpp" 2 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 7 using namespace std::string_literals; 8 9 static constexpr std::size_t INPUTS = 2; 10 11 static void FindCh( 12 std::string_view sv, const std::vector<Channel::E>& channels, 13 std::vector<int>& reorder, unsigned cur) 14 { 15 for (std::size_t i = 0; i < channels.size(); ++i) 16 if (auto x = Channel::NAMES_PIPEWIRE[channels[i]]; 17 strlen(x) == sv.size() && !strncasecmp(x, sv.data(), sv.size())) 18 if (reorder[i] == -1) 19 { 20 reorder[i] = cur; 21 return; 22 } 23 else 24 throw std::runtime_error{"Duplicate channel " + std::string{sv}}; 25 throw std::runtime_error{"Invalid channel " + std::string{sv}}; 26 } 27 28 int Main(int argc, char** argv) 29 { 30 float rate = 1/48000.f; 31 std::string_view channel_map; 32 Decoder dec; 33 { 34 Option opts[] = { 35 { "help", "", "Show help" }, 36 { 37 "sample_rate", "FLOAT", "Sets sample rate of input (default: 48000 Hz)", 38 [&](std::string_view sv) 39 { rate = 1 / FromString<float>(sv); }, 40 }, 41 { 42 "channel_map", "CHANNEL_MAP", 43 "Set comma separated list of output channel order (help to get list of available channels)", 44 [&](std::string_view sv) { channel_map = sv; }, 45 }, 46 }; 47 48 opts[0].apply = [&](std::string_view) 49 { 50 std::cerr << "Usage " << argv[0] << " [--options] < input > output\n"; 51 PrintHelp(opts); 52 dec.PrintHelp(); 53 throw Exit{0}; 54 }; 55 56 auto dopt = dec.GetOptions(); 57 ParseArgs(argc, argv, [&](std::string_view k, std::string_view v) 58 { 59 if (HandleOption(opts, k, v)) return; 60 auto dopt = dec.GetOptions(); 61 if (HandleOption(dopt, k, v)) return; 62 throw ParseError("Unknown option "s + std::string{k}); 63 }); 64 } 65 dec.Init(rate); 66 67 std::vector<int> channel_reorder; 68 if (channel_map == "help") 69 { 70 for (const auto m : dec.GetChannels()) 71 std::cerr << Channel::NAMES_PIPEWIRE[m] << '\n'; 72 return 0; 73 } 74 else if (!channel_map.empty()) 75 { 76 auto chs = dec.GetChannels(); 77 channel_reorder.resize(chs.size(), -1); 78 std::size_t begin = 0; 79 unsigned i = 0; 80 while (true) 81 { 82 auto end = channel_map.find_first_of(',', begin); 83 auto it = channel_map.substr(begin, end-begin); 84 FindCh(it, chs, channel_reorder, i++); 85 if (end == std::string_view::npos) break; 86 begin = end + 1; 87 } 88 89 if (i != chs.size()) 90 throw std::runtime_error{"Not enough channels in reorder"}; 91 } 92 93 auto block_size = dec.GetBlockSize(); 94 auto read_size = INPUTS * (block_size ? block_size : 8192); 95 auto outputs = dec.GetChannels().size(); 96 auto skip = outputs * dec.GetDelay(); 97 std::vector<float> in_buf(read_size); 98 99 auto do_skip = [&](std::span<const float>& data) 100 { 101 auto cskip = std::min<std::size_t>(skip, data.size()); 102 data = data.subspan(cskip); 103 skip -= cskip; 104 }; 105 106 std::uint64_t total_read = 0, total_write = 0; 107 std::vector<float> reorder_buf; 108 auto wr = [&](std::span<const float> data) 109 { 110 if (const auto n = channel_reorder.size()) 111 { 112 reorder_buf.resize(data.size()); 113 for (std::size_t i = 0; i < data.size(); i += n) 114 { 115 std::array<float, Channel::N_CHANNELS> buf; 116 std::memcpy(buf.data(), data.data() + i, sizeof(float) * n); 117 for (std::size_t j = 0; j < n; ++j) 118 reorder_buf[i + std::size_t(channel_reorder[j])] = buf[j]; 119 } 120 data = reorder_buf; 121 } 122 123 if (fwrite(data.data(), sizeof(float), data.size(), stdout) != data.size()) 124 throw std::runtime_error("Write error"); 125 total_write += data.size(); 126 }; 127 128 std::size_t n_read; 129 while (true) 130 { 131 n_read = fread(in_buf.data(), sizeof(float), read_size, stdin); 132 total_read += n_read; 133 if (n_read != read_size) break; 134 135 auto res = dec.Decode(std::span{in_buf}); 136 do_skip(res); 137 wr(res); 138 } 139 140 // partial read, finish up 141 auto os_read = (total_read / INPUTS) * outputs; 142 auto do_chunk = [&]() 143 { 144 auto res = dec.Decode(std::span{in_buf}); 145 do_skip(res); 146 wr(res.subspan(0, std::min(os_read - total_write, res.size()))); 147 }; 148 149 std::memset(in_buf.data() + n_read, 0, sizeof(float) * (read_size - n_read)); 150 do_chunk(); 151 if (os_read == total_write) return 0; 152 153 std::memset(in_buf.data(), 0, sizeof(float) * in_buf.size()); 154 while (os_read > total_write) do_chunk(); 155 156 return 0; 157 }