|
|
@@ -1,6 +1,6 @@ |
|
|
|
/* |
|
|
|
* Carla Native Plugins |
|
|
|
* Copyright (C) 2013-2022 Filipe Coelho <falktx@falktx.com> |
|
|
|
* Copyright (C) 2013-2023 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 |
|
|
@@ -20,37 +20,37 @@ |
|
|
|
|
|
|
|
#include "audio-base.hpp" |
|
|
|
|
|
|
|
static const char* const audiofilesWildcard = |
|
|
|
#ifdef HAVE_SNDFILE |
|
|
|
"*.aif;*.aifc;*.aiff;*.au;*.bwf;*.flac;*.htk;*.iff;*.mat4;*.mat5;*.oga;*.ogg;*.opus;" |
|
|
|
"*.paf;*.pvf;*.pvf5;*.sd2;*.sf;*.snd;*.svx;*.vcc;*.w64;*.wav;*.xi;" |
|
|
|
#endif |
|
|
|
#ifdef HAVE_FFMPEG |
|
|
|
"*.3g2;*.3gp;*.aac;*.ac3;*.amr;*.ape;*.mp2;*.mp3;*.mpc;*.wma;" |
|
|
|
# ifndef HAVE_SNDFILE |
|
|
|
"*.flac;*.oga;*.ogg;*.w64;*.wav;" |
|
|
|
# endif |
|
|
|
#else |
|
|
|
"*.mp3;" |
|
|
|
#endif |
|
|
|
; |
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
class AudioFilePlugin : public NativePluginWithMidiPrograms<FileAudio> |
|
|
|
#else |
|
|
|
class AudioFilePlugin : public NativePluginClass |
|
|
|
#endif |
|
|
|
{ |
|
|
|
public: |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
typedef enum _PendingInlineDisplay |
|
|
|
# ifdef CARLA_PROPER_CPP11_SUPPORT |
|
|
|
: uint8_t |
|
|
|
# endif |
|
|
|
{ |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
static constexpr const char* const audiofilesWildcard = |
|
|
|
#ifdef HAVE_SNDFILE |
|
|
|
"*.aif;*.aifc;*.aiff;*.au;*.bwf;*.flac;*.htk;*.iff;*.mat4;*.mat5;*.oga;*.ogg;*.opus;" |
|
|
|
"*.paf;*.pvf;*.pvf5;*.sd2;*.sf;*.snd;*.svx;*.vcc;*.w64;*.wav;*.xi;" |
|
|
|
#endif |
|
|
|
#ifdef HAVE_FFMPEG |
|
|
|
"*.3g2;*.3gp;*.aac;*.ac3;*.amr;*.ape;*.mp2;*.mp3;*.mpc;*.wma;" |
|
|
|
#ifndef HAVE_SNDFILE |
|
|
|
"*.flac;*.oga;*.ogg;*.w64;*.wav;" |
|
|
|
#endif |
|
|
|
#else |
|
|
|
"*.mp3;" |
|
|
|
#endif |
|
|
|
; |
|
|
|
|
|
|
|
enum PendingInlineDisplay : uint8_t { |
|
|
|
InlineDisplayNotPending, |
|
|
|
InlineDisplayNeedRequest, |
|
|
|
InlineDisplayRequesting |
|
|
|
} PendingInlineDisplay; |
|
|
|
#endif |
|
|
|
}; |
|
|
|
#endif |
|
|
|
|
|
|
|
enum Parameters { |
|
|
|
kParameterLooping, |
|
|
@@ -68,42 +68,35 @@ public: |
|
|
|
}; |
|
|
|
|
|
|
|
AudioFilePlugin(const NativeHostDescriptor* const host) |
|
|
|
: NativePluginWithMidiPrograms<FileAudio>(host, fPrograms, 2), |
|
|
|
fLoopMode(true), |
|
|
|
#ifdef __MOD_DEVICES__ |
|
|
|
fHostSync(false), |
|
|
|
#else |
|
|
|
fHostSync(true), |
|
|
|
#endif |
|
|
|
fEnabled(true), |
|
|
|
fDoProcess(false), |
|
|
|
fWasPlayingBefore(false), |
|
|
|
fNeedsFileRead(false), |
|
|
|
fEntireFileLoaded(false), |
|
|
|
fMaxFrame(0), |
|
|
|
fInternalTransportFrame(0), |
|
|
|
fLastPosition(0.0f), |
|
|
|
fLastPoolFill(0.0f), |
|
|
|
fVolume(1.0f), |
|
|
|
fPool(), |
|
|
|
fReader(), |
|
|
|
fFilename(), |
|
|
|
fPrograms(hostGetFilePath("audio"), audiofilesWildcard), |
|
|
|
fPreviewData() |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
, fInlineDisplay() |
|
|
|
#endif |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
: NativePluginWithMidiPrograms<FileAudio>(host, fPrograms, 3), |
|
|
|
fPrograms(hostGetFilePath("audio"), audiofilesWildcard) |
|
|
|
#else |
|
|
|
: NativePluginClass(host) |
|
|
|
#endif |
|
|
|
// fWasPlayingBefore(false), |
|
|
|
// fNeedsFileRead(false), |
|
|
|
// fEntireFileLoaded(false), |
|
|
|
// fMaxFrame(0), |
|
|
|
// fLastPoolFill(0.0f), |
|
|
|
// fPool(), |
|
|
|
// fReader(), |
|
|
|
// fFilename(), |
|
|
|
// fPreviewData() |
|
|
|
// #ifndef __MOD_DEVICES__ |
|
|
|
// , fInlineDisplay() |
|
|
|
// #endif |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
~AudioFilePlugin() override |
|
|
|
{ |
|
|
|
fReader.destroy(); |
|
|
|
fPool.destroy(); |
|
|
|
// fReader.destroy(); |
|
|
|
// fPool.destroy(); |
|
|
|
} |
|
|
|
|
|
|
|
protected: |
|
|
|
// ------------------------------------------------------------------- |
|
|
|
// ---------------------------------------------------------------------------------------------------------------- |
|
|
|
// Plugin parameter calls |
|
|
|
|
|
|
|
uint32_t getParameterCount() const override |
|
|
@@ -139,11 +132,11 @@ protected: |
|
|
|
param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMATABLE| |
|
|
|
NATIVE_PARAMETER_IS_ENABLED| |
|
|
|
NATIVE_PARAMETER_IS_BOOLEAN); |
|
|
|
#ifdef __MOD_DEVICES__ |
|
|
|
#ifdef __MOD_DEVICES__ |
|
|
|
param.ranges.def = 0.0f; |
|
|
|
#else |
|
|
|
#else |
|
|
|
param.ranges.def = 1.0f; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
param.ranges.min = 0.0f; |
|
|
|
param.ranges.max = 1.0f; |
|
|
|
break; |
|
|
@@ -253,15 +246,15 @@ protected: |
|
|
|
case kParameterLooping: |
|
|
|
return fLoopMode ? 1.0f : 0.0f; |
|
|
|
case kParameterHostSync: |
|
|
|
return fHostSync ? 1.0f : 0.0f; |
|
|
|
return fHostSync ? 1.f : 0.f; |
|
|
|
case kParameterEnabled: |
|
|
|
return fEnabled ? 1.0f : 0.0f; |
|
|
|
return fEnabled ? 1.f : 0.f; |
|
|
|
case kParameterVolume: |
|
|
|
return fVolume * 100.0f; |
|
|
|
return fVolume * 100.f; |
|
|
|
case kParameterInfoPosition: |
|
|
|
return fLastPosition; |
|
|
|
case kParameterInfoPoolFill: |
|
|
|
return fLastPoolFill; |
|
|
|
// case kParameterInfoPoolFill: |
|
|
|
// return fLastPoolFill; |
|
|
|
case kParameterInfoBitRate: |
|
|
|
return static_cast<float>(fReader.getCurrentBitRate()); |
|
|
|
} |
|
|
@@ -277,24 +270,21 @@ protected: |
|
|
|
case kParameterInfoSampleRate: |
|
|
|
return static_cast<float>(nfo.sample_rate); |
|
|
|
case kParameterInfoLength: |
|
|
|
return static_cast<float>(nfo.length)/1000.0f; |
|
|
|
default: |
|
|
|
return 0.0f; |
|
|
|
return static_cast<float>(nfo.length)/1000.f; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------- |
|
|
|
// Plugin state calls |
|
|
|
return 0.f; |
|
|
|
} |
|
|
|
|
|
|
|
void setParameterValue(const uint32_t index, const float value) override |
|
|
|
{ |
|
|
|
if (index == kParameterVolume) |
|
|
|
{ |
|
|
|
fVolume = value / 100.0f; |
|
|
|
fVolume = value / 100.f; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const bool b = (value > 0.5f); |
|
|
|
const bool b = value > 0.5f; |
|
|
|
|
|
|
|
switch (index) |
|
|
|
{ |
|
|
@@ -302,7 +292,7 @@ protected: |
|
|
|
if (fLoopMode != b) |
|
|
|
{ |
|
|
|
fLoopMode = b; |
|
|
|
fReader.setLoopingMode(b); |
|
|
|
// fReader.setLoopingMode(b); |
|
|
|
} |
|
|
|
break; |
|
|
|
case kParameterHostSync: |
|
|
@@ -324,51 +314,69 @@ protected: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------- |
|
|
|
// Plugin state calls |
|
|
|
|
|
|
|
void setCustomData(const char* const key, const char* const value) override |
|
|
|
{ |
|
|
|
if (std::strcmp(key, "file") != 0) |
|
|
|
return; |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
invalidateNextFilename(); |
|
|
|
#endif |
|
|
|
loadFilename(value); |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------- |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
void setStateFromFile(const char* const filename) override |
|
|
|
{ |
|
|
|
loadFilename(filename); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------- |
|
|
|
// Plugin process calls |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
void process2(const float* const*, float** const outBuffer, const uint32_t frames, |
|
|
|
const NativeMidiEvent*, uint32_t) override |
|
|
|
#else |
|
|
|
void process(const float* const*, float** const outBuffer, const uint32_t frames, |
|
|
|
const NativeMidiEvent*, uint32_t) override |
|
|
|
#endif |
|
|
|
{ |
|
|
|
float* const out1 = outBuffer[0]; |
|
|
|
float* const out2 = outBuffer[1]; |
|
|
|
float* const playCV = outBuffer[2]; |
|
|
|
|
|
|
|
const water::GenericScopedLock<water::SpinLock> gsl(fPool.mutex); |
|
|
|
// const water::GenericScopedLock<water::SpinLock> gsl(fPool.mutex); |
|
|
|
|
|
|
|
if (! fDoProcess) |
|
|
|
{ |
|
|
|
// carla_stderr("P: no process"); |
|
|
|
carla_zeroFloats(out1, frames); |
|
|
|
carla_zeroFloats(out2, frames); |
|
|
|
carla_zeroFloats(playCV, frames); |
|
|
|
fLastPosition = 0.0f; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const bool loopMode = fLoopMode; |
|
|
|
const float volume = fVolume; |
|
|
|
// const bool loopMode = fLoopMode; |
|
|
|
bool needsIdleRequest = false; |
|
|
|
bool playing; |
|
|
|
uint64_t frame; |
|
|
|
uint64_t framePos; |
|
|
|
|
|
|
|
if (fHostSync) |
|
|
|
{ |
|
|
|
const NativeTimeInfo* const timePos = getTimeInfo(); |
|
|
|
playing = fEnabled && timePos->playing; |
|
|
|
frame = timePos->frame; |
|
|
|
framePos = timePos->frame; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
playing = fEnabled; |
|
|
|
frame = fInternalTransportFrame; |
|
|
|
framePos = fInternalTransportFrame; |
|
|
|
|
|
|
|
if (playing) |
|
|
|
fInternalTransportFrame += frames; |
|
|
@@ -377,143 +385,161 @@ protected: |
|
|
|
// not playing |
|
|
|
if (! playing) |
|
|
|
{ |
|
|
|
// carla_stderr("P: not playing"); |
|
|
|
if (frame == 0 && fWasPlayingBefore) |
|
|
|
fReader.setNeedsRead(frame); |
|
|
|
// // carla_stderr("P: not playing"); |
|
|
|
// if (framePos == 0 && fWasPlayingBefore) |
|
|
|
// fReader.setNeedsRead(framePos); |
|
|
|
|
|
|
|
carla_zeroFloats(out1, frames); |
|
|
|
carla_zeroFloats(out2, frames); |
|
|
|
fWasPlayingBefore = false; |
|
|
|
carla_zeroFloats(playCV, frames); |
|
|
|
// fWasPlayingBefore = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fWasPlayingBefore = true; |
|
|
|
} |
|
|
|
|
|
|
|
// out of reach |
|
|
|
if ((frame < fPool.startFrame || frame >= fMaxFrame) && !loopMode) |
|
|
|
{ |
|
|
|
if (frame < fPool.startFrame) |
|
|
|
{ |
|
|
|
needsIdleRequest = true; |
|
|
|
fNeedsFileRead = true; |
|
|
|
fReader.setNeedsRead(frame); |
|
|
|
} |
|
|
|
|
|
|
|
carla_zeroFloats(out1, frames); |
|
|
|
carla_zeroFloats(out2, frames); |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
if (fInlineDisplay.writtenValues < 32) |
|
|
|
{ |
|
|
|
fInlineDisplay.lastValuesL[fInlineDisplay.writtenValues] = 0.0f; |
|
|
|
fInlineDisplay.lastValuesR[fInlineDisplay.writtenValues] = 0.0f; |
|
|
|
++fInlineDisplay.writtenValues; |
|
|
|
} |
|
|
|
if (fInlineDisplay.pending == InlineDisplayNotPending) |
|
|
|
{ |
|
|
|
needsIdleRequest = true; |
|
|
|
fInlineDisplay.pending = InlineDisplayNeedRequest; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
if (needsIdleRequest) |
|
|
|
hostRequestIdle(); |
|
|
|
|
|
|
|
if (frame == 0) |
|
|
|
fLastPosition = 0.0f; |
|
|
|
else if (frame >= fMaxFrame) |
|
|
|
fLastPosition = 100.0f; |
|
|
|
else |
|
|
|
fLastPosition = static_cast<float>(frame) / static_cast<float>(fMaxFrame) * 100.0f; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (fEntireFileLoaded) |
|
|
|
{ |
|
|
|
// NOTE: frame is always < fMaxFrame (or looping) |
|
|
|
uint32_t targetStartFrame = static_cast<uint32_t>(loopMode ? frame % fMaxFrame : frame); |
|
|
|
|
|
|
|
for (uint32_t framesDone=0, framesToDo=frames, remainingFrames; framesDone < frames;) |
|
|
|
{ |
|
|
|
if (targetStartFrame + framesToDo <= fMaxFrame) |
|
|
|
{ |
|
|
|
// everything fits together |
|
|
|
carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, framesToDo); |
|
|
|
carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, framesToDo); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
remainingFrames = std::min(fMaxFrame - targetStartFrame, framesToDo); |
|
|
|
carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, remainingFrames); |
|
|
|
carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, remainingFrames); |
|
|
|
framesDone += remainingFrames; |
|
|
|
framesToDo -= remainingFrames; |
|
|
|
|
|
|
|
if (! loopMode) |
|
|
|
{ |
|
|
|
// not looping, stop here |
|
|
|
if (framesToDo != 0) |
|
|
|
{ |
|
|
|
carla_zeroFloats(out1+framesDone, framesToDo); |
|
|
|
carla_zeroFloats(out2+framesDone, framesToDo); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// reset for next loop |
|
|
|
targetStartFrame = 0; |
|
|
|
} |
|
|
|
|
|
|
|
fLastPosition = static_cast<float>(targetStartFrame) / static_cast<float>(fMaxFrame) * 100.0f; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
const bool offline = isOffline(); |
|
|
|
|
|
|
|
if (! fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest)) |
|
|
|
{ |
|
|
|
carla_zeroFloats(out1, frames); |
|
|
|
carla_zeroFloats(out2, frames); |
|
|
|
} |
|
|
|
|
|
|
|
if (needsIdleRequest) |
|
|
|
{ |
|
|
|
fNeedsFileRead = true; |
|
|
|
// else |
|
|
|
// { |
|
|
|
// fWasPlayingBefore = true; |
|
|
|
// } |
|
|
|
|
|
|
|
fLastPosition = fReader.tickFrames(outBuffer, 0, frames, framePos, fLoopMode, isOffline()) * 100.f; |
|
|
|
|
|
|
|
// // out of reach |
|
|
|
// if ((frame < fPool.startFrame || frame >= fMaxFrame) && !loopMode) |
|
|
|
// { |
|
|
|
// if (frame < fPool.startFrame) |
|
|
|
// { |
|
|
|
// needsIdleRequest = true; |
|
|
|
// fNeedsFileRead = true; |
|
|
|
// fReader.setNeedsRead(frame); |
|
|
|
// } |
|
|
|
// |
|
|
|
// carla_zeroFloats(out1, frames); |
|
|
|
// carla_zeroFloats(out2, frames); |
|
|
|
// carla_zeroFloats(playCV, frames); |
|
|
|
// |
|
|
|
// #ifndef __MOD_DEVICES__ |
|
|
|
// if (fInlineDisplay.writtenValues < 32) |
|
|
|
// { |
|
|
|
// fInlineDisplay.lastValuesL[fInlineDisplay.writtenValues] = 0.0f; |
|
|
|
// fInlineDisplay.lastValuesR[fInlineDisplay.writtenValues] = 0.0f; |
|
|
|
// ++fInlineDisplay.writtenValues; |
|
|
|
// } |
|
|
|
// if (fInlineDisplay.pending == InlineDisplayNotPending) |
|
|
|
// { |
|
|
|
// needsIdleRequest = true; |
|
|
|
// fInlineDisplay.pending = InlineDisplayNeedRequest; |
|
|
|
// } |
|
|
|
// #endif |
|
|
|
|
|
|
|
// if (needsIdleRequest) |
|
|
|
// hostRequestIdle(); |
|
|
|
// |
|
|
|
// if (frame == 0) |
|
|
|
// fLastPosition = 0.0f; |
|
|
|
// else if (frame >= fMaxFrame) |
|
|
|
// fLastPosition = 100.0f; |
|
|
|
// else |
|
|
|
// fLastPosition = static_cast<float>(frame) / static_cast<float>(fMaxFrame) * 100.0f; |
|
|
|
// return; |
|
|
|
// } |
|
|
|
|
|
|
|
// if (fEntireFileLoaded) |
|
|
|
// { |
|
|
|
// // NOTE: frame is always < fMaxFrame (or looping) |
|
|
|
// uint32_t targetStartFrame = static_cast<uint32_t>(loopMode ? frame % fMaxFrame : frame); |
|
|
|
// |
|
|
|
// for (uint32_t framesDone=0, framesToDo=frames, remainingFrames; framesDone < frames;) |
|
|
|
// { |
|
|
|
// if (targetStartFrame + framesToDo <= fMaxFrame) |
|
|
|
// { |
|
|
|
// // everything fits together |
|
|
|
// carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, framesToDo); |
|
|
|
// carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, framesToDo); |
|
|
|
// carla_fillFloatsWithSingleValue(playCV+framesDone, 10.f, framesToDo); |
|
|
|
// break; |
|
|
|
// } |
|
|
|
// |
|
|
|
// remainingFrames = std::min(fMaxFrame - targetStartFrame, framesToDo); |
|
|
|
// carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, remainingFrames); |
|
|
|
// carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, remainingFrames); |
|
|
|
// carla_fillFloatsWithSingleValue(playCV+framesDone, 10.f, remainingFrames); |
|
|
|
// framesDone += remainingFrames; |
|
|
|
// framesToDo -= remainingFrames; |
|
|
|
// |
|
|
|
// if (! loopMode) |
|
|
|
// { |
|
|
|
// // not looping, stop here |
|
|
|
// if (framesToDo != 0) |
|
|
|
// { |
|
|
|
// carla_zeroFloats(out1+framesDone, framesToDo); |
|
|
|
// carla_zeroFloats(out2+framesDone, framesToDo); |
|
|
|
// carla_zeroFloats(playCV+framesDone, framesToDo); |
|
|
|
// } |
|
|
|
// break; |
|
|
|
// } |
|
|
|
// |
|
|
|
// // reset for next loop |
|
|
|
// targetStartFrame = 0; |
|
|
|
// } |
|
|
|
|
|
|
|
// fLastPosition = static_cast<float>(targetStartFrame) / static_cast<float>(fMaxFrame) * 100.0f; |
|
|
|
// } |
|
|
|
// else |
|
|
|
// { |
|
|
|
// const bool offline = isOffline(); |
|
|
|
|
|
|
|
// if (fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest)) |
|
|
|
// { |
|
|
|
// carla_fillFloatsWithSingleValue(playCV, 10.f, frames); |
|
|
|
// } |
|
|
|
// else |
|
|
|
// { |
|
|
|
// carla_zeroFloats(out1, frames); |
|
|
|
// carla_zeroFloats(out2, frames); |
|
|
|
// carla_zeroFloats(playCV, frames); |
|
|
|
// } |
|
|
|
// |
|
|
|
// if (needsIdleRequest) |
|
|
|
// { |
|
|
|
// fNeedsFileRead = true; |
|
|
|
// |
|
|
|
// if (isOffline()) |
|
|
|
// { |
|
|
|
// needsIdleRequest = false; |
|
|
|
// fReader.readPoll(); |
|
|
|
// |
|
|
|
// if (fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest)) |
|
|
|
// { |
|
|
|
// carla_fillFloatsWithSingleValue(playCV, 10.f, frames); |
|
|
|
// } |
|
|
|
// else |
|
|
|
// { |
|
|
|
// carla_zeroFloats(out1, frames); |
|
|
|
// carla_zeroFloats(out2, frames); |
|
|
|
// carla_zeroFloats(playCV, frames); |
|
|
|
// } |
|
|
|
// |
|
|
|
// if (needsIdleRequest) |
|
|
|
// fNeedsFileRead = true; |
|
|
|
// } |
|
|
|
// } |
|
|
|
// |
|
|
|
// const uint32_t modframe = static_cast<uint32_t>(frame % fMaxFrame); |
|
|
|
// fLastPosition = static_cast<float>(modframe) / static_cast<float>(fMaxFrame) * 100.0f; |
|
|
|
// |
|
|
|
// if (modframe > fPool.startFrame) |
|
|
|
// fLastPoolFill = static_cast<float>(modframe - fPool.startFrame) / static_cast<float>(fPool.numFrames) * 100.0f; |
|
|
|
// else |
|
|
|
// fLastPoolFill = 100.0f; |
|
|
|
// } |
|
|
|
|
|
|
|
if (isOffline()) |
|
|
|
{ |
|
|
|
needsIdleRequest = false; |
|
|
|
fReader.readPoll(); |
|
|
|
|
|
|
|
if (! fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest)) |
|
|
|
{ |
|
|
|
carla_zeroFloats(out1, frames); |
|
|
|
carla_zeroFloats(out2, frames); |
|
|
|
} |
|
|
|
|
|
|
|
if (needsIdleRequest) |
|
|
|
fNeedsFileRead = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const uint32_t modframe = static_cast<uint32_t>(frame % fMaxFrame); |
|
|
|
fLastPosition = static_cast<float>(modframe) / static_cast<float>(fMaxFrame) * 100.0f; |
|
|
|
|
|
|
|
if (modframe > fPool.startFrame) |
|
|
|
fLastPoolFill = static_cast<float>(modframe - fPool.startFrame) / static_cast<float>(fPool.numFrames) * 100.0f; |
|
|
|
else |
|
|
|
fLastPoolFill = 100.0f; |
|
|
|
} |
|
|
|
|
|
|
|
if (carla_isNotZero(volume-1.0f)) |
|
|
|
const float volume = fVolume; |
|
|
|
if (carla_isNotEqual(volume, 1.0f)) |
|
|
|
{ |
|
|
|
carla_multiply(out1, volume, frames); |
|
|
|
carla_multiply(out2, volume, frames); |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
if (fInlineDisplay.writtenValues < 32) |
|
|
|
{ |
|
|
|
fInlineDisplay.lastValuesL[fInlineDisplay.writtenValues] = carla_findMaxNormalizedFloat(out1, frames); |
|
|
@@ -525,13 +551,13 @@ protected: |
|
|
|
needsIdleRequest = true; |
|
|
|
fInlineDisplay.pending = InlineDisplayNeedRequest; |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
if (needsIdleRequest) |
|
|
|
hostRequestIdle(); |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------- |
|
|
|
// ---------------------------------------------------------------------------------------------------------------- |
|
|
|
// Plugin UI calls |
|
|
|
|
|
|
|
void uiShow(const bool show) override |
|
|
@@ -545,37 +571,38 @@ protected: |
|
|
|
uiClosed(); |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------- |
|
|
|
// Plugin state calls |
|
|
|
|
|
|
|
void setStateFromFile(const char* const filename) override |
|
|
|
{ |
|
|
|
loadFilename(filename); |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------- |
|
|
|
// ---------------------------------------------------------------------------------------------------------------- |
|
|
|
// Plugin dispatcher calls |
|
|
|
|
|
|
|
void idle() override |
|
|
|
{ |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
NativePluginWithMidiPrograms<FileAudio>::idle(); |
|
|
|
|
|
|
|
if (fNeedsFileRead) |
|
|
|
{ |
|
|
|
fReader.readPoll(); |
|
|
|
fNeedsFileRead = false; |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
if (fInlineDisplay.pending == InlineDisplayNeedRequest) |
|
|
|
{ |
|
|
|
fInlineDisplay.pending = InlineDisplayRequesting; |
|
|
|
hostQueueDrawInlineDisplay(); |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
// if (fNeedsFileRead) |
|
|
|
// { |
|
|
|
// fReader.readPoll(); |
|
|
|
// fNeedsFileRead = false; |
|
|
|
// } |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
void sampleRateChanged(double) override |
|
|
|
{ |
|
|
|
if (char* const filename = fFilename.releaseBufferPointer()) |
|
|
|
{ |
|
|
|
loadFilename(filename); |
|
|
|
std::free(filename); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
const NativeInlineDisplayImageSurface* renderInlineDisplay(const uint32_t rwidth, const uint32_t height) override |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(height > 4, nullptr); |
|
|
@@ -685,62 +712,46 @@ protected: |
|
|
|
fInlineDisplay.pending = InlineDisplayNotPending; |
|
|
|
return (NativeInlineDisplayImageSurface*)(NativeInlineDisplayImageSurfaceCompat*)&fInlineDisplay; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
void sampleRateChanged(double) override |
|
|
|
{ |
|
|
|
if (char* const filename = fFilename.releaseBufferPointer()) |
|
|
|
{ |
|
|
|
loadFilename(filename); |
|
|
|
std::free(filename); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// ------------------------------------------------------------------- |
|
|
|
// ---------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
private: |
|
|
|
bool fLoopMode; |
|
|
|
bool fHostSync; |
|
|
|
bool fEnabled; |
|
|
|
bool fDoProcess; |
|
|
|
bool fWasPlayingBefore; |
|
|
|
volatile bool fNeedsFileRead; |
|
|
|
|
|
|
|
bool fEntireFileLoaded; |
|
|
|
uint32_t fMaxFrame; |
|
|
|
uint32_t fInternalTransportFrame; |
|
|
|
float fLastPosition; |
|
|
|
float fLastPoolFill; |
|
|
|
float fVolume; |
|
|
|
|
|
|
|
AudioFilePool fPool; |
|
|
|
bool fLoopMode = true; |
|
|
|
#ifdef __MOD_DEVICES__ |
|
|
|
bool fHostSync = false; |
|
|
|
#else |
|
|
|
bool fHostSync = true; |
|
|
|
#endif |
|
|
|
bool fEnabled = true; |
|
|
|
bool fDoProcess = false; |
|
|
|
// bool fWasPlayingBefore; |
|
|
|
// volatile bool fNeedsFileRead; |
|
|
|
// |
|
|
|
// bool fEntireFileLoaded; |
|
|
|
// uint32_t fMaxFrame; |
|
|
|
uint32_t fInternalTransportFrame = 0; |
|
|
|
float fLastPosition = 0.f; |
|
|
|
// float fLastPoolFill; |
|
|
|
float fVolume = 1.f; |
|
|
|
|
|
|
|
// AudioFilePool fPool; |
|
|
|
AudioFileReader fReader; |
|
|
|
CarlaString fFilename; |
|
|
|
|
|
|
|
float fPreviewData[108] = {}; |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
NativeMidiPrograms fPrograms; |
|
|
|
float fPreviewData[108]; |
|
|
|
|
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
struct InlineDisplay : NativeInlineDisplayImageSurfaceCompat { |
|
|
|
float lastValuesL[32]; |
|
|
|
float lastValuesR[32]; |
|
|
|
volatile PendingInlineDisplay pending; |
|
|
|
volatile uint8_t writtenValues; |
|
|
|
float lastValuesL[32] = {}; |
|
|
|
float lastValuesR[32] = {}; |
|
|
|
volatile PendingInlineDisplay pending = InlineDisplayNotPending; |
|
|
|
volatile uint8_t writtenValues = 0; |
|
|
|
|
|
|
|
InlineDisplay() |
|
|
|
: NativeInlineDisplayImageSurfaceCompat(), |
|
|
|
# ifdef CARLA_PROPER_CPP11_SUPPORT |
|
|
|
lastValuesL{0.0f}, |
|
|
|
lastValuesR{0.0f}, |
|
|
|
# endif |
|
|
|
pending(InlineDisplayNotPending), |
|
|
|
writtenValues(0) |
|
|
|
{ |
|
|
|
# ifndef CARLA_PROPER_CPP11_SUPPORT |
|
|
|
carla_zeroFloats(lastValuesL, 32); |
|
|
|
carla_zeroFloats(lastValuesR, 32); |
|
|
|
# endif |
|
|
|
} |
|
|
|
: NativeInlineDisplayImageSurfaceCompat() {} |
|
|
|
|
|
|
|
~InlineDisplay() |
|
|
|
{ |
|
|
@@ -754,86 +765,78 @@ private: |
|
|
|
CARLA_DECLARE_NON_COPYABLE(InlineDisplay) |
|
|
|
CARLA_PREVENT_HEAP_ALLOCATION |
|
|
|
} fInlineDisplay; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
void loadFilename(const char* const filename) |
|
|
|
{ |
|
|
|
CARLA_ASSERT(filename != nullptr); |
|
|
|
carla_debug("AudioFilePlugin::loadFilename(\"%s\")", filename); |
|
|
|
carla_stdout("AudioFilePlugin::loadFilename(\"%s\")", filename); |
|
|
|
|
|
|
|
fDoProcess = false; |
|
|
|
fLastPoolFill = 0.0f; |
|
|
|
fInternalTransportFrame = 0; |
|
|
|
fPool.destroy(); |
|
|
|
// fLastPoolFill = 0.0f; |
|
|
|
// fPool.destroy(); |
|
|
|
fReader.destroy(); |
|
|
|
fFilename.clear(); |
|
|
|
|
|
|
|
if (filename == nullptr || *filename == '\0') |
|
|
|
{ |
|
|
|
fMaxFrame = 0; |
|
|
|
// fMaxFrame = 0; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const uint32_t previewDataSize = sizeof(fPreviewData)/sizeof(float); |
|
|
|
constexpr uint32_t kPreviewDataLen = sizeof(fPreviewData)/sizeof(float); |
|
|
|
|
|
|
|
if (fReader.loadFilename(filename, static_cast<uint32_t>(getSampleRate()), previewDataSize, fPreviewData)) |
|
|
|
if (fReader.loadFilename(filename, static_cast<uint32_t>(getSampleRate()), kPreviewDataLen, fPreviewData)) |
|
|
|
{ |
|
|
|
fEntireFileLoaded = fReader.isEntireFileLoaded(); |
|
|
|
fMaxFrame = fReader.getMaxFrame(); |
|
|
|
|
|
|
|
if (fEntireFileLoaded) |
|
|
|
{ |
|
|
|
fReader.putAndSwapAllData(fPool); |
|
|
|
fLastPoolFill = 100.0f; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fReader.createSwapablePool(fPool); |
|
|
|
fReader.readPoll(); |
|
|
|
} |
|
|
|
|
|
|
|
// fEntireFileLoaded = fReader.isEntireFileLoaded(); |
|
|
|
// fMaxFrame = fReader.getMaxFrame(); |
|
|
|
// |
|
|
|
// if (fEntireFileLoaded) |
|
|
|
// { |
|
|
|
// fReader.putAndSwapAllData(fPool); |
|
|
|
// fLastPoolFill = 100.0f; |
|
|
|
// } |
|
|
|
// else |
|
|
|
// { |
|
|
|
// fReader.createSwapablePool(fPool); |
|
|
|
// fReader.readPoll(); |
|
|
|
// } |
|
|
|
|
|
|
|
fInternalTransportFrame = 0; |
|
|
|
fDoProcess = true; |
|
|
|
fFilename = filename; |
|
|
|
hostSendPreviewBufferData('f', previewDataSize, fPreviewData); |
|
|
|
hostSendPreviewBufferData('f', kPreviewDataLen, fPreviewData); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fEntireFileLoaded = false; |
|
|
|
fMaxFrame = 0; |
|
|
|
// fEntireFileLoaded = false; |
|
|
|
// fMaxFrame = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
PluginClassEND(AudioFilePlugin) |
|
|
|
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioFilePlugin) |
|
|
|
}; |
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
static const char* _get_buffer_port_name(NativePluginHandle, const uint32_t index, const bool isOutput) |
|
|
|
{ |
|
|
|
if (!isOutput || index != 2) |
|
|
|
return nullptr; |
|
|
|
|
|
|
|
static const NativePluginDescriptor audiofileDesc = { |
|
|
|
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, |
|
|
|
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE |
|
|
|
|NATIVE_PLUGIN_HAS_UI |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
|NATIVE_PLUGIN_HAS_INLINE_DISPLAY |
|
|
|
#endif |
|
|
|
|NATIVE_PLUGIN_REQUESTS_IDLE |
|
|
|
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE |
|
|
|
|NATIVE_PLUGIN_USES_TIME), |
|
|
|
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, |
|
|
|
/* audioIns */ 0, |
|
|
|
/* audioOuts */ 2, |
|
|
|
/* midiIns */ 0, |
|
|
|
/* midiOuts */ 0, |
|
|
|
/* paramIns */ 1, |
|
|
|
/* paramOuts */ 0, |
|
|
|
/* name */ "Audio File", |
|
|
|
/* label */ "audiofile", |
|
|
|
/* maker */ "falkTX", |
|
|
|
/* copyright */ "GNU GPL v2+", |
|
|
|
PluginDescriptorFILL(AudioFilePlugin) |
|
|
|
return "Play status"; |
|
|
|
} |
|
|
|
|
|
|
|
static const NativePortRange* _get_buffer_port_range(NativePluginHandle, const uint32_t index, const bool isOutput) |
|
|
|
{ |
|
|
|
if (!isOutput || index != 2) |
|
|
|
return nullptr; |
|
|
|
|
|
|
|
static NativePortRange npr = { 0.f, 10.f }; |
|
|
|
return ⊀ |
|
|
|
} |
|
|
|
|
|
|
|
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioFilePlugin) |
|
|
|
}; |
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
CARLA_API_EXPORT |
|
|
|
void carla_register_native_plugin_audiofile(); |
|
|
@@ -841,7 +844,59 @@ void carla_register_native_plugin_audiofile(); |
|
|
|
CARLA_API_EXPORT |
|
|
|
void carla_register_native_plugin_audiofile() |
|
|
|
{ |
|
|
|
static const NativePluginDescriptor audiofileDesc = { |
|
|
|
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, |
|
|
|
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE |
|
|
|
#ifndef __MOD_DEVICES__ |
|
|
|
|NATIVE_PLUGIN_HAS_INLINE_DISPLAY |
|
|
|
#endif |
|
|
|
|NATIVE_PLUGIN_HAS_UI |
|
|
|
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE |
|
|
|
|NATIVE_PLUGIN_REQUESTS_IDLE |
|
|
|
|NATIVE_PLUGIN_USES_CONTROL_VOLTAGE |
|
|
|
|NATIVE_PLUGIN_USES_TIME), |
|
|
|
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, |
|
|
|
/* audioIns */ 0, |
|
|
|
/* audioOuts */ 2, |
|
|
|
/* midiIns */ 0, |
|
|
|
/* midiOuts */ 0, |
|
|
|
/* paramIns */ 1, |
|
|
|
/* paramOuts */ 0, |
|
|
|
/* name */ "Audio File", |
|
|
|
/* label */ "audiofile", |
|
|
|
/* maker */ "falkTX", |
|
|
|
/* copyright */ "GNU GPL v2+", |
|
|
|
AudioFilePlugin::_instantiate, |
|
|
|
AudioFilePlugin::_cleanup, |
|
|
|
AudioFilePlugin::_get_parameter_count, |
|
|
|
AudioFilePlugin::_get_parameter_info, |
|
|
|
AudioFilePlugin::_get_parameter_value, |
|
|
|
AudioFilePlugin::_get_midi_program_count, |
|
|
|
AudioFilePlugin::_get_midi_program_info, |
|
|
|
AudioFilePlugin::_set_parameter_value, |
|
|
|
AudioFilePlugin::_set_midi_program, |
|
|
|
AudioFilePlugin::_set_custom_data, |
|
|
|
AudioFilePlugin::_ui_show, |
|
|
|
AudioFilePlugin::_ui_idle, |
|
|
|
AudioFilePlugin::_ui_set_parameter_value, |
|
|
|
AudioFilePlugin::_ui_set_midi_program, |
|
|
|
AudioFilePlugin::_ui_set_custom_data, |
|
|
|
AudioFilePlugin::_activate, |
|
|
|
AudioFilePlugin::_deactivate, |
|
|
|
AudioFilePlugin::_process, |
|
|
|
AudioFilePlugin::_get_state, |
|
|
|
AudioFilePlugin::_set_state, |
|
|
|
AudioFilePlugin::_dispatcher, |
|
|
|
AudioFilePlugin::_render_inline_display, |
|
|
|
/* cvIns */ 0, |
|
|
|
/* cvOuts */ 1, |
|
|
|
AudioFilePlugin::_get_buffer_port_name, |
|
|
|
AudioFilePlugin::_get_buffer_port_range, |
|
|
|
/* ui_width */ 0, |
|
|
|
/* ui_height */ 0 |
|
|
|
}; |
|
|
|
|
|
|
|
carla_register_native_plugin(&audiofileDesc); |
|
|
|
} |
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |