@@ -636,12 +636,11 @@ const SaveState& CarlaPlugin::getSaveState() | |||
void* data = nullptr; | |||
const int32_t dataSize(chunkData(&data)); | |||
if (data != nullptr && dataSize >= 4) | |||
if (data != nullptr && dataSize > 0) | |||
{ | |||
CarlaString chunkStr; | |||
chunkStr.importBinaryAsBase64((const uint8_t*)data, static_cast<size_t>(dataSize)); | |||
QByteArray chunk(QByteArray((char*)data, dataSize).toBase64()); | |||
saveState.chunk = carla_strdup(chunkStr); | |||
saveState.chunk = carla_strdup(chunk.constData()); | |||
// Don't save anything else if using chunks | |||
return saveState; | |||
@@ -39,8 +39,7 @@ public: | |||
fDssiDescriptor(nullptr), | |||
fAudioInBuffers(nullptr), | |||
fAudioOutBuffers(nullptr), | |||
fParamBuffers(nullptr), | |||
fLastChunk(nullptr) | |||
fParamBuffers(nullptr) | |||
{ | |||
carla_debug("DssiPlugin::DssiPlugin(%p, %i)", engine, id); | |||
@@ -91,12 +90,6 @@ public: | |||
fDssiDescriptor = nullptr; | |||
} | |||
if (fLastChunk != nullptr) | |||
{ | |||
delete[] fLastChunk; | |||
fLastChunk = nullptr; | |||
} | |||
clearBuffers(); | |||
} | |||
@@ -319,21 +312,14 @@ public: | |||
if (fDssiDescriptor->set_custom_data == nullptr) | |||
return; | |||
if (fLastChunk != nullptr) | |||
{ | |||
delete[] fLastChunk; | |||
fLastChunk = nullptr; | |||
} | |||
const size_t size(CarlaString(stringData).exportAsBase64Binary(&fLastChunk)); | |||
QByteArray chunk(QByteArray::fromBase64(stringData)); | |||
CARLA_ASSERT(size > 0); | |||
CARLA_ASSERT(fLastChunk != nullptr); | |||
CARLA_ASSERT(chunk.size() > 0); | |||
if (size > 0 && fLastChunk != nullptr) | |||
if (chunk.size() > 0) | |||
{ | |||
const ScopedSingleProcessLocker spl(this, true); | |||
fDssiDescriptor->set_custom_data(fHandle, fLastChunk, static_cast<unsigned long>(size)); | |||
fDssiDescriptor->set_custom_data(fHandle, chunk.data(), chunk.size()); | |||
} | |||
} | |||
@@ -1920,10 +1906,9 @@ private: | |||
const LADSPA_Descriptor* fDescriptor; | |||
const DSSI_Descriptor* fDssiDescriptor; | |||
float** fAudioInBuffers; | |||
float** fAudioOutBuffers; | |||
float* fParamBuffers; | |||
uint8_t* fLastChunk; | |||
float** fAudioInBuffers; | |||
float** fAudioOutBuffers; | |||
float* fParamBuffers; | |||
snd_seq_event_t fMidiEvents[MAX_MIDI_EVENTS]; | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DssiPlugin) | |||
@@ -108,7 +108,7 @@ public: | |||
if (fLastChunk != nullptr) | |||
{ | |||
delete[] fLastChunk; | |||
std::free(fLastChunk); | |||
fLastChunk = nullptr; | |||
} | |||
@@ -289,19 +289,21 @@ public: | |||
if (fLastChunk != nullptr) | |||
{ | |||
delete[] fLastChunk; | |||
std::free(fLastChunk); | |||
fLastChunk = nullptr; | |||
} | |||
const size_t size(CarlaString(stringData).exportAsBase64Binary(&fLastChunk)); | |||
QByteArray chunk(QByteArray::fromBase64(stringData)); | |||
CARLA_ASSERT(size > 0); | |||
CARLA_ASSERT(fLastChunk != nullptr); | |||
CARLA_ASSERT(chunk.size() > 0); | |||
if (size > 0 && fLastChunk != nullptr) | |||
if (chunk.size() > 0) | |||
{ | |||
fLastChunk = std::malloc(chunk.size()); | |||
std::memcpy(fLastChunk, chunk.constData(), chunk.size()); | |||
const ScopedSingleProcessLocker spl(this, true); | |||
dispatcher(effSetChunk, 0 /* bank */, size, fLastChunk, 0.0f); | |||
dispatcher(effSetChunk, 0 /* bank */, chunk.size(), fLastChunk, 0.0f); | |||
} | |||
} | |||
@@ -2258,7 +2260,7 @@ private: | |||
int fUnique1; | |||
AEffect* fEffect; | |||
uint8_t* fLastChunk; | |||
void* fLastChunk; | |||
uint32_t fMidiEventCount; | |||
VstMidiEvent fMidiEvents[MAX_MIDI_EVENTS*2]; | |||
VstTimeInfo_R fTimeInfo; | |||
@@ -1091,9 +1091,10 @@ const char* carla_get_chunk_data(unsigned int pluginId) | |||
void* data = nullptr; | |||
const int32_t dataSize = plugin->chunkData(&data); | |||
if (data != nullptr && dataSize >= 4) | |||
if (data != nullptr && dataSize > 0) | |||
{ | |||
chunkData.importBinaryAsBase64((const uint8_t*)data, static_cast<size_t>(dataSize)); | |||
QByteArray chunk(QByteArray((char*)data, dataSize).toBase64()); | |||
chunkData = chunk.constData(); | |||
return (const char*)chunkData; | |||
} | |||
else | |||
@@ -49,10 +49,12 @@ int main() | |||
int i; | |||
double d; | |||
void* ptr; | |||
char pad[17]; | |||
int32_t i32; | |||
int64_t i64; | |||
bool b; | |||
} blob; | |||
}; | |||
Blob blob; | |||
const size_t blobSize = sizeof(Blob); | |||
carla_zeroStruct<Blob>(blob); | |||
@@ -66,6 +68,7 @@ int main() | |||
blob.i32 = 32; | |||
blob.i64 = 64; | |||
blob.b = true; | |||
blob.pad[11] = 71; | |||
// binary -> base64 | |||
char blobEnc[carla_base64_encoded_len(blobSize) + 1]; | |||
@@ -90,6 +93,7 @@ int main() | |||
assert(blobTest.i32 == 32); | |||
assert(blobTest.i64 == 64); | |||
assert(blobTest.b == true); | |||
assert(blobTest.pad[11] == 71); | |||
} | |||
{ | |||
@@ -110,6 +114,7 @@ int main() | |||
assert(blobNew->i32 == 32); | |||
assert(blobNew->i64 == 64); | |||
assert(blobNew->b == true); | |||
assert(blobNew->pad[11] == 71); | |||
delete blobNew; | |||
} | |||
@@ -1,183 +0,0 @@ | |||
/* | |||
* Carla base64 utils imported from qemu source code | |||
* Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk> | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the GPL.txt file | |||
*/ | |||
#ifndef __CARLA_BASE64_UTILS_HPP__ | |||
#define __CARLA_BASE64_UTILS_HPP__ | |||
#include "CarlaUtils.hpp" | |||
#include <cctype> | |||
#include <cstdint> | |||
static const char kBase64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |||
/** | |||
* Calculate length of base64-encoded data | |||
* | |||
* @v rawLen Raw data length | |||
* @ret encodedLen Encoded string length (excluding NUL) | |||
*/ | |||
static inline | |||
size_t carla_base64_encoded_len(const size_t rawLen) | |||
{ | |||
return (((rawLen + 3 - 1) / 3) * 4); | |||
} | |||
/** | |||
* Calculate maximum length of base64-decoded string | |||
* | |||
* @v encoded Encoded string | |||
* @v maxRawLen Maximum length of raw data | |||
* | |||
* Note that the exact length of the raw data cannot be known until | |||
* the string is decoded. | |||
*/ | |||
static inline | |||
size_t carla_base64_decoded_max_len(const char* const encoded) | |||
{ | |||
return (((std::strlen(encoded) + 4 - 1) / 4) * 3); | |||
} | |||
/** | |||
* Base64-encode data | |||
* | |||
* @v raw Raw data | |||
* @v len Length of raw data | |||
* @v encoded Buffer for encoded string | |||
* | |||
* The buffer must be the correct length for the encoded string. | |||
* Use something like | |||
* | |||
* char buf[carla_base64_encoded_len(len) + 1]; | |||
* | |||
* (the +1 is for the terminating NUL) to provide a buffer of the correct size. | |||
*/ | |||
static inline | |||
void carla_base64_encode(const uint8_t* const raw, const size_t len, char* const encoded) | |||
{ | |||
const uint8_t* rawBytes = raw; | |||
uint8_t* encodedBytes = (uint8_t*)encoded; | |||
size_t rawBitLen = 8*len; | |||
size_t bit, tmp; | |||
for (bit = 0; bit < rawBitLen; bit += 6) | |||
{ | |||
tmp = static_cast<size_t>((rawBytes[bit/8] << (bit % 8)) | (rawBytes[bit/8 + 1] >> (8 - (bit % 8)))); | |||
tmp = static_cast<size_t>((tmp >> 2) & 0x3f); | |||
CARLA_ASSERT(tmp < 64); | |||
*(encodedBytes++) = static_cast<uint8_t>(kBase64[tmp]); | |||
} | |||
for (; (bit % 8) != 0; bit += 6) | |||
*(encodedBytes++) = '='; | |||
*(encodedBytes++) = '\0'; | |||
carla_debug("Base64-encoded to \"%s\"\n", encoded); | |||
CARLA_ASSERT(std::strlen(encoded) == carla_base64_encoded_len(len)); | |||
} | |||
/** | |||
* Base64-decode string | |||
* | |||
* @v encoded Encoded string | |||
* @v raw Raw data | |||
* @ret len Length of raw data, or 0 | |||
* | |||
* The buffer must be large enough to contain the decoded data. | |||
* Use something like | |||
* | |||
* char buf[carla_base64_decoded_max_len(encoded)]; | |||
* | |||
* to provide a buffer of the correct size. | |||
*/ | |||
static inline | |||
unsigned int carla_base64_decode(const char* const encoded, uint8_t* const raw) | |||
{ | |||
const uint8_t* encodedBytes = (const uint8_t*)encoded; | |||
uint8_t* rawBytes = raw; | |||
uint8_t encodedByte; | |||
unsigned int bit = 0; | |||
unsigned int padCount = 0; | |||
/* Zero the raw data */ | |||
carla_zeroMem(raw, carla_base64_decoded_max_len(encoded)); | |||
/* Decode string */ | |||
while ((encodedByte = *(encodedBytes++)) > 0) | |||
{ | |||
/* Ignore whitespace characters */ | |||
if (std::isspace(encodedByte)) | |||
continue; | |||
/* Process pad characters */ | |||
if (encodedByte == '=') | |||
{ | |||
if (padCount >= 2) | |||
{ | |||
carla_debug("Base64-encoded string \"%s\" has too many pad characters", encoded); | |||
return 0; | |||
} | |||
padCount++; | |||
bit -= 2; /* unused_bits = ( 2 * padCount ) */ | |||
continue; | |||
} | |||
if (padCount > 0) | |||
{ | |||
carla_debug("Base64-encoded string \"%s\" has invalid pad sequence", encoded); | |||
return 0; | |||
} | |||
/* Process normal characters */ | |||
const char* const match = std::strchr(kBase64, encodedByte); | |||
if (match == nullptr) | |||
{ | |||
carla_debug("Base64-encoded string \"%s\" contains invalid character '%c'", encoded, encodedByte); | |||
return 0; | |||
} | |||
uint8_t decoded = static_cast<uint8_t>(match - kBase64); | |||
/* Add to raw data */ | |||
decoded <<= 2; | |||
rawBytes[bit / 8] |= (decoded >> (bit % 8)); | |||
rawBytes[bit / 8 + 1] |= (decoded << (8 - (bit % 8))); | |||
bit += 6; | |||
} | |||
/* Check that we decoded a whole number of bytes */ | |||
if ((bit % 8) != 0) | |||
{ | |||
carla_debug("Base64-encoded string \"%s\" has invalid bit length %d", encoded, bit); | |||
return 0; | |||
} | |||
unsigned int len = bit/8; | |||
carla_debug("Base64-decoded from \"%s\"", encoded); | |||
CARLA_ASSERT(len <= carla_base64_decoded_max_len(encoded)); | |||
/* Return length in bytes */ | |||
return len; | |||
} | |||
#endif // __CARLA_BASE64_UTILS_HPP__ |
@@ -18,7 +18,6 @@ | |||
#ifndef __CARLA_STRING_HPP__ | |||
#define __CARLA_STRING_HPP__ | |||
#include "CarlaBase64Utils.hpp" | |||
#include "CarlaJuceUtils.hpp" | |||
// ------------------------------------------------- | |||
@@ -251,96 +250,26 @@ public: | |||
void toLower() | |||
{ | |||
static const char charDiff = 'a' - 'A'; | |||
static const char kCharDiff = 'a' - 'A'; | |||
for (size_t i=0; i < bufferLen; ++i) | |||
{ | |||
if (buffer[i] >= 'A' && buffer[i] <= 'Z') | |||
buffer[i] += charDiff; | |||
buffer[i] += kCharDiff; | |||
} | |||
} | |||
void toUpper() | |||
{ | |||
static const char charDiff = 'a' - 'A'; | |||
static const char kCharDiff = 'a' - 'A'; | |||
for (size_t i=0; i < bufferLen; ++i) | |||
{ | |||
if (buffer[i] >= 'a' && buffer[i] <= 'z') | |||
buffer[i] -= charDiff; | |||
buffer[i] -= kCharDiff; | |||
} | |||
} | |||
void toBase64() | |||
{ | |||
importBinaryAsBase64((const uint8_t*)buffer, bufferLen); | |||
} | |||
void fromBase64() | |||
{ | |||
uint8_t buffer2[carla_base64_decoded_max_len(buffer)]; | |||
if (unsigned int len = carla_base64_decode(buffer, buffer2)) | |||
{ | |||
char bufDecoded[len+1]; | |||
std::strncpy(bufDecoded, (char*)buffer2, len); | |||
bufDecoded[len] = '\0'; | |||
_dup(bufDecoded, len); | |||
} | |||
else | |||
clear(); | |||
} | |||
void importBinaryAsBase64(const uint8_t* const raw, const size_t rawLen) | |||
{ | |||
const size_t rawBufferSize = carla_base64_encoded_len(rawLen); | |||
char rawBuffer[rawBufferSize+1]; | |||
carla_base64_encode(raw, rawLen, rawBuffer); | |||
_dup(rawBuffer, rawBufferSize); | |||
} | |||
template<typename T> | |||
void importBinaryAsBase64(const T* const t) | |||
{ | |||
importBinaryAsBase64((const uint8_t*)t, sizeof(T)); | |||
} | |||
size_t exportAsBase64Binary(uint8_t** const rawPtr) | |||
{ | |||
uint8_t binaryBuffer[carla_base64_decoded_max_len(buffer)]; | |||
if (unsigned int len = carla_base64_decode(buffer, binaryBuffer)) | |||
{ | |||
uint8_t* const binaryBufferHeap = new uint8_t[len]; | |||
carla_copy<uint8_t>(binaryBufferHeap, binaryBuffer, len); | |||
*rawPtr = binaryBufferHeap; | |||
return len; | |||
} | |||
*rawPtr = nullptr; | |||
return 0; | |||
} | |||
template<typename T> | |||
T* exportAsBase64Binary() | |||
{ | |||
uint8_t binaryBuffer[carla_base64_decoded_max_len(buffer)]; | |||
if (unsigned int len = carla_base64_decode(buffer, binaryBuffer)) | |||
{ | |||
CARLA_ASSERT_INT2(len == sizeof(T), len, sizeof(T)); | |||
T* const t = new T(); | |||
std::memcpy(t, binaryBuffer, sizeof(T)); | |||
return t; | |||
} | |||
return nullptr; | |||
} | |||
// --------------------------------------------- | |||
// public operators | |||
@@ -1,274 +0,0 @@ | |||
/* | |||
* Carla Thread | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the GPL.txt file | |||
*/ | |||
#ifndef __CARLA_THREAD_HPP__ | |||
#define __CARLA_THREAD_HPP__ | |||
#include "CarlaJuceUtils.hpp" | |||
#error This class is not ready for usage yet | |||
// #define CPP11_THREAD | |||
#ifdef CPP11_THREAD | |||
# include <thread> | |||
#else | |||
# include <pthread.h> | |||
#endif | |||
// ------------------------------------------------- | |||
// CarlaThread class | |||
class CarlaThread | |||
{ | |||
public: | |||
CarlaThread() | |||
: fStarted(false), | |||
fFinished(false) | |||
{ | |||
#ifdef CPP11_THREAD | |||
cthread = nullptr; | |||
#else | |||
_zero(); | |||
pthread_attr_init(&pthreadAttr); | |||
pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_JOINABLE); | |||
#endif | |||
} | |||
~CarlaThread() | |||
{ | |||
CARLA_ASSERT(! isRunning()); | |||
if (isRunning()) | |||
terminate(); | |||
#ifdef CPP11_THREAD | |||
if (cthread != nullptr) | |||
{ | |||
cthread->join(); | |||
delete cthread; | |||
} | |||
#else | |||
//if (! _isNull()) | |||
// pthread_join(pthreadId, nullptr); | |||
pthread_attr_destroy(&pthreadAttr); | |||
#endif | |||
} | |||
bool start() | |||
{ | |||
CARLA_ASSERT(! isRunning()); | |||
if (isRunning()) | |||
return false; | |||
fStarted = false; | |||
fFinished = false; | |||
#ifdef CPP11_THREAD | |||
CARLA_ASSERT(cthread == nullptr); | |||
if (cthread != nullptr) | |||
return false; | |||
cthread = new std::thread(_cthreadRoutine, this); | |||
CARLA_ASSERT(cthread->joinable()); | |||
return true; | |||
#else | |||
CARLA_ASSERT(_isNull()); | |||
if (! _isNull()) | |||
return false; | |||
return (pthread_create(&pthreadId, &pthreadAttr, _pthreadRoutine, this) == 0); | |||
#endif | |||
} | |||
bool stop(const unsigned int timeout = 0) | |||
{ | |||
CARLA_ASSERT(isRunning()); | |||
if (! isRunning()) | |||
return true; | |||
#ifdef CPP11_THREAD | |||
if (cthread == nullptr) | |||
return true; | |||
#else | |||
if (_isNull()) | |||
return true; | |||
#endif | |||
if (timeout == 0) | |||
{ | |||
#ifdef CPP11_THREAD | |||
cthread->join(); | |||
#else | |||
pthread_join(pthreadId, nullptr); | |||
#endif | |||
} | |||
else | |||
{ | |||
for (unsigned int i=0; i < timeout && ! fFinished; i++) | |||
carla_msleep(1); | |||
} | |||
if (! fFinished) | |||
return false; | |||
#ifdef CPP11_THREAD | |||
delete cthread; | |||
cthread = nullptr; | |||
#else | |||
_zero(); | |||
#endif | |||
return true; | |||
} | |||
void terminate() | |||
{ | |||
CARLA_ASSERT(isRunning()); | |||
if (fFinished) | |||
return; | |||
#ifdef CPP11_THREAD | |||
if (cthread == nullptr) | |||
return; | |||
#else | |||
if (_isNull()) | |||
return; | |||
#endif | |||
#ifdef CPP11_THREAD | |||
cthread->detach(); | |||
//cthread->join(); | |||
delete cthread; | |||
cthread = nullptr; | |||
#else | |||
pthread_detach(pthreadId); | |||
//pthread_join(pthreadId, nullptr); | |||
pthread_cancel(pthreadId); | |||
_zero(); | |||
#endif | |||
fFinished = true; | |||
} | |||
bool isRunning() | |||
{ | |||
if (fStarted && ! fFinished) | |||
return true; | |||
// take the chance to clear data | |||
#ifdef CPP11_THREAD | |||
if (cthread != nullptr) | |||
{ | |||
cthread->join(); | |||
delete cthread; | |||
cthread = nullptr; | |||
} | |||
#else | |||
if (! _isNull()) | |||
{ | |||
//pthread_join(pthreadId, nullptr); | |||
//_zero(); | |||
} | |||
#endif | |||
return false; | |||
} | |||
void waitForStarted(const unsigned int timeout = 0) // ms | |||
{ | |||
if (fStarted) | |||
return; | |||
if (timeout == 0) | |||
{ | |||
while (! fStarted) | |||
carla_msleep(1); | |||
} | |||
else | |||
{ | |||
for (unsigned int i=0; i < timeout && ! fStarted; i++) | |||
carla_msleep(1); | |||
} | |||
} | |||
void waitForFinished() | |||
{ | |||
waitForStarted(); | |||
stop(0); | |||
} | |||
protected: | |||
virtual void run() = 0; | |||
private: | |||
bool fStarted; | |||
bool fFinished; | |||
void handleRoutine() | |||
{ | |||
fStarted = true; | |||
run(); | |||
fFinished = true; | |||
} | |||
#ifdef CPP11_THREAD | |||
std::thread* cthread; | |||
static void _cthreadRoutine(CarlaThread* const _this_) | |||
{ | |||
_this_->handleRoutine(); | |||
} | |||
#else | |||
pthread_t pthreadId; | |||
pthread_attr_t pthreadAttr; | |||
static void* _pthreadRoutine(void* const _this_) | |||
{ | |||
((CarlaThread*)_this_)->handleRoutine(); | |||
pthread_exit(nullptr); | |||
return nullptr; | |||
} | |||
bool _isNull() | |||
{ | |||
#ifdef CARLA_OS_WIN | |||
return (pthreadId.p == nullptr); | |||
#else | |||
return (pthreadId == 0); | |||
#endif | |||
} | |||
void _zero() | |||
{ | |||
carla_zeroStruct<pthread_t>(pthreadId); | |||
} | |||
#endif | |||
//CARLA_PREVENT_HEAP_ALLOCATION | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) | |||
}; | |||
// ------------------------------------------------- | |||
#endif // __CARLA_THREAD_HPP__ |