aboutsummaryrefslogtreecommitdiffstats
path: root/src/dsd2pcm/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dsd2pcm/main.cpp')
-rw-r--r--src/dsd2pcm/main.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/dsd2pcm/main.cpp b/src/dsd2pcm/main.cpp
new file mode 100644
index 000000000..0b58888a8
--- /dev/null
+++ b/src/dsd2pcm/main.cpp
@@ -0,0 +1,120 @@
+#include <iostream>
+#include <vector>
+#include <cstring>
+
+#include "dsd2pcm.hpp"
+#include "noiseshape.hpp"
+
+namespace {
+
+const float my_ns_coeffs[] = {
+// b1 b2 a1 a2
+ -1.62666423, 0.79410094, 0.61367127, 0.23311013, // section 1
+ -1.44870017, 0.54196219, 0.03373857, 0.70316556 // section 2
+};
+
+const int my_ns_soscount = sizeof(my_ns_coeffs)/(sizeof(my_ns_coeffs[0])*4);
+
+inline long myround(float x)
+{
+ return static_cast<long>(x + (x>=0 ? 0.5f : -0.5f));
+}
+
+template<typename T>
+struct id { typedef T type; };
+
+template<typename T>
+inline T clip(
+ typename id<T>::type min,
+ T v,
+ typename id<T>::type max)
+{
+ if (v<min) return min;
+ if (v>max) return max;
+ return v;
+}
+
+inline void write_intel16(unsigned char * ptr, unsigned word)
+{
+ ptr[0] = word & 0xFF;
+ ptr[1] = (word >> 8) & 0xFF;
+}
+
+inline void write_intel24(unsigned char * ptr, unsigned long word)
+{
+ ptr[0] = word & 0xFF;
+ ptr[1] = (word >> 8) & 0xFF;
+ ptr[2] = (word >> 16) & 0xFF;
+}
+
+} // anonymous namespace
+
+using std::vector;
+using std::cin;
+using std::cout;
+using std::cerr;
+
+int main(int argc, char *argv[])
+{
+ const int block = 16384;
+ int channels = -1;
+ int lsbitfirst = -1;
+ int bits = -1;
+ if (argc==4) {
+ if ('1'<=argv[1][0] && argv[1][0]<='9') channels = 1 + (argv[1][0]-'1');
+ if (argv[2][0]=='m' || argv[2][0]=='M') lsbitfirst=0;
+ if (argv[2][0]=='l' || argv[2][0]=='L') lsbitfirst=1;
+ if (!strcmp(argv[3],"16")) bits = 16;
+ if (!strcmp(argv[3],"24")) bits = 24;
+ }
+ if (channels<1 || lsbitfirst<0 || bits<0) {
+ cerr << "\n"
+ "DSD2PCM filter (raw DSD64 --> 352 kHz raw PCM)\n"
+ "(c) 2009 Sebastian Gesemann\n\n"
+ "(filter as in \"reads data from stdin and writes to stdout\")\n\n"
+ "Syntax: dsd2pcm <channels> <bitorder> <bitdepth>\n"
+ "channels = 1,2,3,...,9 (number of channels in DSD stream)\n"
+ "bitorder = L (lsb first), M (msb first) (DSD stream option)\n"
+ "bitdepth = 16 or 24 (intel byte order, output option)\n\n"
+ "Note: At 16 bits/sample a noise shaper kicks in that can preserve\n"
+ "a dynamic range of 135 dB below 30 kHz.\n\n";
+ return 1;
+ }
+ int bytespersample = bits/8;
+ vector<dxd> dxds (channels);
+ vector<noise_shaper> ns;
+ if (bits==16) {
+ ns.resize(channels, noise_shaper(my_ns_soscount, my_ns_coeffs) );
+ }
+ vector<unsigned char> dsd_data (block * channels);
+ vector<float> float_data (block);
+ vector<unsigned char> pcm_data (block * channels * bytespersample);
+ char * const dsd_in = reinterpret_cast<char*>(&dsd_data[0]);
+ char * const pcm_out = reinterpret_cast<char*>(&pcm_data[0]);
+ while (cin.read(dsd_in,block * channels)) {
+ for (int c=0; c<channels; ++c) {
+ dxds[c].translate(block,&dsd_data[0]+c,channels,
+ lsbitfirst,
+ &float_data[0],1);
+ unsigned char * out = &pcm_data[0] + c*bytespersample;
+ if (bits==16) {
+ for (int s=0; s<block; ++s) {
+ float r = float_data[s]*32768 + ns[c].get();
+ long smp = clip(-32768,myround(r),32767);
+ ns[c].update( clip(-1,smp-r,1) );
+ write_intel16(out,smp);
+ out += channels*bytespersample;
+ }
+ } else {
+ for (int s=0; s<block; ++s) {
+ float r = float_data[s]*8388608;
+ long smp = clip(-8388608,myround(r),8388607);
+ write_intel24(out,smp);
+ out += channels*bytespersample;
+ }
+ }
+ }
+ cout.write(pcm_out,block*channels*bytespersample);
+ }
+}
+