summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2023-03-16 21:07:10 +0100
committerCarl Hetherington <cth@carlh.net>2023-03-16 21:07:10 +0100
commit8c5aed0c60927ad3f22ef3b620a4c2e000316a65 (patch)
treebee8b41ba5b48cedf7b402367234f4f5eef9d01c /src
parentc1d296b163ddf88a5b387f98e7e77988a242a996 (diff)
Allow writing to sound assets with int32_t as well as float.
Diffstat (limited to 'src')
-rw-r--r--src/sound_asset_writer.cc65
-rw-r--r--src/sound_asset_writer.h80
2 files changed, 101 insertions, 44 deletions
diff --git a/src/sound_asset_writer.cc b/src/sound_asset_writer.cc
index f789eb3b..0300407c 100644
--- a/src/sound_asset_writer.cc
+++ b/src/sound_asset_writer.cc
@@ -202,54 +202,17 @@ LIBDCP_ENABLE_WARNINGS
void
SoundAssetWriter::write(float const * const * data, int data_channels, int frames)
{
- DCP_ASSERT (!_finalized);
- DCP_ASSERT (frames > 0);
-
- auto const asset_channels = _asset->channels();
- DCP_ASSERT (data_channels <= asset_channels);
-
- static float const clip = 1.0f - (1.0f / pow (2, 23));
-
- if (!_started) {
- start ();
- }
-
- for (int i = 0; i < frames; ++i) {
-
- byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
-
- /* Write one sample per asset channel */
- for (int j = 0; j < asset_channels; ++j) {
- int32_t s = 0;
- if (j == 13 && _sync) {
- s = _fsk.get();
- } else if (j < data_channels) {
- /* Convert sample to 24-bit int, clipping if necessary. */
- float x = data[j][i];
- if (x > clip) {
- x = clip;
- } else if (x < -clip) {
- x = -clip;
- }
- s = x * (1 << 23);
- }
- *out++ = (s & 0xff);
- *out++ = (s & 0xff00) >> 8;
- *out++ = (s & 0xff0000) >> 16;
- }
- _frame_buffer_offset += 3 * asset_channels;
+ do_write(data, data_channels, frames);
+}
- DCP_ASSERT (_frame_buffer_offset <= int(_state->frame_buffer.Capacity()));
- /* Finish the MXF frame if required */
- if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
- write_current_frame ();
- _frame_buffer_offset = 0;
- memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
- }
- }
+void
+SoundAssetWriter::write(int32_t const * const * data, int data_channels, int frames)
+{
+ do_write(data, data_channels, frames);
}
+
void
SoundAssetWriter::write_current_frame ()
{
@@ -367,3 +330,17 @@ SoundAssetWriter::create_sync_packets ()
return bs.get();
}
+
+byte_t*
+SoundAssetWriter::frame_buffer_data() const
+{
+ return _state->frame_buffer.Data();
+}
+
+
+int
+SoundAssetWriter::frame_buffer_capacity() const
+{
+ return _state->frame_buffer.Capacity();
+}
+
diff --git a/src/sound_asset_writer.h b/src/sound_asset_writer.h
index 6d8191c7..d8ebdc7b 100644
--- a/src/sound_asset_writer.h
+++ b/src/sound_asset_writer.h
@@ -38,8 +38,10 @@
#include "asset_writer.h"
+#include "dcp_assert.h"
#include "fsk.h"
#include "types.h"
+#include "sound_asset.h"
#include "sound_frame.h"
#include <memory>
#include <boost/filesystem.hpp>
@@ -52,6 +54,30 @@ struct sync_test1;
namespace dcp {
+namespace sound_asset_writer {
+
+template <typename T>
+int32_t convert(T) { return {}; }
+
+template <>
+inline int32_t convert(int32_t x)
+{
+ int constexpr clip = (1 << 23);
+ return std::max(-clip, std::min(clip, x));
+}
+
+template<>
+inline int32_t convert(float x)
+{
+ float constexpr clip = 1.0f - (1.0f / (1 << 23));
+ float constexpr scale = (1 << 23);
+ auto const clipped = std::max(-clip, std::min(clip, x));
+ return std::lround(clipped * scale);
+}
+
+}
+
+
class SoundAsset;
@@ -76,12 +102,66 @@ public:
*/
void write(float const * const * data, int channels, int frames);
+ /** @param data Pointer an array of int32_t pointers, one for each channel.
+ * The 24-bit audio sample should be in the lower 24 bits of the int32_t.
+ * @param channels Number of channels in data; if this is less than the channels in the asset
+ * the remaining asset channels will be padded with silence.
+ * @param frames Number of frames i.e. number of floats that are given for each channel.
+ */
+ void write(int32_t const * const * data, int channels, int frames);
+
bool finalize () override;
private:
friend class SoundAsset;
friend struct ::sync_test1;
+ byte_t* frame_buffer_data() const;
+ int frame_buffer_capacity() const;
+
+ template <class T>
+ void
+ do_write(T const * const * data, int data_channels, int frames)
+ {
+ DCP_ASSERT(!_finalized);
+ DCP_ASSERT(frames > 0);
+
+ auto const asset_channels = _asset->channels();
+ DCP_ASSERT(data_channels <= asset_channels);
+
+ if (!_started) {
+ start();
+ }
+
+ for (int i = 0; i < frames; ++i) {
+
+ auto out = frame_buffer_data() + _frame_buffer_offset;
+
+ /* Write one sample per asset channel */
+ for (int j = 0; j < asset_channels; ++j) {
+ int32_t s = 0;
+ if (j == 13 && _sync) {
+ s = _fsk.get();
+ } else if (j < data_channels) {
+ s = sound_asset_writer::convert(data[j][i]);
+ }
+ *out++ = (s & 0xff);
+ *out++ = (s & 0xff00) >> 8;
+ *out++ = (s & 0xff0000) >> 16;
+ }
+ _frame_buffer_offset += 3 * asset_channels;
+
+ DCP_ASSERT(_frame_buffer_offset <= frame_buffer_capacity());
+
+ /* Finish the MXF frame if required */
+ if (_frame_buffer_offset == frame_buffer_capacity()) {
+ write_current_frame();
+ _frame_buffer_offset = 0;
+ memset(frame_buffer_data(), 0, frame_buffer_capacity());
+ }
+ }
+ }
+
SoundAssetWriter(SoundAsset *, boost::filesystem::path, bool sync, bool include_mca_subdescriptors);
void start ();