17 :
mFilename { filename.empty() ?
std::tmpnam(nullptr) : filename }
20 std::memset(&sfInfo, 0,
sizeof(sfInfo));
21 sfInfo.samplerate = 44100;
23 sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
27 assert(
mFile !=
nullptr);
32 static_cast<sf_count_t
>(
std::round(duration * sfInfo.samplerate));
33 const auto numItems = sfInfo.channels * sfInfo.frames;
34 std::unique_ptr<short[]> zeros {
new short[numItems] };
35 std::fill(zeros.get(), zeros.get() + numItems, 0);
36 const auto written = sf_write_short(
mFile, zeros.get(), numItems);
37 if (written != numItems)
38 throw std::runtime_error(
"Failed to write audio to file");
47LibsndfileTagger::operator bool()
const
49 return mFile !=
nullptr;
55 throw std::runtime_error(
"File is not open");
64 throw std::runtime_error(
"Failed to re-open file");
104 SF_LOOP_INFO loopInfo {};
105 loopInfo.bpm = acidTags.
bpm.value_or(0.);
106 loopInfo.loop_mode = acidTags.
isOneShot ? SF_LOOP_NONE : SF_LOOP_FORWARD;
109 std::memset(&chunk, 0,
sizeof(chunk));
110 std::snprintf(chunk.id,
sizeof(chunk.id),
"acid");
113 chunk.datalen = 4 + 2 + 2 + 4 + 4 + 2 + 2 + 4;
114 mAcidData = std::make_unique<uint8_t[]>(chunk.datalen);
115 std::memset(
mAcidData.get(), 0, chunk.datalen);
122 auto type =
reinterpret_cast<uint32_t*
>(
mAcidData.get());
125 else if (acidTags.
beats.has_value())
127 auto numBeats =
reinterpret_cast<uint32_t*
>(
mAcidData.get() + 12);
128 *numBeats = *acidTags.
beats;
132 assert(acidTags.
bpm.has_value());
133 auto tempo =
reinterpret_cast<float*
>(
mAcidData.get() + 20);
134 *tempo = *acidTags.
bpm;
138 auto numerator =
reinterpret_cast<uint16_t*
>(
mAcidData.get() + 16);
139 *numerator |= 0x0004;
140 auto denominator =
reinterpret_cast<uint16_t*
>(
mAcidData.get() + 18);
141 *denominator |= 0x0004;
143 const auto result = sf_set_chunk(
mFile, &chunk);
144 assert(result == SF_ERR_NO_ERROR);
149 const uint32_t distributorSize = distributor.size();
151 static_assert(
sizeof(distributorSize) == 4);
153 std::snprintf(chunk.id,
sizeof(chunk.id),
"LIST");
155 constexpr std::array<char, 4> listTypeID = {
'I',
'N',
'F',
'O' };
156 constexpr std::array<char, 4> distributorTypeID = {
'I',
'D',
'S',
'T' };
157 chunk.datalen =
sizeof(listTypeID) +
sizeof(distributorTypeID) +
158 sizeof(distributorSize) + distributorSize;
161 while (chunk.datalen & 3)
166 std::memset(chunk.data, 0, chunk.datalen);
169 std::memcpy(data + pos, listTypeID.data(),
sizeof(listTypeID));
171 pos +=
sizeof(listTypeID);
172 std::memcpy(data + pos, distributorTypeID.data(),
sizeof(distributorTypeID));
174 pos +=
sizeof(distributorTypeID);
175 std::memcpy(data + pos, &distributorSize,
sizeof(distributorSize));
177 pos +=
sizeof(distributorSize);
178 std::memcpy(data + pos, distributor.data(), distributorSize);
180 const auto result = sf_set_chunk(
mFile, &chunk);
181 assert(result == SF_ERR_NO_ERROR);
static wxCharBuffer mFilename
SNDFILE & ReopenInReadMode()
void AddAcidizerTags(const Test::AcidizerTags &acidTags)
std::unique_ptr< uint8_t[]> mDistributorData
void AddDistributorInfo(const std::string &distributor)
const std::string mFilename
std::unique_ptr< uint8_t[]> mAcidData
LibsndfileTagger(double duration=0., const std::string &filename="")
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept