1b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson/*
2b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * Copyright (C) 2011 The Android Open Source Project
3b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson *
4b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * Licensed under the Apache License, Version 2.0 (the "License");
5b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * you may not use this file except in compliance with the License.
6b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * You may obtain a copy of the License at
7b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson *
8b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson *      http://www.apache.org/licenses/LICENSE-2.0
9b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson *
10b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * Unless required by applicable law or agreed to in writing, software
11b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * distributed under the License is distributed on an "AS IS" BASIS,
12b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * See the License for the specific language governing permissions and
14b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson * limitations under the License.
15b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson */
16b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
17b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson#include "ring_buffer.h"
18b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
19b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson#include "integral_types.h"
20b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
21b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonnamespace video_editing {
22b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
23b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonvoid RingBuffer::Init(int size, int num_channels, int num_readers) {
24b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  size_ = size;
25b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  num_channels_ = num_channels;
26b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  num_readers_ = num_readers;
27b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  temp_read_buffer_size_ = 1024;
28b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  initialized_ = true;
29b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  Reset();
30b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
31b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
32b83ad73794088498d6d38cd3b4fc9311f505d051Hugo HudsonRingBuffer::RingBuffer()
33b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    : initialized_(false), samples_(NULL),
34b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      num_readers_(0), temp_read_buffer_(NULL) {
35b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
36b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
37b83ad73794088498d6d38cd3b4fc9311f505d051Hugo HudsonRingBuffer::~RingBuffer() {
38b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  delete[] samples_;
39b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  delete[] temp_read_buffer_;
40b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
41b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
42b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonvoid RingBuffer::Reset() {
43b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  delete[] samples_;
44b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  samples_ = new float[size_ * num_channels_];
45b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  memset(samples_, 0,
46b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson         size_ * num_channels_ * sizeof(samples_[0]));
47b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
48b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  temp_read_buffer_size_ = 1024;
49b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  delete[] temp_read_buffer_;
50b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  temp_read_buffer_ = new float[temp_read_buffer_size_ * num_channels_];
51b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  memset(temp_read_buffer_, 0,
52b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson         temp_read_buffer_size_ * num_channels_ * sizeof(samples_[0]));
53b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  readers_.clear();
54b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  for (int i = 0; i < num_readers_; ++i) {
55b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    readers_.push_back(0LL);
56b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  }
57b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  head_logical_ = 0LL;
58b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  head_ = 0;
59b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
60b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
61b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonint RingBuffer::available(int reader) const {
62b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  return head_logical_ - readers_[reader];
63b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
64b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
65b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonint RingBuffer::overhead() const {
66b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  int64 tail = GetTail();
67b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  return tail + size_ - head_logical_;
68b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
69b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
70b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonint64 RingBuffer::GetTail() const {
71b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  return *min_element(readers_.begin(), readers_.end());
72b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
73b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
74b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonint64 RingBuffer::Tell(int reader) const {
75b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  return readers_[reader];
76b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
77b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
78b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonvoid RingBuffer::Seek(int reader, int64 position) {
79b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  readers_[reader] = position;
80b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
81b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
82b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonvoid RingBuffer::Write(const float* samples, int num_frames) {
83b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  if (!num_frames) {
84b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    return;
85b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  }
86b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  if (head_ + num_frames <= size_) {
87b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    memcpy(samples_ + head_ * num_channels_, samples,
88b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson           num_frames * num_channels_ * sizeof(samples[0]));
89b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    head_ += num_frames;
90b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  } else {
91b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    int overhead = size_ - head_;
92b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    memcpy(samples_ + head_ * num_channels_, samples,
93b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson           num_channels_ * overhead * sizeof(samples[0]));
94b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    head_ = num_frames - overhead;
95b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    memcpy(samples_, samples + overhead * num_channels_,
96b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson           num_channels_ * head_ * sizeof(samples[0]));
97b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  }
98b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  head_logical_ += num_frames;
99b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
100b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
101b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonvoid RingBuffer::Copy(int reader, float* destination, int num_frames) const {
102b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  int pos = Tell(reader) % size_;
103b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  if (pos + num_frames <= size_) {
104b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    memcpy(destination, samples_ + pos * num_channels_,
105b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson           num_channels_ * num_frames * sizeof(destination[0]));
106b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  } else {
107b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    int wrapped = size_ - pos;
108b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    memcpy(destination, samples_ + pos * num_channels_,
109b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson           num_channels_ * wrapped * sizeof(destination[0]));
110b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    int remaining = num_frames - wrapped;
111b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    memcpy(destination + wrapped * num_channels_, samples_,
112b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson           num_channels_ * remaining * sizeof(destination[0]));
113b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  }
114b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
115b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
116b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonfloat* RingBuffer::GetPointer(int reader, int num_frames) {
117b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  int pos = Tell(reader) % size_;
118b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  if (pos + num_frames <= size_) {
119b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    return samples_ + pos * num_channels_;
120b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  } else {
121b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    if (num_frames > temp_read_buffer_size_) {
122b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      temp_read_buffer_size_ = num_frames;
123b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      delete[] temp_read_buffer_;
124b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      temp_read_buffer_ =
125b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson          new float[temp_read_buffer_size_ * num_channels_];  // NOLINT
126b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    }
127b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    Copy(reader, temp_read_buffer_, num_frames);
128b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    return temp_read_buffer_;
129b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  }
130b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
131b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
132b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudsonvoid RingBuffer::MergeBack(int reader, const float* source, int num_frames) {
133b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  // If the source pointer is not the temporary buffer,
134b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  // data updates were performed in place, so there is nothing to do.
135b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  // Otherwise, copy samples from the temp buffer back to the ring buffer.
136b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  if (source == temp_read_buffer_) {
137b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    int pos = Tell(reader) % size_;
138b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    if (pos + num_frames <= size_) {
139b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      memcpy(samples_ + (pos * num_channels_), source,
140b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson             num_channels_ * num_frames * sizeof(source[0]));
141b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    } else {
142b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      int wrapped = size_ - pos;
143b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      memcpy(samples_ + (pos * num_channels_), source,
144b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson             num_channels_ * wrapped * sizeof(source[0]));
145b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      int remaining = num_frames - wrapped;
146b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson      memcpy(samples_, source + (wrapped * num_channels_),
147b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson             num_channels_ * remaining * sizeof(source[0]));
148b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson    }
149b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson  }
150b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}
151b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson
152b83ad73794088498d6d38cd3b4fc9311f505d051Hugo Hudson}  // namespace video_editing
153