rawconverter.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright (C) 2018-2020 Stefan Westerfeld
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "rawconverter.hh"
  18. #include <math.h>
  19. using std::vector;
  20. template<int BIT_DEPTH, RawFormat::Endian ENDIAN, RawFormat::Encoding ENCODING>
  21. class RawConverterImpl : public RawConverter
  22. {
  23. public:
  24. void to_raw (const std::vector<float>& samples, std::vector<unsigned char>& bytes);
  25. void from_raw (const std::vector<unsigned char>& bytes, std::vector<float>& samples);
  26. };
  27. template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
  28. static RawConverter *
  29. create_with_bits_endian (const RawFormat& raw_format, Error& error)
  30. {
  31. switch (raw_format.encoding())
  32. {
  33. case RawFormat::SIGNED: return new RawConverterImpl<BIT_DEPTH, ENDIAN, RawFormat::SIGNED>();
  34. case RawFormat::UNSIGNED: return new RawConverterImpl<BIT_DEPTH, ENDIAN, RawFormat::UNSIGNED>();
  35. }
  36. error = Error ("unsupported encoding");
  37. return nullptr;
  38. }
  39. template<int BIT_DEPTH>
  40. static RawConverter *
  41. create_with_bits (const RawFormat& raw_format, Error& error)
  42. {
  43. switch (raw_format.endian())
  44. {
  45. case RawFormat::LITTLE: return create_with_bits_endian <BIT_DEPTH, RawFormat::LITTLE> (raw_format, error);
  46. case RawFormat::BIG: return create_with_bits_endian <BIT_DEPTH, RawFormat::BIG> (raw_format, error);
  47. }
  48. error = Error ("unsupported endianness");
  49. return nullptr;
  50. }
  51. RawConverter *
  52. RawConverter::create (const RawFormat& raw_format, Error& error)
  53. {
  54. error = Error::Code::NONE;
  55. switch (raw_format.bit_depth())
  56. {
  57. case 16: return create_with_bits<16> (raw_format, error);
  58. case 24: return create_with_bits<24> (raw_format, error);
  59. default: error = Error ("unsupported bit depth");
  60. return nullptr;
  61. }
  62. }
  63. template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
  64. constexpr std::array<int, 3>
  65. make_endian_shift ()
  66. {
  67. if (BIT_DEPTH == 16)
  68. {
  69. if (ENDIAN == RawFormat::Endian::LITTLE)
  70. return { 16, 24, -1 };
  71. else
  72. return { 24, 16, -1 };
  73. }
  74. if (BIT_DEPTH == 24)
  75. {
  76. if (ENDIAN == RawFormat::Endian::LITTLE)
  77. return { 8, 16, 24 };
  78. else
  79. return { 24, 16, 8 };
  80. }
  81. }
  82. template<int BIT_DEPTH, RawFormat::Endian ENDIAN, RawFormat::Encoding ENCODING>
  83. void
  84. RawConverterImpl<BIT_DEPTH, ENDIAN, ENCODING>::to_raw (const vector<float>& samples, vector<unsigned char>& output_bytes)
  85. {
  86. constexpr int sample_width = BIT_DEPTH / 8;
  87. constexpr auto eshift = make_endian_shift<BIT_DEPTH, ENDIAN>();
  88. constexpr unsigned char sign_flip = ENCODING == RawFormat::SIGNED ? 0x00 : 0x80;
  89. output_bytes.resize (sample_width * samples.size());
  90. unsigned char *ptr = output_bytes.data();
  91. for (size_t i = 0; i < samples.size(); i++)
  92. {
  93. const double norm = 0x80000000LL;
  94. const double min_value = -0x80000000LL;
  95. const double max_value = 0x7FFFFFFF;
  96. const int sample = lrint (bound<double> (min_value, samples[i] * norm, max_value));
  97. if (eshift[0] >= 0)
  98. ptr[0] = (sample >> eshift[0]) ^ sign_flip;
  99. if (eshift[1] >= 0)
  100. ptr[1] = sample >> eshift[1];
  101. if (eshift[2] >= 0)
  102. ptr[2] = sample >> eshift[2];
  103. ptr += sample_width;
  104. }
  105. }
  106. template<int BIT_DEPTH, RawFormat::Endian ENDIAN, RawFormat::Encoding ENCODING>
  107. void
  108. RawConverterImpl<BIT_DEPTH, ENDIAN, ENCODING>::from_raw (const vector<unsigned char>& input_bytes, vector<float>& samples)
  109. {
  110. const unsigned char *ptr = input_bytes.data();
  111. constexpr int sample_width = BIT_DEPTH / 8;
  112. constexpr auto eshift = make_endian_shift<BIT_DEPTH, ENDIAN>();
  113. constexpr unsigned char sign_flip = ENCODING == RawFormat::SIGNED ? 0x00 : 0x80;
  114. samples.resize (input_bytes.size() / sample_width);
  115. const double norm = 1.0 / 0x80000000LL;
  116. for (size_t i = 0; i < samples.size(); i++)
  117. {
  118. int s32 = 0;
  119. if (eshift[0] >= 0)
  120. s32 += (ptr[0] ^ sign_flip) << eshift[0];
  121. if (eshift[1] >= 0)
  122. s32 += ptr[1] << eshift[1];
  123. if (eshift[2] >= 0)
  124. s32 += ptr[2] << eshift[2];
  125. samples[i] = s32 * norm;
  126. ptr += sample_width;
  127. }
  128. }