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   while (true) {
56     const short[] data = input.rawRead(rawData);
57 
58     if (data.length != rawData.length) {
59       break;
60     }
61 
62     Frame(enc.encode(data, args.frameSize)).write(output);
63 
64     if (args.flush) {
65       output.flush();
66     }
67   }
68 
69   output.flush();
70   output.close();
71 }
72 
73 void main(string[] rawargs) {
74   CommandLineArgs args;
75 
76   auto opts = getopt(
77     rawargs,
78     "channels|ac", "Number of audio channels (1 = mono, 2 = stero)", &args.channels,
79     "rate|ar", "Audio sampling rate", &args.frameRate,
80     "size|as", "Audio frame size", &args.frameSize,
81     "bitrate|ab", "Audio bitrate", &args.bitrate,
82     "fec", "Enable FEC (forward error correction)", &args.fec,
83     "packet-loss-percent", "FEC packet loss percent", &args.packetLossPercent,
84     "raw", "Don't include DCA metadata/magic bytes (raw OPUS)", &args.raw,
85     "input", "Input file or pipe", &args.input,
86     "output", "Output file or pipe", &args.output,
87     "flush", "Flush output after each frame, assists in real time pipelines", &args.flush,
88   );
89 
90   if (opts.helpWanted) {
91     return defaultGetoptPrinter("DCAD - a DCA audio encoder", opts.options);
92   }
93 
94   encode(args);
95 
96 }