Browse Source

Update zynaddsubfx

tags/1.9.7
falkTX 8 years ago
parent
commit
aac0860247
25 changed files with 446 additions and 75 deletions
  1. +1
    -0
      .gitignore
  2. +3
    -3
      source/native-plugins/Makefile
  3. +7
    -0
      source/native-plugins/zynaddsubfx-src.cpp
  4. +6
    -1
      source/native-plugins/zynaddsubfx-synth.cpp
  5. +138
    -34
      source/native-plugins/zynaddsubfx/Containers/NotePool.cpp
  6. +21
    -1
      source/native-plugins/zynaddsubfx/Containers/NotePool.h
  7. +13
    -0
      source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.cpp
  8. +18
    -0
      source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.h
  9. +14
    -1
      source/native-plugins/zynaddsubfx/Misc/Master.cpp
  10. +97
    -1
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp
  11. +13
    -0
      source/native-plugins/zynaddsubfx/Misc/MiddleWare.h
  12. +18
    -8
      source/native-plugins/zynaddsubfx/Misc/Part.cpp
  13. +0
    -3
      source/native-plugins/zynaddsubfx/Misc/Part.h
  14. +6
    -1
      source/native-plugins/zynaddsubfx/Synth/ADnote.cpp
  15. +3
    -1
      source/native-plugins/zynaddsubfx/Synth/ADnote.h
  16. +5
    -0
      source/native-plugins/zynaddsubfx/Synth/Envelope.cpp
  17. +2
    -0
      source/native-plugins/zynaddsubfx/Synth/Envelope.h
  18. +6
    -1
      source/native-plugins/zynaddsubfx/Synth/PADnote.cpp
  19. +3
    -1
      source/native-plugins/zynaddsubfx/Synth/PADnote.h
  20. +6
    -1
      source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp
  21. +2
    -1
      source/native-plugins/zynaddsubfx/Synth/SUBnote.h
  22. +4
    -1
      source/native-plugins/zynaddsubfx/Synth/SynthNote.h
  23. +34
    -2
      source/native-plugins/zynaddsubfx/UI/Connection.cpp
  24. +8
    -13
      source/native-plugins/zynaddsubfx/UI/MasterUI.fl
  25. +18
    -1
      source/native-plugins/zynaddsubfx/main.cpp

+ 1
- 0
.gitignore View File

@@ -108,6 +108,7 @@ data/windows/Carla-*-win64/
source/bridges/jackplugin/libjack.so.0
source/frontend/Makefile
source/tests/ansi-pedantic-test_*
source/tests/CachedPlugins
source/tests/CarlaRingBuffer
source/tests/CarlaPipeUtils
source/tests/CarlaString


+ 3
- 3
source/native-plugins/Makefile View File

@@ -331,17 +331,17 @@ $(OBJDIR)/zynaddsubfx-fx.cpp.o: zynaddsubfx-fx.cpp $(ZYN_UI_FILES_H)
$(OBJDIR)/zynaddsubfx-synth.cpp.o: zynaddsubfx-synth.cpp $(ZYN_UI_FILES_H)
-@mkdir -p $(OBJDIR)
@echo "Compiling $<"
@$(CXX) $< $(ZYN_CXX_FLAGS) -c -o $@
@$(CXX) $< $(ZYN_CXX_FLAGS) -Wno-unused-parameter -c -o $@

$(OBJDIR)/zynaddsubfx-src.cpp.o: zynaddsubfx-src.cpp $(ZYN_UI_FILES_H)
-@mkdir -p $(OBJDIR)
@echo "Compiling $<"
@$(CXX) $< $(ZYN_CXX_FLAGS) -Wno-unused-parameter -c -o $@
@$(CXX) $< $(ZYN_CXX_FLAGS) -Wno-unused-parameter -Wno-unused-variable -c -o $@

$(OBJDIR)/zynaddsubfx-ui.cpp.o: zynaddsubfx-ui.cpp $(ZYN_UI_FILES_H) $(ZYN_UI_FILES_CPP)
-@mkdir -p $(OBJDIR)
@echo "Compiling $<"
$(CXX) $< $(ZYN_CXX_FLAGS) -Wno-unused-parameter -Wno-unused-variable -c -o $@
@$(CXX) $< $(ZYN_CXX_FLAGS) -Wno-unused-parameter -Wno-unused-variable -c -o $@

# ----------------------------------------------------------------------------------------------------------------------------



+ 7
- 0
source/native-plugins/zynaddsubfx-src.cpp View File

@@ -220,6 +220,13 @@ extern "C" {
#undef rChangeCb
#define rChangeCb

#include "zynaddsubfx/Misc/CallbackRepeater.cpp"
#undef rObject
#undef rStdString
#undef rStdStringCb
#undef rChangeCb
#define rChangeCb

#include "zynaddsubfx/Misc/Config.cpp"
#undef rObject
#undef rStdString


+ 6
- 1
source/native-plugins/zynaddsubfx-synth.cpp View File

@@ -286,6 +286,7 @@ public:
fMiddleWare(nullptr),
fMaster(nullptr),
fSynth(),
fDefaultState(nullptr),
fMutex(),
fMiddleWareThread(new MiddleWareThread())
{
@@ -324,6 +325,8 @@ public:
_initMaster();
_setMasterParameters();

fMaster->getalldata(&fDefaultState);

fMiddleWareThread->start(fMiddleWare);
}

@@ -331,6 +334,7 @@ public:
{
fMiddleWareThread->stop();
_deleteMaster();
std::free(fDefaultState);
}

protected:
@@ -594,7 +598,7 @@ protected:
if (bank == 0)
{
// reset part to default
// TODO
setState(fDefaultState);
return;
}

@@ -828,6 +832,7 @@ private:
Master* fMaster;
SYNTH_T fSynth;
Config fConfig;
char* fDefaultState;

float fParameters[kParamCount];



+ 138
- 34
source/native-plugins/zynaddsubfx/Containers/NotePool.cpp View File

@@ -1,18 +1,69 @@
#include "NotePool.h"
//XXX eliminate dependence on Part.h
#include "../Misc/Part.h"
#include "../Misc/Allocator.h"
#include "../Synth/SynthNote.h"
#include <cstring>
#include <cassert>
#include <iostream>

#define SUSTAIN_BIT 0x04
#define NOTE_MASK 0x03

enum NoteStatus {
KEY_OFF = 0x00,
KEY_PLAYING = 0x01,
KEY_RELEASED_AND_SUSTAINED = 0x02,
KEY_RELEASED = 0x03
};


NotePool::NotePool(void)
:needs_cleaning(0)
{
memset(ndesc, 0, sizeof(ndesc));
memset(sdesc, 0, sizeof(sdesc));
}

bool NotePool::NoteDescriptor::playing(void) const
{
return (status&NOTE_MASK) == KEY_PLAYING;
}

bool NotePool::NoteDescriptor::sustained(void) const
{
return (status&NOTE_MASK) == KEY_RELEASED_AND_SUSTAINED;
}

bool NotePool::NoteDescriptor::released(void) const
{
return (status&NOTE_MASK) == KEY_RELEASED;
}

bool NotePool::NoteDescriptor::off(void) const
{
return (status&NOTE_MASK) == KEY_OFF;
}

void NotePool::NoteDescriptor::setStatus(uint8_t s)
{
status &= ~NOTE_MASK;
status |= (NOTE_MASK&s);
}

void NotePool::NoteDescriptor::doSustain(void)
{
setStatus(KEY_RELEASED_AND_SUSTAINED);
}

bool NotePool::NoteDescriptor::canSustain(void) const
{
return !(status & SUSTAIN_BIT);
}

void NotePool::NoteDescriptor::makeUnsustainable(void)
{
status |= SUSTAIN_BIT;
}

NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n)
{
const int off_d1 = &n-ndesc;
@@ -35,18 +86,18 @@ static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato,
{
int desc_id = 0;
for(int i=0; i<POLYPHONY; ++i, ++desc_id)
if(ndesc[desc_id].status == Part::KEY_OFF)
if(ndesc[desc_id].off())
break;

if(desc_id != 0) {
auto &nd = ndesc[desc_id-1];
if(nd.age == 0 && nd.note == note && nd.sendto == sendto
&& nd.status == Part::KEY_PLAYING && nd.legatoMirror == legato)
&& nd.playing() && nd.legatoMirror == legato && nd.canSustain())
return desc_id-1;
}

//Out of free descriptors
if(desc_id >= POLYPHONY || ndesc[desc_id].status != Part::KEY_OFF) {
if(desc_id >= POLYPHONY || !ndesc[desc_id].off()) {
return -1;
}

@@ -65,6 +116,28 @@ NotePool::constActiveDescIter NotePool::activeDesc(void) const
return constActiveDescIter{*this};
}

int NotePool::usedNoteDesc(void) const
{
if(needs_cleaning)
const_cast<NotePool*>(this)->cleanup();

int cnt = 0;
for(int i=0; i<POLYPHONY; ++i)
cnt += (ndesc[i].size != 0);
return cnt;
}

int NotePool::usedSynthDesc(void) const
{
if(needs_cleaning)
const_cast<NotePool*>(this)->cleanup();

int cnt = 0;
for(int i=0; i<POLYPHONY*EXPECTED_USAGE; ++i)
cnt += (bool)sdesc[i].note;
return cnt;
}

void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato)
{
//Get first free note descriptor
@@ -74,7 +147,7 @@ void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bo
ndesc[desc_id].note = note;
ndesc[desc_id].sendto = sendto;
ndesc[desc_id].size += 1;
ndesc[desc_id].status = Part::KEY_PLAYING;
ndesc[desc_id].status = KEY_PLAYING;
ndesc[desc_id].legatoMirror = legato;

//Get first free synth descriptor
@@ -90,7 +163,7 @@ void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bo
void NotePool::upgradeToLegato(void)
{
for(auto &d:activeDesc())
if(d.status == Part::KEY_PLAYING)
if(d.playing())
for(auto &s:activeNotes(d))
insertLegatoNote(d.note, d.sendto, s);
}
@@ -118,12 +191,23 @@ void NotePool::applyLegato(LegatoParams &par)
std::cerr << "failed to create legato note: " << ba.what() << std::endl;
}
}
};
}

void NotePool::makeUnsustainable(uint8_t note)
{
for(auto &desc:activeDesc()) {
if(desc.note == note) {
desc.makeUnsustainable();
if(desc.sustained())
release(desc);
}
}
}

bool NotePool::full(void) const
{
for(int i=0; i<POLYPHONY; ++i)
if(ndesc[i].status == Part::KEY_OFF)
if(ndesc[i].off())
return false;
return true;
}
@@ -149,8 +233,7 @@ int NotePool::getRunningNotes(void) const
bool running[256] = {0};
for(auto &desc:activeDesc()) {
//printf("note!(%d)\n", desc.note);
if(desc.status == Part::KEY_PLAYING ||
desc.status == Part::KEY_RELEASED_AND_SUSTAINED)
if(desc.playing() || desc.sustained())
running[desc.note] = true;
}

@@ -160,30 +243,44 @@ int NotePool::getRunningNotes(void) const

return running_count;
}
int NotePool::enforceKeyLimit(int limit) const
{
//{
//int oldestnotepos = -1;
//if(notecount > keylimit) //find out the oldest note
// for(int i = 0; i < POLYPHONY; ++i) {
// int maxtime = 0;
// if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) {
// maxtime = partnote[i].time;
// oldestnotepos = i;
// }
// }
//if(oldestnotepos != -1)
// ReleaseNotePos(oldestnotepos);
//}
//printf("Unimplemented enforceKeyLimit()\n");
return -1;
void NotePool::enforceKeyLimit(int limit)
{
int notes_to_kill = getRunningNotes() - limit;
if(notes_to_kill <= 0)
return;

NoteDescriptor *to_kill = NULL;
unsigned oldest = 0;
for(auto &nd : activeDesc()) {
if(to_kill == NULL) {
//There must be something to kill
oldest = nd.age;
to_kill = &nd;
} else if(to_kill->released() && nd.playing()) {
//Prefer to kill off a running note
oldest = nd.age;
to_kill = &nd;
} else if(nd.age > oldest && !(to_kill->playing() && nd.released())) {
//Get an older note when it doesn't move from running to released
oldest = nd.age;
to_kill = &nd;
}
}

if(to_kill) {
auto &tk = *to_kill;
if(tk.released() || tk.sustained())
kill(*to_kill);
else
entomb(*to_kill);
}
}

void NotePool::releasePlayingNotes(void)
{
for(auto &d:activeDesc()) {
if(d.status == Part::KEY_PLAYING) {
d.status = Part::KEY_RELEASED;
if(d.playing()) {
d.setStatus(KEY_RELEASED);
for(auto s:activeNotes(d))
s.note->releasekey();
}
@@ -192,7 +289,7 @@ void NotePool::releasePlayingNotes(void)

void NotePool::release(NoteDescriptor &d)
{
d.status = Part::KEY_RELEASED;
d.setStatus(KEY_RELEASED);
for(auto s:activeNotes(d))
s.note->releasekey();
}
@@ -213,7 +310,7 @@ void NotePool::killNote(uint8_t note)

void NotePool::kill(NoteDescriptor &d)
{
d.status = Part::KEY_OFF;
d.setStatus(KEY_OFF);
for(auto &s:activeNotes(d))
kill(s);
}
@@ -225,6 +322,13 @@ void NotePool::kill(SynthDescriptor &s)
needs_cleaning = true;
}

void NotePool::entomb(NoteDescriptor &d)
{
d.setStatus(KEY_RELEASED);
for(auto &s:activeNotes(d))
s.note->entomb();
}

const char *getStatus(int status_bits)
{
switch(status_bits)
@@ -252,7 +356,7 @@ void NotePool::cleanup(void)

int last_valid_desc = 0;
for(int i=0; i<POLYPHONY; ++i)
if(ndesc[i].status != Part::KEY_OFF)
if(!ndesc[i].off())
last_valid_desc = i;

//Find the real numbers of allocated notes
@@ -275,7 +379,7 @@ void NotePool::cleanup(void)
if(new_length[i] != 0)
ndesc[cum_new++] = ndesc[i];
else
ndesc[i].status = Part::KEY_OFF;
ndesc[i].setStatus(KEY_OFF);
}
memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new));
}


+ 21
- 1
source/native-plugins/zynaddsubfx/Containers/NotePool.h View File

@@ -24,6 +24,19 @@ class NotePool
uint8_t status;
bool legatoMirror;
bool operator==(NoteDescriptor);

//status checks
bool playing(void) const;
bool off(void) const;
bool sustained(void) const;
bool released(void) const;

//status transitions
void setStatus(uint8_t s);
void doSustain(void);

bool canSustain(void) const;
void makeUnsustainable(void);
};

//To be pedantic this wastes 2 or 6 bytes per descriptor
@@ -84,6 +97,10 @@ class NotePool
activeDescIter activeDesc(void);
constActiveDescIter activeDesc(void) const;

//Counts of descriptors used for tests
int usedNoteDesc(void) const;
int usedSynthDesc(void) const;

NotePool(void);

//Operations
@@ -93,13 +110,15 @@ class NotePool
void upgradeToLegato(void);
void applyLegato(LegatoParams &par);

void makeUnsustainable(uint8_t note);

bool full(void) const;
bool synthFull(int sdesc_count) const;

//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
bool existsRunningNote(void) const;
int getRunningNotes(void) const;
int enforceKeyLimit(int limit) const;
void enforceKeyLimit(int limit);

void releasePlayingNotes(void);
void releaseNote(note_t note);
@@ -109,6 +128,7 @@ class NotePool
void killNote(note_t note);
void kill(NoteDescriptor &d);
void kill(SynthDescriptor &s);
void entomb(NoteDescriptor &d);

void cleanup(void);



+ 13
- 0
source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.cpp View File

@@ -0,0 +1,13 @@
#include "CallbackRepeater.h"
CallbackRepeater::CallbackRepeater(int interval, cb_t cb_)
:last(time(0)), dt(interval), cb(cb_)
{}

void CallbackRepeater::tick(void)
{
auto now = time(0);
if(now-last > dt && dt >= 0) {
cb();
last = now;
}
}

+ 18
- 0
source/native-plugins/zynaddsubfx/Misc/CallbackRepeater.h View File

@@ -0,0 +1,18 @@
#pragma once
#include <functional>
#include <ctime>

struct CallbackRepeater
{
typedef std::function<void(void)> cb_t ;

//Call interval in seconds and callback
CallbackRepeater(int interval, cb_t cb_);

//Time Check
void tick(void);

std::time_t last;
std::time_t dt;
cb_t cb;
};

+ 14
- 1
source/native-plugins/zynaddsubfx/Misc/Master.cpp View File

@@ -237,6 +237,19 @@ static const Ports master_ports = {
SNIP
preset_ports.dispatch(msg, data);
rBOIL_END},
{"HDDRecorder/preparefile:s", rDoc("Init WAV file"), 0, [](const char *msg, RtData &d) {
Master *m = (Master*)d.obj;
m->HDDRecorder.preparefile(rtosc_argument(msg, 0).s, 1);}},
{"HDDRecorder/start:", rDoc("Start recording"), 0, [](const char *, RtData &d) {
Master *m = (Master*)d.obj;
m->HDDRecorder.start();}},
{"HDDRecorder/stop:", rDoc("Stop recording"), 0, [](const char *, RtData &d) {
Master *m = (Master*)d.obj;
m->HDDRecorder.stop();}},
{"HDDRecorder/pause:", rDoc("Pause recording"), 0, [](const char *, RtData &d) {
Master *m = (Master*)d.obj;
m->HDDRecorder.pause();}},

};
const Ports &Master::ports = master_ports;

@@ -618,7 +631,7 @@ int msg_id=0;
/*
* Master audio out (the final sound)
*/
bool Master::AudioOut(float *outl, float *outr)
bool Master::AudioOut(float *outr, float *outl)
{
//Danger Limits
if(memory->lowMemory(2,1024*1024))


+ 97
- 1
source/native-plugins/zynaddsubfx/Misc/MiddleWare.cpp View File

@@ -5,6 +5,7 @@
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <dirent.h>

#include <rtosc/undo-history.h>
#include <rtosc/thread-link.h>
@@ -19,6 +20,7 @@
#include <map>

#include "Util.h"
#include "CallbackRepeater.h"
#include "Master.h"
#include "Part.h"
#include "PresetExtractor.h"
@@ -576,14 +578,18 @@ public:
{
if(server)
while(lo_server_recv_noblock(server, 0));

while(bToU->hasNext()) {
const char *rtmsg = bToU->read();
bToUhandle(rtmsg);
}

while(auto *m = multi_thread_source.read()) {
handleMsg(m->memory);
multi_thread_source.free(m);
}

autoSave.tick();
}


@@ -659,6 +665,8 @@ public:
const SYNTH_T synth;

PresetsStore presetsstore;

CallbackRepeater autoSave;
};

/*****************************************************************************
@@ -965,6 +973,25 @@ static rtosc::Ports middwareSnoopPorts = {
const char *file = rtosc_argument(msg,1).s;
impl.savePart(part_id, file);
rEnd},
{"reload_auto_save:i", 0, 0,
rBegin
const int save_id = rtosc_argument(msg,0).i;
const string save_dir = string(getenv("HOME")) + "/.local";
const string save_file = "zynaddsubfx-"+to_s(save_id)+"-autosave.xmz";
const string save_loc = save_dir + "/" + save_file;
impl.loadMaster(save_loc.c_str());
//XXX it would be better to remove the autosave after there is a new
//autosave, but this method should work for non-immediate crashes :-|
remove(save_loc.c_str());
rEnd},
{"delete_auto_save:i", 0, 0,
rBegin
const int save_id = rtosc_argument(msg,0).i;
const string save_dir = string(getenv("HOME")) + "/.local";
const string save_file = "zynaddsubfx-"+to_s(save_id)+"-autosave.xmz";
const string save_loc = save_dir + "/" + save_file;
remove(save_loc.c_str());
rEnd},
{"load_xmz:s", 0, 0,
rBegin;
const char *file = rtosc_argument(msg, 0).s;
@@ -1100,7 +1127,14 @@ static rtosc::Ports middlewareReplyPorts = {
MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_,
Config* config, int preferrred_port)
:parent(mw), config(config), ui(nullptr), synth(std::move(synth_)),
presetsstore(*config)
presetsstore(*config), autoSave(-1, [this]() {
auto master = this->master;
this->doReadOnlyOp([master](){
std::string home = getenv("HOME");
std::string save_file = home+"/.local/zynaddsubfx-"+to_s(getpid())+"-autosave.xmz";
printf("doing an autosave <%s>...\n", save_file.c_str());
int res = master->saveXML(save_file.c_str());
(void)res;});})
{
bToU = new rtosc::ThreadLink(4096*2,1024);
uToB = new rtosc::ThreadLink(4096*2,1024);
@@ -1425,24 +1459,86 @@ MiddleWare::MiddleWare(SYNTH_T synth, Config* config,
int preferred_port)
:impl(new MiddleWareImpl(this, std::move(synth), config, preferred_port))
{}

MiddleWare::~MiddleWare(void)
{
delete impl;
}

void MiddleWare::updateResources(Master *m)
{
impl->updateResources(m);
}

Master *MiddleWare::spawnMaster(void)
{
assert(impl->master);
assert(impl->master->uToB);
return impl->master;
}

void MiddleWare::enableAutoSave(int interval_sec)
{
impl->autoSave.dt = interval_sec;
}

int MiddleWare::checkAutoSave(void)
{
//save spec zynaddsubfx-PID-autosave.xmz
const std::string home = getenv("HOME");
const std::string save_dir = home+"/.local/";

DIR *dir = opendir(save_dir.c_str());

if(dir == NULL)
return -1;

struct dirent *fn;
int reload_save = -1;

while((fn = readdir(dir))) {
const char *filename = fn->d_name;
const char *prefix = "zynaddsubfx-";

//check for manditory prefix
if(strstr(filename, prefix) != filename)
continue;

int id = atoi(filename+strlen(prefix));

bool in_use = false;

std::string proc_file = "/proc/" + to_s(id) + "/comm";
std::ifstream ifs(proc_file);
if(ifs.good()) {
std::string comm_name;
ifs >> comm_name;
in_use = (comm_name == "zynaddsubfx");
}

if(!in_use) {
reload_save = id;
break;
}
}

closedir(dir);

return reload_save;
}

void MiddleWare::removeAutoSave(void)
{
std::string home = getenv("HOME");
std::string save_file = home+"/.local/zynaddsubfx-"+to_s(getpid())+"-autosave.xmz";
remove(save_file.c_str());
}

Fl_Osc_Interface *MiddleWare::spawnUiApi(void)
{
return impl->osc;
}

void MiddleWare::tick(void)
{
impl->tick();


+ 13
- 0
source/native-plugins/zynaddsubfx/Misc/MiddleWare.h View File

@@ -17,6 +17,18 @@ class MiddleWare
void updateResources(Master *m);
//returns internal master pointer
class Master *spawnMaster(void);

//Enable AutoSave Functionality
void enableAutoSave(int interval_sec=60);

//Check for old automatic saves which should only exist if multiple
//instances are in use OR when there was a crash
//
//When an old save is found return the id of the save file
int checkAutoSave(void);

void removeAutoSave(void);

//return UI interface
class Fl_Osc_Interface *spawnUiApi(void);
//Set callback to push UI events to
@@ -40,6 +52,7 @@ class MiddleWare
//Indicate that a bank will be loaded
//NOTE: Can only be called by realtime thread
void pendingSetBank(int bank);

//Indicate that a program will be loaded on a known part
//NOTE: Can only be called by realtime thread
void pendingSetProgram(int part, int program);


+ 18
- 8
source/native-plugins/zynaddsubfx/Misc/Part.cpp View File

@@ -312,7 +312,7 @@ void Part::defaultsinstrument()
Pdrummode = 0;

for(int n = 0; n < NUM_KIT_ITEMS; ++n) {
kit[n].Penabled = false;
//kit[n].Penabled = false;
kit[n].Pmuted = false;
kit[n].Pminkey = 0;
kit[n].Pmaxkey = 127;
@@ -475,6 +475,9 @@ bool Part::NoteOn(unsigned char note,
return true;
}

if(Ppolymode)
notePool.makeUnsustainable(note);

//Create New Notes
for(uint8_t i = 0; i < NUM_KIT_ITEMS; ++i) {
auto &item = kit[i];
@@ -522,7 +525,7 @@ void Part::NoteOff(unsigned char note) //release the key
monomemPop(note);

for(auto &desc:notePool.activeDesc()) {
if(desc.note != note || desc.status != KEY_PLAYING)
if(desc.note != note || !desc.playing())
continue;
if(!ctl.sustain.sustain) { //the sustain pedal is not pushed
if((isMonoMode() || isLegatoMode()) && !monomemEmpty())
@@ -530,8 +533,12 @@ void Part::NoteOff(unsigned char note) //release the key
else
notePool.release(desc);
}
else //the sustain pedal is pushed
desc.status = KEY_RELEASED_AND_SUSTAINED;
else { //the sustain pedal is pushed
if(desc.canSustain())
desc.doSustain();
else
notePool.release(desc);
}
}
}

@@ -550,7 +557,7 @@ void Part::PolyphonicAftertouch(unsigned char note,

const float vel = getVelocity(velocity, Pvelsns, Pveloffs);
for(auto &d:notePool.activeDesc()) {
if(d.note == note && d.status == KEY_PLAYING)
if(d.note == note && d.playing())
for(auto &s:notePool.activeNotes(d))
s.note->setVelocity(vel);
}
@@ -659,7 +666,7 @@ void Part::ReleaseSustainedKeys()
MonoMemRenote(); // To play most recent still held note.

for(auto &d:notePool.activeDesc())
if(d.status == KEY_RELEASED_AND_SUSTAINED)
if(d.sustained())
for(auto &s:notePool.activeNotes(d))
s.note->releasekey();
}
@@ -671,7 +678,7 @@ void Part::ReleaseSustainedKeys()
void Part::ReleaseAllKeys()
{
for(auto &d:notePool.activeDesc())
if(d.status != KEY_RELEASED)
if(!d.released())
for(auto &s:notePool.activeNotes(d))
s.note->releasekey();
}
@@ -726,7 +733,7 @@ void Part::setkeylimit(unsigned char Pkeylimit_)
if(keylimit == 0)
keylimit = POLYPHONY - 5;

if(notePool.getRunningNotes() > keylimit)
if(notePool.getRunningNotes() >= keylimit)
notePool.enforceKeyLimit(keylimit);
}

@@ -840,6 +847,9 @@ void Part::setkititemstatus(unsigned kititem, bool Penabled_)
delete kkit.adpars;
delete kkit.subpars;
delete kkit.padpars;
kkit.adpars = nullptr;
kkit.subpars = nullptr;
kkit.padpars = nullptr;
kkit.Pname[0] = '\0';

notePool.killAllNotes();


+ 0
- 3
source/native-plugins/zynaddsubfx/Misc/Part.h View File

@@ -147,9 +147,6 @@ class Part
float *partfxinputl[NUM_PART_EFX + 1], //Left and right signal that pass thru part effects;
*partfxinputr[NUM_PART_EFX + 1]; //partfxinput l/r [NUM_PART_EFX] is for "no effect" buffer

enum NoteStatus {
KEY_OFF, KEY_PLAYING, KEY_RELEASED_AND_SUSTAINED, KEY_RELEASED
};

float volume, oldvolumel, oldvolumer; //this is applied by Master
float panning; //this is applied by Master, too


+ 6
- 1
source/native-plugins/zynaddsubfx/Synth/ADnote.cpp View File

@@ -1845,7 +1845,7 @@ void ADnote::releasekey()
/*
* Check if the note is finished
*/
int ADnote::finished() const
bool ADnote::finished() const
{
if(NoteEnabled == ON)
return 0;
@@ -1853,6 +1853,11 @@ int ADnote::finished() const
return 1;
}

void ADnote::entomb(void)
{
NoteGlobalPar.AmpEnvelope->forceFinish();
}

void ADnote::Voice::releasekey()
{
if(!Enabled)


+ 3
- 1
source/native-plugins/zynaddsubfx/Synth/ADnote.h View File

@@ -52,7 +52,9 @@ class ADnote:public SynthNote

int noteout(float *outl, float *outr);
void releasekey();
int finished() const;
bool finished() const;
void entomb(void);


virtual SynthNote *cloneLegato(void) override;
private:


+ 5
- 0
source/native-plugins/zynaddsubfx/Synth/Envelope.cpp View File

@@ -101,6 +101,11 @@ void Envelope::releasekey()
t = 0.0f;
}

void Envelope::forceFinish(void)
{
envfinish = true;
}

/*
* Envelope Output
*/


+ 2
- 0
source/native-plugins/zynaddsubfx/Synth/Envelope.h View File

@@ -35,6 +35,8 @@ class Envelope
/**Destructor*/
~Envelope();
void releasekey();
/**Push Envelope to finishing state*/
void forceFinish(void);
float envout();
float envout_dB();
/**Determines the status of the Envelope


+ 6
- 1
source/native-plugins/zynaddsubfx/Synth/PADnote.cpp View File

@@ -428,11 +428,16 @@ int PADnote::noteout(float *outl, float *outr)
return 1;
}

int PADnote::finished() const
bool PADnote::finished() const
{
return finished_;
}

void PADnote::entomb(void)
{
NoteGlobalPar.AmpEnvelope->forceFinish();
}

void PADnote::releasekey()
{
NoteGlobalPar.FreqEnvelope->releasekey();


+ 3
- 1
source/native-plugins/zynaddsubfx/Synth/PADnote.h View File

@@ -38,7 +38,9 @@ class PADnote:public SynthNote
void legatonote(LegatoParams pars);

int noteout(float *outl, float *outr);
int finished() const;
bool finished() const;
void entomb(void);

void releasekey();
private:
void setup(float freq, float velocity, int portamento_,


+ 6
- 1
source/native-plugins/zynaddsubfx/Synth/SUBnote.cpp View File

@@ -619,10 +619,15 @@ void SUBnote::releasekey()
/*
* Check if the note is finished
*/
int SUBnote::finished() const
bool SUBnote::finished() const
{
if(NoteEnabled == OFF)
return 1;
else
return 0;
}

void SUBnote::entomb(void)
{
AmpEnvelope->forceFinish();
}

+ 2
- 1
source/native-plugins/zynaddsubfx/Synth/SUBnote.h View File

@@ -38,7 +38,8 @@ class SUBnote:public SynthNote

int noteout(float *outl, float *outr); //note output,return 0 if the note is finished
void releasekey();
int finished() const;
bool finished() const;
void entomb(void);
private:

void setup(float freq,


+ 4
- 1
source/native-plugins/zynaddsubfx/Synth/SynthNote.h View File

@@ -63,7 +63,10 @@ class SynthNote

/**Return if note is finished.
* @return finished=1 unfinished=0*/
virtual int finished() const = 0;
virtual bool finished() const = 0;

/**Make a note die off next buffer compute*/
virtual void entomb(void) = 0;

virtual void legatonote(LegatoParams pars) = 0;



+ 34
- 2
source/native-plugins/zynaddsubfx/UI/Connection.cpp View File

@@ -134,7 +134,7 @@ void GUI::destroyUi(ui_handle_t ui)
delete static_cast<MasterUI*>(ui);
}

#define BEGIN(x) {x,":non-realtime\0",NULL,[](const char *m, rtosc::RtData d){ \
#define BEGIN(x) {x,":non-realtime\0",NULL,[](const char *m, rtosc::RtData &d){ \
MasterUI *ui = static_cast<MasterUI*>(d.obj); \
rtosc_arg_t a0 = {0}, a1 = {0}; \
if(rtosc_narguments(m) > 0) \
@@ -157,6 +157,18 @@ rtosc::Ports uiPorts::ports = {
BEGIN("alert:s") {
fl_alert("%s",a0.s);
} END
BEGIN("alert-reload:i") {
int res = fl_choice("Old autosave found, do you want to reload?",
"Delete", "Reload", "Ignore");
// 0 1 2
if(1==res) {
d.reply("/reload_auto_save", "i", a0.i);
ui->refresh_master_ui();
ui->updatepanel();
} else if(0==res) {
d.reply("/delete_auto_save", "i", a0.i);
}
} END
BEGIN("session-type:s") {
if(strcmp(a0.s,"LASH"))
return;
@@ -188,6 +200,26 @@ rtosc::Ports uiPorts::ports = {
} END
};

//very tiny rtdata ext
class RtDataUI: public rtosc::RtData {
public:

RtDataUI(Fl_Osc_Interface *osc_)
:osc(osc_)
{}

void reply(const char *path, const char *args, ...) override
{
va_list va;
va_start(va,args);
char buf[2048];
rtosc_vmessage(buf,sizeof(buf),path,args,va);
osc->writeRaw(buf);
va_end(va);
}

Fl_Osc_Interface *osc;
};

void GUI::raiseUi(ui_handle_t gui, const char *message)
{
@@ -209,7 +241,7 @@ void GUI::raiseUi(ui_handle_t gui, const char *message)
//printf("got message for UI '%s'\n", message);
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
rtosc::RtData d;
RtDataUI d(mui->osc);
d.loc = buffer;
d.loc_size = 1024;
d.obj = gui;


+ 8
- 13
source/native-plugins/zynaddsubfx/UI/MasterUI.fl View File

@@ -178,18 +178,13 @@ bankui->show();}
}
Fl_Check_Button partenabled {
label 01
callback {o->oscWrite("Penabled", o->value() ? "T" : "F");
if ((int) o->value()==0) panellistitemgroup->deactivate();
else {
panellistitemgroup->activate();
/*
if ((int)bankui->cbwig->value()!=(npart+1)){
bankui->cbwig->value(npart+1);
bankui->cbwig->do_callback();
};*/
};
callback {
if ((int) o->value()==0) panellistitemgroup->deactivate();
else {
panellistitemgroup->activate();
};

o->redraw();}
o->redraw();}
private xywh {5 0 45 20} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 24
code0 {char tmp[10];snprintf(tmp,10,"%d",npart+1);o->copy_label(tmp);}
code1 {o->init("Penabled");}
@@ -472,7 +467,7 @@ fl_filename_setext(filename,".wav");

//TODO TODO Test if a file exists
if (fl_choice("The file *might* exist. \\nOverwrite it?","No","Yes",NULL)) {
osc->write("/HDDRecorder/preparefile", "T");
osc->write("/HDDRecorder/preparefile", "s", filename);
recordbutton->activate();//TODO make this button osc controlled
}

@@ -765,7 +760,7 @@ stopbutton->activate();
pausebutton->activate();
pauselabel->activate();
o->oscWrite("HDDRecorder/start");
o->oscWrite("resetvu");
o->oscWrite("reset-vu");
mastermenu->redraw();}
tooltip {Start Recording} xywh {159 46 21 21} box ROUND_UP_BOX color 88 labelfont 1 labelsize 10 align 2 deactivate
class Fl_Osc_Button


+ 18
- 1
source/native-plugins/zynaddsubfx/main.cpp View File

@@ -109,6 +109,7 @@ void exitprogram(const Config& config)
{
Nio::stop();
config.save();
middleware->removeAutoSave();

GUI::destroyUi(gui);
delete middleware;
@@ -193,6 +194,9 @@ int main(int argc, char *argv[])
{
"auto-connect", 0, NULL, 'a'
},
{
"auto-save", 0, NULL, 'A'
},
{
"pid-in-client-name", 0, NULL, 'p'
},
@@ -221,6 +225,7 @@ int main(int argc, char *argv[])
opterr = 0;
int option_index = 0, opt, exitwithhelp = 0, exitwithversion = 0;
int prefered_port = -1;
int auto_save_interval = 60;

string loadfile, loadinstrument, execAfterInit, ui_title;

@@ -230,7 +235,7 @@ int main(int argc, char *argv[])
/**\todo check this process for a small memory leak*/
opt = getopt_long(argc,
argv,
"l:L:r:b:o:I:O:N:e:P:u:hvapSDUY",
"l:L:r:b:o:I:O:N:e:P:A:u:hvapSDUY",
opts,
&option_index);
char *optarguments = optarg;
@@ -321,6 +326,10 @@ int main(int argc, char *argv[])
if(optarguments)
prefered_port = atoi(optarguments);
break;
case 'A':
if(optarguments)
auto_save_interval = atoi(optarguments);
break;
case 'e':
GETOP(execAfterInit);
break;
@@ -370,6 +379,7 @@ int main(int argc, char *argv[])
" -U , --no-gui\t\t\t\t Run ZynAddSubFX without user interface\n"
<< " -N , --named\t\t\t\t Postfix IO Name when possible\n"
<< " -a , --auto-connect\t\t\t AutoConnect when using JACK\n"
<< " -A , --auto-save=INTERVAL\t\t Automatically save at interval (disabled for negative intervals)\n"
<< " -p , --pid-in-client-name\t\t Append PID to (JACK) "
"client name\n"
<< " -P , --preferred-port\t\t\t Preferred OSC Port\n"
@@ -476,6 +486,13 @@ int main(int argc, char *argv[])
"Default IO did not initialize.\nDefaulting to NULL backend.");
}

if(auto_save_interval >= 0) {
int old_save = middleware->checkAutoSave();
if(old_save > 0)
GUI::raiseUi(gui, "/alert-reload", "i", old_save);
middleware->enableAutoSave(auto_save_interval);
}

#if USE_NSM
char *nsm_url = getenv("NSM_URL");



Loading…
Cancel
Save