Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
microbit-carlos committed Oct 22, 2020
2 parents 4eecf71 + fac7b59 commit 6647b1a
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 46 deletions.
46 changes: 40 additions & 6 deletions inc/streams/MemorySource.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@ namespace codal
private:
int outputFormat; // The format to output in. By default, this is the same as the input.
int outputBufferSize; // The maximum size of an output buffer.
int bytesSent; // The number of bytes sent in the current buffer
ManagedBuffer buffer; // The output buffer being filled

uint8_t *data; // The input data being played (immutable)
uint8_t *in; // The input data being played (mutable)
int length; // The lenght of the input buffer (immutable)
int bytesToSend; // The lenght of the input buffer (mutable)
int count; // The number of times left to repeat

DataSink *downstream; // Pointer to our downstream component
bool blockingPlayout; // Set to true if a blocking playout has been requested
FiberLock lock; // used to synchronise blocking play calls.

public:
DataStream output;
DataSource &output; // DEPRECATED: backward compatilbity only

/**
* Default Constructor.
Expand Down Expand Up @@ -52,6 +61,12 @@ namespace codal
*/
virtual int setFormat(int format);

/*
* Allow out downstream component to register itself with us
*/
virtual void connect(DataSink &sink);


/**
* Determine the maximum size of the buffers streamed out of this component.
* @return The maximum size of this component's output buffers, in bytes.
Expand All @@ -68,16 +83,35 @@ namespace codal
* Perform a blocking playout of the data buffer. Returns when all the data has been queued.
* @param data pointer to memory location to playout
* @param length number of samples in the buffer. Assumes a sample size as defined by setFormat().
* @param loop if repeat playback of buffer when completed the given number of times. Defaults to one. Set to a negative number to loop forever.
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void play(const void *data, int length, int loop = 1);
void play(const void *data, int length, int count = 1);

/**
* Perform a blocking playout of the data buffer. Returns when all the data has been queued.
* @param b the buffer to playout
* @param loop if repeat playback of buffer when completed the given number of times. Defaults to one. Set to a negative number to loop forever.
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void play(ManagedBuffer b, int loop = 1);
void play(ManagedBuffer b, int count = 1);

/**
* Perform a blocking playout of the data buffer. Returns when all the data has been queued.
* @param data pointer to memory location to playout
* @param length number of samples in the buffer. Assumes a sample size as defined by setFormat().
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void playAsync(const void *data, int length, int count = 1);

/**
* Perform a blocking playout of the data buffer. Returns when all the data has been queued.
* @param b the buffer to playout
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void playAsync(ManagedBuffer b, int count = 1);


private:
void _play(const void *data, int length, int count, bool mode);
};
}
#endif
124 changes: 84 additions & 40 deletions source/streams/MemorySource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ using namespace codal;
*/
MemorySource::MemorySource() : output(*this)
{
this->bytesSent = 0;
this->downstream = NULL;
this->setFormat(DATASTREAM_FORMAT_8BIT_UNSIGNED);
this->setBufferSize(MEMORY_SOURCE_DEFAULT_MAX_BUFFER);
lock.wait();
}

/*
* Allow out downstream component to register itself with us
*/
void MemorySource::connect(DataSink &sink)
{
this->downstream = &sink;
}


/**
* Determine the data format of the buffers streamed out of this component.
*/
Expand Down Expand Up @@ -62,59 +72,93 @@ MemorySource::setBufferSize(int size)
*/
ManagedBuffer MemorySource::pull()
{
// Calculate the amount of data we can transfer.
int l = min(bytesToSend, outputBufferSize);
buffer = ManagedBuffer(l);

memcpy(&buffer[0], in, l);

bytesToSend -= l;
in += l;

// If we've consumed the input buffer, see if we need to reload it
if (bytesToSend == 0)
{
if (count > 0)
count--;

if (count != 0)
{
bytesToSend = length;
in = data;
}
}

// If we still have data to send, indicate this to our downstream component
if (bytesToSend > 0)
downstream->pullRequest();

// If we have completed playback and blockingbehaviour was requested, wake the fiber that is blocked waiting.
if (bytesToSend == 0 && count == 0 && blockingPlayout)
lock.notify();

return buffer;
}
}

/**
* Perform a blocking playout of the data buffer. Returns when all the data has been queued.
* Perform a non-blocking playout of the data buffer. Returns when all the data has been queued.
* @param data pointer to memory location to playout
* @param length number of samples in the buffer. Assumes a sample size as defined by setFormat().
* @param loop if repeat playback of buffer when completed the given number of times. Set to a negative number to loop forever.
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void MemorySource::play(const void *data, int length, int loop)
void MemorySource::playAsync(const void *data, int length, int count)
{
uint8_t *out;
uint8_t *in;

in = (uint8_t *)data;
length = length * DATASTREAM_FORMAT_BYTES_PER_SAMPLE(outputFormat);

do
{
while (bytesSent < length)
{
int size = min(length - bytesSent, outputBufferSize);
buffer = ManagedBuffer(size);
out = &buffer[0];

memcpy(out, in, size);
in += size;
bytesSent += size;

output.pullRequest();
}
_play(data, length, count, false);
}

bytesSent = 0;
if (loop > 0)
loop--;
/**
* Perform a non-blocking playout of the data buffer. Returns when all the data has been queued.
* @param b the buffer to playout
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void MemorySource::playAsync(ManagedBuffer b, int count)
{
this->play(&b[0], b.length(), count);
}

} while (loop);
/**
* Perform a blocking playout of the data buffer. Returns when all the data has been queued.
* @param data pointer to memory location to playout
* @param length number of samples in the buffer. Assumes a sample size as defined by setFormat().
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void MemorySource::play(const void *data, int length, int count)
{
_play(data, length, count, true);
}

/**
* Perform a blocking playout of the data buffer. Returns when all the data has been queued.
* @param b the buffer to playout
* @param loop if repeat playback of buffer when completed the given number of times. Set to a negative number to loop forever.
* @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever.
*/
void MemorySource::play(ManagedBuffer b, int loop)
void MemorySource::play(ManagedBuffer b, int count)
{
do
{
buffer = b;
output.pullRequest();

if (loop > 0)
loop--;
this->play(&b[0], b.length(), count);
}

} while (loop);
}
void MemorySource::_play(const void *data, int length, int count, bool mode)
{
if (downstream == NULL || length <= 0 || count == 0)
return;

this->data = this->in = (uint8_t *)data;
this->length =this->bytesToSend = length;
this->count = count;
this->blockingPlayout = mode;

downstream->pullRequest();

if (this->blockingPlayout)
lock.wait();
}

0 comments on commit 6647b1a

Please sign in to comment.