diff options
Diffstat (limited to 'src/dsd2pcm/main.cpp')
-rw-r--r-- | src/dsd2pcm/main.cpp | 120 |
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); + } +} + |