1 module main; 2 3 import std.stdio, 4 std.getopt; 5 6 import dcad.types; 7 import opus.encoder; 8 9 struct CommandLineArgs { 10 int channels = 2; 11 int frameRate = 48000; 12 int frameSize = 960; 13 int bitrate = 128; 14 15 bool fec = true; 16 int packetLossPercent = 30; 17 18 bool raw = true; 19 20 string input = "pipe:0"; 21 string output = "pipe:1"; 22 23 bool flush = true; 24 } 25 26 void encode(CommandLineArgs args) { 27 assert(args.raw, "Non-raw mode is not supported currently"); 28 29 // Create the OPUS Encoder 30 Encoder enc = new Encoder(args.frameRate, args.channels); 31 32 // Set some base options 33 enc.setBandwidth(Bandwidth.FULLBAND); 34 enc.setBitrate(args.bitrate); 35 enc.setInbandFEC(args.fec); 36 enc.setPacketLossPercent(args.packetLossPercent); 37 38 File input; 39 if (args.input == "pipe:0") { 40 input = std.stdio.stdin; 41 } else { 42 input = File(args.input, "r"); 43 } 44 45 File output; 46 if (args.output == "pipe:1") { 47 output = std.stdio.stdout; 48 } else { 49 output = File(args.output, "w"); 50 } 51 52 short[] rawData; 53 rawData.length = (args.frameSize * args.channels); 54 55 short[] data; 56 57 while (true) { 58 data = input.rawRead(rawData); 59 60 if (data.length != rawData.length) { 61 break; 62 } 63 64 Frame(enc.encode(cast(immutable)data, args.frameSize)).write(output); 65 66 if (args.flush) { 67 output.flush(); 68 } 69 } 70 71 output.flush(); 72 output.close(); 73 } 74 75 void main(string[] rawargs) { 76 CommandLineArgs args; 77 78 auto opts = getopt( 79 rawargs, 80 "channels|ac", "Number of audio channels (1 = mono, 2 = stero)", &args.channels, 81 "rate|ar", "Audio sampling rate", &args.frameRate, 82 "size|as", "Audio frame size", &args.frameSize, 83 "bitrate|ab", "Audio bitrate", &args.bitrate, 84 "fec", "Enable FEC (forward error correction)", &args.fec, 85 "packet-loss-percent", "FEC packet loss percent", &args.packetLossPercent, 86 "raw", "Don't include DCA metadata/magic bytes (raw OPUS)", &args.raw, 87 "input", "Input file or pipe", &args.input, 88 "output", "Output file or pipe", &args.output, 89 "flush", "Flush output after each frame, assists in real time pipelines", &args.flush, 90 ); 91 92 if (opts.helpWanted) { 93 return defaultGetoptPrinter("DCAD - a DCA audio encoder", opts.options); 94 } 95 96 encode(args); 97 98 }