+
+/** Write some audio frames to the DCP.
+ * @param audio Audio data.
+ * @param time Time of this data within the DCP.
+ * This method is not thread safe.
+ */
+void
+Writer::write (shared_ptr<const AudioBuffers> audio, DCPTime const time)
+{
+ DCPOMATIC_ASSERT (audio);
+
+ int const afr = film()->audio_frame_rate();
+
+ DCPTime const end = time + DCPTime::from_frames(audio->frames(), afr);
+
+ /* The audio we get might span a reel boundary, and if so we have to write it in bits */
+
+ DCPTime t = time;
+ while (t < end) {
+
+ if (_audio_reel == _reels.end ()) {
+ /* This audio is off the end of the last reel; ignore it */
+ return;
+ }
+
+ if (end <= _audio_reel->period().to) {
+ /* Easy case: we can write all the audio to this reel */
+ _audio_reel->write (audio);
+ t = end;
+ } else if (_audio_reel->period().to <= t) {
+ /* This reel is entirely before the start of our audio; just skip the reel */
+ ++_audio_reel;
+ } else {
+ /* This audio is over a reel boundary; split the audio into two and write the first part */
+ DCPTime part_lengths[2] = {
+ _audio_reel->period().to - t,
+ end - _audio_reel->period().to
+ };
+
+ /* Be careful that part_lengths[0] + part_lengths[1] can't be bigger than audio->frames() */
+ Frame part_frames[2] = {
+ part_lengths[0].frames_ceil(afr),
+ part_lengths[1].frames_floor(afr)
+ };
+
+ DCPOMATIC_ASSERT ((part_frames[0] + part_frames[1]) <= audio->frames());
+
+ if (part_frames[0]) {
+ shared_ptr<AudioBuffers> part (new AudioBuffers(audio, part_frames[0], 0));
+ _audio_reel->write (part);
+ }
+
+ if (part_frames[1]) {
+ audio.reset (new AudioBuffers(audio, part_frames[1], part_frames[0]));
+ } else {
+ audio.reset ();
+ }
+
+ ++_audio_reel;
+ t += part_lengths[0];
+ }
+ }
+}
+
+