/*
____ _____ _ _
| __ )| ____| | / \
| _ \| _| | | / _ \
| |_) | |___| |___ / ___ \
|____/|_____|_____/_/ \_\
http://bela.io
*/
/**
\example Audio/file-player/render.cpp
Playback of several large wav files
---------------------------
This example shows how to play audio files from a playlist sequentially.
It uses the AudioFileReader class, which loads data from the audio file into
memory in the background, while the user can request data safely from the
RT-thread via the AudioFileReader::getSamples() method.
We want to start playing back the next file as soon as the current one
finishes, so we need to start preloading the next one ahead of time. This is
done by using two AudioFileReader objects, where at any time one, whose index
is `gCurrReader`, will be playing back the current file while the other one
starts preloading the next file.
*/
#include <Bela.h>
#include <libraries/AudioFile/AudioFile.h>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <thread>
#include <atomic>
std::vector<AudioFileReader> gReaders(2);
std::vector<std::string> gFilenames = {
"05._Toy_Ballerina.wav",
"sample-4.wav",
// "number2.wav",
// "number3.wav",
// "number4.wav",
// "number5.wav",
// "number6.wav",
// "number7.wav",
};
size_t gLoadingFile;
size_t gCurrReader;
std::vector<float> gSamples;
size_t gFrameCount = 0;
AuxiliaryTask gStartLoadingFileTask;
// defining button GPIO
#define PLAY_PAUSE_BUTTON_PIN "/sys/class/gpio/gpio59/value";
#define SKIP_BUTTON_PIN "/sys/class/gpio/gpio58/value";
#define REPLAY_BUTTON_PIN "/sys/class/gpio/gpio57/value";
std::atomic<bool> gPauseFlag(false); // Flag to indicate whether the song is paused
// Function to read the play/pause button state asynchronously
void readPlayPauseButtonState() {
std::ifstream playPauseButton("/sys/class/gpio/gpio59/value");
if (!playPauseButton.is_open()) {
std::cerr << "Failed to open play/pause button GPIO file." << std::endl;
return;
}
std::string play_state;
while (true) {
// Read the play/pause button state
std::getline(playPauseButton, play_state);
std::cout << "Play state: " << play_state << std::endl;
// Check the state and enter the while loop if paused
if (play_state == "1") {
std::cout << "Play state: " << play_state << std::endl;
// Toggle the pause flag
gPauseFlag.store(!gPauseFlag.load(std::memory_order_relaxed), std::memory_order_relaxed);
}
playPauseButton.clear(); // Clear any error flags
playPauseButton.seekg(0, std::ios::beg); // Move the get pointer to the beginning of the file
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Adjust sleep duration as needed
}
// Close the file
playPauseButton.close();
}
std::thread buttonThread(readPlayPauseButtonState);
// creats global variable for input stream and initializes
// std::ifstream playPauseButton(PLAY_PAUSE_BUTTON_PIN);
// std::ifstream skipButton(SKIP_BUTTON_PIN);
// std::ifstream replayButton(REPLAY_BUTTON_PIN);
void loadNextFile(void*)
{
// start preloading the next file
gLoadingFile = (gLoadingFile + 1) % gFilenames.size();
size_t nextReader = (gCurrReader + 1) % gReaders.size();
gReaders[nextReader].setup(gFilenames[gLoadingFile], 16384);
rt_printf("Opening file [%d] %s in reader %d\n", gLoadingFile, gFilenames[gLoadingFile].c_str(), nextReader);
}
bool setup(BelaContext *context, void *userData)
{
// create a task to load files
gStartLoadingFileTask = Bela_createAuxiliaryTask(loadNextFile, 1, "loadNextFile");
if(!gStartLoadingFileTask) {
fprintf(stderr, "Error creating file loading task\n");
return false;
}
gLoadingFile = -1;
gCurrReader = -1;
// open the first file
loadNextFile(NULL);
gCurrReader = 0;
// open the second file
loadNextFile(NULL);
gSamples.reserve(context->audioFrames * gReaders[gCurrReader].getChannels());
std::string line;
return true;
}
std::atomic<unsigned int> gFrameIndex(0);
void render(BelaContext *context, void *userData) {
AudioFileReader& reader = gReaders[gCurrReader];
// this call may allocate memory if getChannels() is larger than for
// all previous files
gSamples.resize(context->audioFrames * reader.getChannels());
reader.getSamples(gSamples);
unsigned int n = gFrameIndex.load(std::memory_order_relaxed);
for(; n < context->audioFrames; )
{
std::cout << "Current frame index: " << n << std::endl;
float out;
// Check if the song is paused
if (gPauseFlag.load(std::memory_order_relaxed)) {
// If paused, skip audio processing
gFrameIndex.fetch_sub(1, std::memory_order_relaxed);
n = gFrameIndex.load(std::memory_order_relaxed);
continue;
} else {
gFrameIndex.fetch_add(1, std::memory_order_relaxed);
n = gFrameIndex.load(std::memory_order_relaxed);
}
for(unsigned int c = 0; c < context->audioOutChannels; ++c)
{
// write each channel from the audio file to the
// output channels. If there are more output channels
// than channels in the file, copy the file's last
// channel to all remaining outputs
if(c < reader.getChannels())
out = gSamples[n * reader.getChannels() + c];
audioWrite(context, n, c, out);
}
// count samples played back for the existing file
gFrameCount++;
if(gFrameCount >= reader.getLength())
{
// reached end of file
gFrameCount = 0;
// start playing the file we preloaded
gCurrReader = (gCurrReader + 1) % gReaders.size();
reader.getSamples(gSamples);
rt_printf("Playing from reader: %d\n", gCurrReader);
// start loading next file in a real-time safe way
Bela_scheduleAuxiliaryTask(gStartLoadingFileTask);
}
}
}
void cleanup(BelaContext *context, void *userData)
{
buttonThread.join();
}
This is what I currently have but the music doesn't seem to play anymore and I get the warning
- *** Error in
/root/Bela/projects/yesnt/yesnt': corrupted size vs. prev_size: 0x00773f18 ***`