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 }