Beatmup
realtime_playback.cpp
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2019, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "../../debug.h"
20 #include "realtime_playback.h"
21 
22 using namespace Beatmup;
23 using namespace Audio;
24 
25 
27 {}
28 
29 
31  freeBuffers();
32 }
33 
34 
36  if (buffers == nullptr)
37  return;
38  for (int i = 0; i < numBuffers; i++)
39  freeBuffer(buffers[i]);
40  delete[] buffers;
41  buffers = nullptr;
42 }
43 
44 
46  freeBuffers();
48  buffers = new sample8*[numBuffers];
49  for (int i = 0; i < numBuffers; i++)
51 }
52 
53 
55  sample8* buffer = (sample8*) malloc(bufferSize);
56  std::memset(buffer, 0, bufferSize);
57  return buffer;
58 }
59 
60 
62  free(buffer);
63 }
64 
65 
68 
69  // set default buffer size
71 
72  // prepare buffers
74 }
75 
76 
78  // setting up control variables
82 }
83 
84 
86  if (!source)
87  return false;
88 
89  int myFillIndex = 0;
90 
91  while (!thread.isTaskAborted()) {
92  source->render(thread, buffers[myFillIndex % numBuffers], mode.bufferLength);
93  myFillIndex++;
94  if (thread.isManaging()) {
95  fillIndex = myFillIndex;
96  advanceTime();
97  // if pushing output mode, then push
100  sendIndex++;
101  }
102  // wait till some buffers are available
103  while (fillIndex - playIndex >= numBuffers)
104  std::this_thread::yield();
105  }
106  thread.synchronize();
107  }
108 
109  return true;
110 }
111 
112 
115 
116  // skipping frames first
117  if (skipFrames > 0) {
118  if (numFrames < skipFrames) {
119  skipFrames -= numFrames;
120  return;
121  }
122  else {
123  buffer += skipFrames * frameSize;
124  numFrames -= skipFrames;
125  skipFrames = 0;
126  }
127  }
128 
129  // copying data from internal buffers until the requested number of frames is reached or underrun occurs
130  const dtime playingBufferSize = mode.bufferLength;
131  while (numFrames > 0 && playIndex - fillIndex < 0) {
132  const dtime
133  chunk = std::min(numFrames, playingBufferSize - playingBufferOffset),
134  numBytes = chunk * frameSize;
135  std::memcpy(buffer, buffers[playIndex % numBuffers] + playingBufferOffset * frameSize, (size_t) numBytes);
136  numFrames -= chunk;
137  playingBufferOffset += chunk;
138  buffer += numBytes;
139  // switching to the next buffer if it is the moment
140  if (playingBufferOffset >= playingBufferSize) {
141  playIndex++;
143  }
144  }
145 
146  // check for underrun
147  if (playIndex - fillIndex >= 0 && numFrames > 0) {
149  BEATMUP_DEBUG_I("UNDERRUN");
150  }
151 }
void advanceTime()
Moves time pointer one buffer forward.
virtual void initialize(Mode mode)
Initializes the playback setting its main parameters.
virtual void pushBuffer(sample8 *buffer, int bufferIndex)
Pushes some data to the output.
void prepareBuffers(const AbstractPlayback::Mode &mode)
Allocates all the atomic buffers.
sample8 ** buffers
buffers containing the data to play
virtual void freeBuffer(sample8 *buffer) const
Frees an atomic playing buffer.
OutputMode
Specifies how the output audio signal is handled by the audio backend.
@ PUSH
The output is sent to pushOutput(..) called by the rendering thread.
int playIndex
points to the buffer currently being played; updated only in the callback
virtual sample8 * createBuffer(const AbstractPlayback::Mode &mode) const
Creates an atomic playing buffer.
dtime playingBufferOffset
when pulling output, offset in frames with respect to the currently playing buffer
bool process(TaskThread &thread)
Executes the task on CPU within a given thread.
void pullBuffer(sample8 *buffer, dtime numFrames)
Called in pulling output mode to send data to output.
int sendIndex
points to the first buffer ready for playing
int fillIndex
points to the buffer currently being filled
void initialize(Mode mode)
Initializes the playback setting its main parameters.
msize bufferSize
size of each buffer in bytes
dtime skipFrames
when pulling output, number of frames to skip to give some time to the rendering process
virtual void start()
Starts playback.
virtual void render(TaskThread &thread, sample8 *buffer, const dtime bufferLength)=0
Renders audio data to the target output buffer given by the user.
Thread executing tasks.
Definition: parallelism.h:154
bool isManaging() const
Definition: parallelism.h:172
virtual void synchronize()=0
Blocks until all the other threads running the same task reach the same point.
virtual bool isTaskAborted() const =0
Returns true if the task is asked to stop from outside.
#define BEATMUP_DEBUG_I(...)
Definition: debug.h:33
uint32_t msize
memory size
Definition: basic_types.h:30
const int AUDIO_SAMPLE_SIZE[]
int dtime
discrete time
Definition: basic_types.h:37
CustomPoint< numeric > min(const CustomPoint< numeric > &a, const CustomPoint< numeric > &b)
Definition: geometry.h:724
AudioSampleFormat sampleFormat
format of each sample
unsigned char numBuffers
number of atomic buffers
unsigned char numChannels
number of channels
dtime bufferLength
length of each atomic buffer in samples
JNIEnv jlong jint mode