zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

WatchPoint.cpp (9085B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   WatchPoint.cpp - Synthesis State Watcher
      5   Copyright (C) 2015-2015 Mark McCurry
      6 
      7   This program is free software; you can redistribute it and/or modify
      8   it under the terms of version 2 of the GNU General Public License
      9   as published by the Free Software Foundation.
     10 
     11   This program is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14   GNU General Public License (version 2 or later) for more details.
     15 
     16   You should have received a copy of the GNU General Public License (version 2)
     17   along with this program; if not, write to the Free Software Foundation,
     18   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     19 
     20 */
     21 
     22 #include "WatchPoint.h"
     23 #include "../Misc/Util.h"
     24 #include <cstring>
     25 #include <rtosc/thread-link.h>
     26 
     27 namespace zyn {
     28 
     29 WatchPoint::WatchPoint(WatchManager *ref, const char *prefix, const char *id)
     30     :active(false), samples_left(0), reference(ref)
     31 {
     32     identity[0] = 0;
     33     if(prefix)
     34         fast_strcpy(identity, prefix, sizeof(identity));
     35     if(id)
     36         strncat(identity, id, sizeof(identity)-1);
     37 }
     38 
     39 bool WatchPoint::is_active(void)
     40 {
     41     //Either the watchpoint is already active or the watchpoint manager has
     42     //received another activation this frame
     43     if(active)
     44         return true;
     45 
     46     if(reference && reference->active(identity)) {
     47         active       = true;
     48         samples_left = 1;
     49         return true;
     50     }
     51 
     52     return false;
     53 }
     54 
     55 bool WatchPoint::is_empty(void)
     56 {
     57     //return reference->is_empty(identity);
     58     return true;
     59 }
     60 
     61 FloatWatchPoint::FloatWatchPoint(WatchManager *ref, const char *prefix, const char *id)
     62     :WatchPoint(ref, prefix, id)
     63 {}
     64 
     65 VecWatchPoint::VecWatchPoint(WatchManager *ref, const char *prefix, const char *id)
     66     :WatchPoint(ref, prefix, id)
     67 {}
     68 
     69 WatchManager::WatchManager(thrlnk *link)
     70     :write_back(link), new_active(false)
     71 {
     72     memset(active_list, 0, sizeof(active_list));
     73     memset(sample_list, 0, sizeof(sample_list));
     74     memset(prebuffer_sample, 0, sizeof(prebuffer_sample));
     75     memset(data_list,   0, sizeof(data_list));
     76     memset(deactivate,  0, sizeof(deactivate));
     77     memset(prebuffer,  0, sizeof(prebuffer));
     78     memset(trigger,  0, sizeof(trigger));
     79     memset(prebuffer_done,  0, sizeof(prebuffer_done));
     80     memset(call_count,0,sizeof(call_count));
     81 
     82 }
     83 
     84 void WatchManager::add_watch(const char *id)
     85 {
     86     //Don't add duplicate watchs
     87     for(int i=0; i<MAX_WATCH; ++i)
     88         if(!strcmp(active_list[i], id))
     89             return;
     90     //Apply to a free slot
     91     for(int i=0; i<MAX_WATCH; ++i) {
     92         if(!active_list[i][0]) {
     93             fast_strcpy(active_list[i], id, MAX_WATCH_PATH);
     94             new_active = true;
     95             sample_list[i] = 0;
     96             call_count[i] = 0;
     97             //printf("\n added watchpoint ID %s\n",id);
     98             break;
     99         }
    100     }
    101 }
    102 
    103 void WatchManager::del_watch(const char *id)
    104 {
    105     //Queue up the delete
    106     for(int i=0; i<MAX_WATCH; ++i)
    107         if(!strcmp(active_list[i], id))
    108             return (void) (deactivate[i] = true);
    109 }
    110 
    111 void WatchManager::tick(void)
    112 {
    113     //Try to send out any vector stuff
    114     for(int i=0; i<MAX_WATCH; ++i) {
    115         int framesize = 2;
    116         call_count[i] = 0;
    117         if(strstr(active_list[i], "noteout") != NULL)
    118             framesize = MAX_SAMPLE-1;
    119         if(sample_list[i] >= framesize && call_count[i]==0) {
    120             char        arg_types[MAX_SAMPLE+1] = {};
    121             rtosc_arg_t arg_val[MAX_SAMPLE];
    122             for(int j=0; j<sample_list[i]; ++j) {
    123                 arg_types[j] = 'f';
    124                 arg_val[j].f = data_list[i][j];
    125             }
    126             write_back->writeArray(active_list[i], arg_types, arg_val);
    127             deactivate[i] = true;
    128         }
    129     }
    130 
    131     //Cleanup internal data
    132     new_active = false;
    133 
    134     //Clear deleted slots
    135     for(int i=0; i<MAX_WATCH; ++i) {
    136         if(deactivate[i]) {
    137             memset(active_list[i], 0, MAX_SAMPLE);
    138             sample_list[i] = 0;
    139             memset(data_list[i], 0, sizeof(float)*MAX_SAMPLE);
    140             memset(prebuffer[i], 0, sizeof(float)*(MAX_SAMPLE/2));
    141             deactivate[i]  = false;
    142             trigger[i] = false;
    143             prebuffer_done[i] = false;
    144             prebuffer_sample[i] = 0;
    145         }
    146     }
    147 }
    148 
    149 bool WatchManager::active(const char *id) const
    150 {
    151     assert(this);
    152     assert(id);
    153     if(new_active || true)
    154         for(int i=0; i<MAX_WATCH; ++i)
    155             if(!strcmp(active_list[i], id))
    156                 return true;
    157 
    158     return false;
    159 }
    160 
    161 bool WatchManager::trigger_active(const char *id) const
    162 {
    163     for(int i=0; i<MAX_WATCH; ++i)
    164         if(!strcmp(active_list[i], id))
    165             return trigger[i];
    166     return false;
    167 }
    168 
    169 int WatchManager::samples(const char *id) const
    170 {
    171     for(int i=0; i<MAX_WATCH; ++i)
    172         if(!strcmp(active_list[i], id))
    173             return sample_list[i];
    174     return 0;
    175 }
    176 
    177 void WatchManager::satisfy(const char *id, float f)
    178 {
    179     //printf("trying to satisfy '%s'\n", id);
    180     if(write_back)
    181         write_back->write(id, "f", f);
    182     del_watch(id);
    183 }
    184 
    185 void WatchManager::satisfy(const char *id, float *f, int n)
    186 {
    187     int selected = -1;
    188     for(int i=0; i<MAX_WATCH; ++i)
    189         if(!strcmp(active_list[i], id))
    190             selected = i;
    191 
    192     if(selected == -1)
    193         return;
    194 
    195     int space = MAX_SAMPLE - sample_list[selected];
    196 
    197     if(space >= n || !trigger[selected])
    198         space = n;
    199 
    200     //special case to capture the time+level pairs that come from
    201     //envelopes/LFOs
    202     if(n == 2)
    203         trigger[selected] = true;
    204 
    205     if(space && (call_count[selected]==0 || n == 2)){
    206         for(int i=0; i<space; i++){
    207             const float prev = prebuffer[selected][(prebuffer_sample[selected]+MAX_SAMPLE/2-1)%(MAX_SAMPLE/2)];
    208             if(!trigger[selected]){
    209                 prebuffer[selected][prebuffer_sample[selected]%(MAX_SAMPLE/2)] = f[i];
    210                 prebuffer_sample[selected]++;
    211                 //printf("\n before trigger %s  prebuffer at index %d   %f \n",active_list[selected],prebuffer_sample[selected],prebuffer[selected][prebuffer_sample[selected]%(MAX_SAMPLE/2)]);
    212             }
    213             if(!trigger[selected] && prebuffer_sample[selected] >= (MAX_SAMPLE/2)){
    214                 if (prev <= 0 && f[i] > 0){
    215                     //printf("\n trigger at %s  prebuffer at index %f  %d   f[i] %f \n",active_list[selected],prebuffer[selected][prebuffer_sample[selected]%(MAX_SAMPLE/2)-2],prebuffer_sample[selected],f[i]);
    216                     trigger[selected] = true;
    217                     for(int j = 0; j < (MAX_SAMPLE/2); ++j){
    218                         data_list[selected][sample_list[selected]] = prebuffer[selected][prebuffer_sample[selected]%(MAX_SAMPLE/2)];
    219                         sample_list[selected]++;
    220                         prebuffer_sample[selected]++;
    221                     }
    222                     prebuffer_done[selected] = true;
    223                     space = MAX_SAMPLE - sample_list[selected];
    224                     if(n >= i+space)
    225                         space = i+space;
    226                     else
    227                         space = n;
    228                     trigger_other(selected);
    229                 }
    230             }
    231 
    232             if(trigger[selected] && !prebuffer_done[selected]){
    233                 data_list[selected][sample_list[selected]] = f[i];
    234                 sample_list[selected]++;
    235             }
    236 
    237             if(prebuffer_done[selected])
    238                 prebuffer_done[selected] = false;
    239         }
    240     }
    241     call_count[selected]++;
    242 }
    243 
    244 void WatchManager::trigger_other(int selected){
    245     for(int k=0; k<MAX_WATCH; ++k){
    246         if(selected != k && !trigger[k] && prebuffer_sample[k]>(MAX_SAMPLE/2) ){
    247             char tmp[128];
    248             char tmp1[128];
    249             strcpy(tmp, active_list[selected]);
    250             strcpy(tmp1, active_list[k]);
    251             if(strlen(active_list[k]) < strlen(active_list[selected]))
    252                 tmp[strlen(tmp)-1] =0;
    253             else if (strlen(active_list[k]) > strlen(active_list[selected]))
    254                 tmp1[strlen(tmp1)-1] =0;
    255             //printf("\n compare tmp1 %s with tmp %s \n",tmp1,tmp);
    256             if(!strcmp(tmp1,tmp)){
    257                 trigger[k] = true;
    258                 // printf("\n putting prebuffer size of %d into %s watchpoint \n",prebuffer_sample[k]%(MAX_SAMPLE/2),active_list[k]);
    259                 // printf("\n value of first buffer %f \n",prebuffer[k][prebuffer_sample[k]%(MAX_SAMPLE/2)]);
    260                 for(int j = prebuffer_sample[k]%(MAX_SAMPLE/2); j < (MAX_SAMPLE/2); ++j){
    261                     data_list[k][sample_list[k]] = prebuffer[k][j];
    262                     sample_list[k]++;
    263                 }
    264                 for(int j = 0; j < prebuffer_sample[selected]%(MAX_SAMPLE/2); ++j){
    265                     data_list[k][sample_list[k]] = prebuffer[k][j];
    266                     sample_list[k]++;
    267                 }
    268                 //prebuffer_done[k] = true;
    269                 //printf("\n t Trigger for %s happen at sample %d \n",active_list[k],sample_list[k] );
    270             }
    271         }
    272     }
    273 }
    274 
    275 
    276 }