-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
v1.0.0! added tutorial bela2python2bela, minor fixes
- Loading branch information
Showing
21 changed files
with
649 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
# pybela | ||
|
||
pybela allows interfacing with [Bela](https://bela.io/), the embedded audio platform, using Python. pybela provides a convenient way to stream, log, monitor sensor data from Bela to python. It also allows you to send buffers of data from python to Bela or control the value of variables in your Bela code from python. | ||
pybela enables seamless interfacing with [Bela](https://bela.io/), the embedded audio platform, using python. It offers a convenient way to stream data between Bela and python in both directions. In addition to data streaming, pybela supports data logging, as well as variable monitoring and control functionalities. | ||
|
||
Below, you can find instructions to install pybela. You can find code examples at `tutorials/` and `test/`. The docs are available at [https://belaplatform.github.io/pybela/](https://belaplatform.github.io/pybela/). | ||
|
||
pybela was developed with a machine learning use case in mind. For a complete pipeline including data acquisition, processing, model training, and deployment (including rapid cross-compilation) check the [pybela-pytorch-xc-tutorial](https://github.com/pelinski/pybela-pytorch-xc-tutorial). | ||
pybela was developed with a machine learning use-case in mind. For a complete pipeline including data acquisition, processing, model training, and deployment (including rapid cross-compilation) check the [pybela-pytorch-xc-tutorial](https://github.com/pelinski/pybela-pytorch-xc-tutorial). | ||
|
||
## Installation and set up | ||
|
||
|
@@ -85,7 +85,7 @@ scp watcher/Watcher.h watcher/Watcher.cpp [email protected]:Bela/projects/your-pro | |
|
||
pybela has three different modes of operation: | ||
|
||
- **Streaming**: continuously send data from Bela to python (**NEW: or vice versa!** check the [tutorial](tutorials/notebooks/2_Streamer-python-to-Bela.ipynb)). | ||
- **Streaming**: continuously send data from Bela to python (**NEW: and from python to Bela!** check the [tutorial](tutorials/notebooks/3_Streamer-python-to-Bela.ipynb)). | ||
- **Logging**: log data in a file in Bela and then retrieve it in python. | ||
- **Monitoring**: monitor the value of variables in the Bela code from python. | ||
- **Controlling**: control the value of variables in the Bela code from python. | ||
|
@@ -193,10 +193,6 @@ pipenv run python -m build --sdist # builds the .tar.gz file | |
|
||
## To do and known issues | ||
|
||
**Before next release** | ||
|
||
- [ ] **Add** a tutorial for `.send_buffer`, and data and buffers callback | ||
|
||
**Long term** | ||
|
||
- [ ] **Design**: remove nest_asyncio? | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
|
||
setuptools.setup( | ||
name="pybela", | ||
version="0.1.0", | ||
version="1.0.0", | ||
author="Teresa Pelinski", | ||
author_email="[email protected]", | ||
description="pybela allows interfacing with Bela, the embedded audio platform, using Python. pybela provides a convenient way to stream, log, and monitor sensor data from your Bela device to your laptop, or alternatively, to stream values to a Bela program from your laptop.", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ The watcher code is already included in `bela-test`. You can update your Bela AP | |
To run the tests, copy the `bela-test` code into your Bela, add the `Watcher`` library compile and run it: | ||
|
||
```bash | ||
rsync -rvL test/bela-test [email protected]:Bela/projects/ | ||
rsync -rvL test/bela-test test/bela-test-send [email protected]:Bela/projects/ | ||
ssh [email protected] "make -C Bela stop Bela PROJECT=bela-test run" | ||
``` | ||
|
||
|
@@ -16,3 +16,15 @@ Once the `bela-test` project is running on Bela, you can run the python tests by | |
```bash | ||
python test.py # or `pipenv run python test.py` if you are using a pipenv environment | ||
``` | ||
|
||
You can also test the `bela-test-send` project by running: | ||
|
||
```bash | ||
ssh [email protected] "make -C Bela stop Bela PROJECT=bela-test run" | ||
``` | ||
and then running the python tests with: | ||
|
||
```bash | ||
python test-send.py # or `pipenv run python test-send.py` if you are using a pipenv environment | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../watcher/Watcher.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../watcher/Watcher.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
#include <Bela.h> | ||
#include <Watcher.h> | ||
#include <cmath> | ||
#include <vector> | ||
#include <RtThread.h> | ||
|
||
#define NUM_OUTPUTS 2 | ||
#define MAX_EXPECTED_BUFFER_SIZE 1024 | ||
|
||
Watcher<float> pot1("pot1"); | ||
Watcher<float> pot2("pot2"); | ||
|
||
uint gPot1Ch = 0; | ||
uint gPot2Ch = 1; | ||
|
||
std::vector<std::vector<float>> circularBuffers(NUM_OUTPUTS); | ||
|
||
size_t circularBufferSize = 30 * 1024; | ||
size_t prefillSize = 2.5 * 1024; | ||
uint32_t circularBufferWriteIndex[NUM_OUTPUTS] = {0}; | ||
uint32_t circularBufferReadIndex[NUM_OUTPUTS] = {0}; | ||
|
||
struct ReceivedBuffer { | ||
uint32_t bufferId; | ||
char bufferType[4]; | ||
uint32_t bufferLen; | ||
uint32_t empty; | ||
std::vector<float> bufferData; | ||
}; | ||
ReceivedBuffer receivedBuffer; | ||
uint receivedBufferHeaderSize; | ||
uint64_t totalReceivedCount; // total number of received buffers | ||
|
||
unsigned int gAudioFramesPerAnalogFrame; | ||
float gInvAudioFramesPerAnalogFrame; | ||
float gInverseSampleRate; | ||
float gPhase1; | ||
float gPhase2; | ||
float gFrequency1 = 440.0f; | ||
float gFrequency2 = 880.0f; | ||
|
||
// this callback is called every time a buffer is received from python. it parses the received data into the ReceivedBuffer struct, and then writes the data to the circular buffer which is read in the | ||
// render function | ||
bool binaryDataCallback(const std::string& addr, const WSServerDetails* id, const unsigned char* data, size_t size, void* arg) { | ||
|
||
if (totalReceivedCount == 0) { | ||
RtThread::setThisThreadPriority(1); | ||
} | ||
|
||
totalReceivedCount++; | ||
|
||
// parse buffer header | ||
std::memcpy(&receivedBuffer, data, receivedBufferHeaderSize); | ||
receivedBuffer.bufferData.resize(receivedBuffer.bufferLen); | ||
// parse buffer data | ||
std::memcpy(receivedBuffer.bufferData.data(), data + receivedBufferHeaderSize, receivedBuffer.bufferLen * sizeof(float)); | ||
|
||
// write the data onto the circular buffer | ||
int _id = receivedBuffer.bufferId; | ||
if (_id >= 0 && _id < NUM_OUTPUTS) { | ||
for (size_t i = 0; i < receivedBuffer.bufferLen; ++i) { | ||
circularBuffers[_id][circularBufferWriteIndex[_id]] = receivedBuffer.bufferData[i]; | ||
circularBufferWriteIndex[_id] = (circularBufferWriteIndex[_id] + 1) % circularBufferSize; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool setup(BelaContext* context, void* userData) { | ||
|
||
Bela_getDefaultWatcherManager()->getGui().setup(context->projectName); | ||
Bela_getDefaultWatcherManager()->setup(context->audioSampleRate); // set sample rate in watcher | ||
|
||
gAudioFramesPerAnalogFrame = context->audioFrames / context->analogFrames; | ||
gInvAudioFramesPerAnalogFrame = 1.0 / gAudioFramesPerAnalogFrame; | ||
gInverseSampleRate = 1.0 / context->audioSampleRate; | ||
|
||
// initialize the Gui buffers and circular buffers | ||
for (int i = 0; i < NUM_OUTPUTS; ++i) { | ||
Bela_getDefaultWatcherManager()->getGui().setBuffer('f', MAX_EXPECTED_BUFFER_SIZE); | ||
circularBuffers[i].resize(circularBufferSize, 0.0f); | ||
// the write index is given some "advantage" (prefillSize) so that the read pointer does not catch up the write pointer | ||
circularBufferWriteIndex[i] = prefillSize % circularBufferSize; | ||
} | ||
|
||
Bela_getDefaultWatcherManager()->getGui().setBinaryDataCallback(binaryDataCallback); | ||
|
||
// vars and preparation for parsing the received buffer | ||
receivedBufferHeaderSize = sizeof(receivedBuffer.bufferId) + sizeof(receivedBuffer.bufferType) + sizeof(receivedBuffer.bufferLen) + sizeof(receivedBuffer.empty); | ||
totalReceivedCount = 0; | ||
receivedBuffer.bufferData.reserve(MAX_EXPECTED_BUFFER_SIZE); | ||
|
||
return true; | ||
} | ||
|
||
void render(BelaContext* context, void* userData) { | ||
for (unsigned int n = 0; n < context->audioFrames; n++) { | ||
uint64_t frames = context->audioFramesElapsed + n; | ||
|
||
if (gAudioFramesPerAnalogFrame && !(n % gAudioFramesPerAnalogFrame)) { | ||
Bela_getDefaultWatcherManager()->tick(frames * gInvAudioFramesPerAnalogFrame); // watcher timestamps | ||
|
||
// read sensor values and put them in the watcher | ||
pot1 = analogRead(context, n / gAudioFramesPerAnalogFrame, gPot1Ch); | ||
pot2 = analogRead(context, n / gAudioFramesPerAnalogFrame, gPot2Ch); | ||
|
||
// read the values sent from python (they're in the circular buffer) | ||
for (unsigned int i = 0; i < NUM_OUTPUTS; i++) { | ||
|
||
if (totalReceivedCount > 0 && (circularBufferReadIndex[i] + 1) % circularBufferSize != circularBufferWriteIndex[i]) { | ||
circularBufferReadIndex[i] = (circularBufferReadIndex[i] + 1) % circularBufferSize; | ||
} else if (totalReceivedCount > 0) { | ||
rt_printf("The read pointer has caught the write pointer up in buffer %d – try increasing prefillSize\n", i); | ||
} | ||
} | ||
} | ||
float amp1 = circularBuffers[0][circularBufferReadIndex[0]]; | ||
float amp2 = circularBuffers[1][circularBufferReadIndex[1]]; | ||
|
||
float out = amp1 * sinf(gPhase1) + amp2 * sinf(gPhase2); | ||
|
||
for (unsigned int channel = 0; channel < context->audioOutChannels; channel++) { | ||
audioWrite(context, n, channel, out); | ||
} | ||
|
||
gPhase1 += 2.0f * (float)M_PI * gFrequency1 * gInverseSampleRate; | ||
if (gPhase1 > M_PI) | ||
gPhase1 -= 2.0f * (float)M_PI; | ||
gPhase2 += 2.0f * (float)M_PI * gFrequency2 * gInverseSampleRate; | ||
if (gPhase2 > M_PI) | ||
gPhase2 -= 2.0f * (float)M_PI; | ||
} | ||
} | ||
|
||
void cleanup(BelaContext* context, void* userData) { | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.