Subversion Repositories svn.mios32

Rev

Rev 1398 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1398 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: MbCvMod.cpp 1960 2014-02-09 20:21:24Z tk $
3
/*
4
 * MIDIbox CV Modulation Matrix
5
 *
6
 * ==========================================================================
7
 *
8
 *  Copyright (C) 2010 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
11
 *
12
 * ==========================================================================
13
 */
14
 
15
#include <string.h>
16
#include "app.h"
17
#include "MbCvMod.h"
18
#include "MbCvEnvironment.h"
19
 
20
 
21
/////////////////////////////////////////////////////////////////////////////
22
// for optional debugging messages via DEBUG_MSG (defined in mios32_config.h)
23
// should be at least 1 for sending error messages
24
/////////////////////////////////////////////////////////////////////////////
25
#define DEBUG_VERBOSE_LEVEL 1
26
 
27
 
28
 
29
/////////////////////////////////////////////////////////////////////////////
30
// Constructor
31
/////////////////////////////////////////////////////////////////////////////
32
MbCvMod::MbCvMod()
33
{
34
    init(0);
35
}
36
 
37
 
38
/////////////////////////////////////////////////////////////////////////////
39
// Destructor
40
/////////////////////////////////////////////////////////////////////////////
41
MbCvMod::~MbCvMod()
42
{
43
}
44
 
45
 
46
/////////////////////////////////////////////////////////////////////////////
47
// MOD init function
48
/////////////////////////////////////////////////////////////////////////////
49
void MbCvMod::init(u8 _modNum)
50
{
51
    ModPatchT *mp = modPatch;
52
    for(int i=0; i<MBCV_NUM_MOD; ++i, ++mp) {
53
        mp->src1 = 0;
54
        mp->src1_chn = _modNum;
55
        mp->src2 = 0;
56
        mp->src2_chn = _modNum;
57
        mp->op = 0;
58
        mp->depth = 64;
1960 tk 59
        mp->offset = 0;
1398 tk 60
        mp->dst1 = 0;
61
        mp->dst2 = 0;
1960 tk 62
 
63
        modOut[i] = 0;
1398 tk 64
    }
65
}
66
 
67
 
68
/////////////////////////////////////////////////////////////////////////////
1960 tk 69
// Modulation Sources
70
/////////////////////////////////////////////////////////////////////////////
71
 
72
#define CREATE_SRC_FUNCTION(name, str, getCode) \
73
    static const char name##SrcString[] = str; \
74
    static s16 getSrc##name(MbCvEnvironment* env, u8 cv) { getCode; }
75
 
76
typedef struct {
77
    const char *nameString;
78
    s16 (*getFunct)(MbCvEnvironment *env, u8 cv);
79
} MbCvModSrcTableEntry_t;
80
 
81
#define SRC_TABLE_ITEM(name) \
82
    { name##SrcString, getSrc##name }
83
 
84
CREATE_SRC_FUNCTION(None,    "--- ", return 0);
85
CREATE_SRC_FUNCTION(Env1,    "ENV1", return env->mbCv[cv].mbCvEnv1[0].envOut);
86
CREATE_SRC_FUNCTION(Env2,    "ENV2", return env->mbCv[cv].mbCvEnv2[0].envOut);
87
CREATE_SRC_FUNCTION(Lfo1,    "LFO1", return env->mbCv[cv].mbCvLfo[0].lfoOut);
88
CREATE_SRC_FUNCTION(Lfo2,    "LFO2", return env->mbCv[cv].mbCvLfo[1].lfoOut);
89
CREATE_SRC_FUNCTION(Mod1,    "MOD1", return env->mbCv[cv].mbCvMod.modOut[0]);
90
CREATE_SRC_FUNCTION(Mod2,    "MOD2", return env->mbCv[cv].mbCvMod.modOut[1]);
91
CREATE_SRC_FUNCTION(Mod3,    "MOD3", return env->mbCv[cv].mbCvMod.modOut[2]);
92
CREATE_SRC_FUNCTION(Mod4,    "MOD4", return env->mbCv[cv].mbCvMod.modOut[3]);
93
CREATE_SRC_FUNCTION(Key,     "Key ", return env->mbCv[cv].mbCvVoice.voiceLinearFrq >> 1);
94
CREATE_SRC_FUNCTION(Vel,     "Vel ", return env->mbCv[cv].mbCvVoice.voiceVelocity << 8);
95
CREATE_SRC_FUNCTION(MdW,     "MdW ", return env->mbCv[cv].mbCvMidiVoice.midivoiceModWheel << 8);
96
CREATE_SRC_FUNCTION(PBn,     "PBn ", return env->mbCv[cv].mbCvMidiVoice.midivoicePitchBender * 2);
97
CREATE_SRC_FUNCTION(Aft,     "Aft ", return env->mbCv[cv].mbCvMidiVoice.midivoiceAftertouch << 8);
98
CREATE_SRC_FUNCTION(Knb1,    "Knb1", return env->knobValue[0] << 7);
99
CREATE_SRC_FUNCTION(Knb2,    "Knb2", return env->knobValue[1] << 7);
100
CREATE_SRC_FUNCTION(Knb3,    "Knb3", return env->knobValue[2] << 7);
101
CREATE_SRC_FUNCTION(Knb4,    "Knb4", return env->knobValue[3] << 7);
102
CREATE_SRC_FUNCTION(Knb5,    "Knb5", return env->knobValue[4] << 7);
103
CREATE_SRC_FUNCTION(Knb6,    "Knb6", return env->knobValue[5] << 7);
104
CREATE_SRC_FUNCTION(Knb7,    "Knb7", return env->knobValue[6] << 7);
105
CREATE_SRC_FUNCTION(Knb8,    "Knb8", return env->knobValue[7] << 7);
106
CREATE_SRC_FUNCTION(Ain1,    "AIN1", return MIOS32_AIN_PinGet(0) << 3); // 12bit -> 15bit
107
CREATE_SRC_FUNCTION(Ain2,    "AIN2", return MIOS32_AIN_PinGet(1) << 3); // 12bit -> 15bit
108
CREATE_SRC_FUNCTION(Ain3,    "AIN3", return MIOS32_AIN_PinGet(2) << 3); // 12bit -> 15bit
109
CREATE_SRC_FUNCTION(Ain4,    "AIN4", return MIOS32_AIN_PinGet(3) << 3); // 12bit -> 15bit
110
CREATE_SRC_FUNCTION(Ain5,    "AIN5", return MIOS32_AIN_PinGet(4) << 3); // 12bit -> 15bit
111
CREATE_SRC_FUNCTION(Ain6,    "AIN6", return MIOS32_AIN_PinGet(5) << 3); // 12bit -> 15bit
112
CREATE_SRC_FUNCTION(Ain7,    "AIN7", return MIOS32_AIN_PinGet(6) << 3); // 12bit -> 15bit
113
CREATE_SRC_FUNCTION(Ain8,    "AIN8", return MIOS32_AIN_PinGet(7) << 3); // 12bit -> 15bit
114
CREATE_SRC_FUNCTION(SeqEnvM, "EnvM", return env->mbCv[cv].mbCvSeqBassline.seqEnvMod << 7);
115
CREATE_SRC_FUNCTION(SeqAcc,  "Acc.", return (env->mbCv[cv].mbCvArp.arpEnabled ? env->mbCv[cv].mbCvSeqBassline.seqAccent : env->mbCv[cv].mbCvSeqBassline.seqAccentEffective) << 7);
116
 
117
static const MbCvModSrcTableEntry_t mbCvModSrcTable[MBCV_NUM_MOD_SRC] = {
118
    SRC_TABLE_ITEM(None),
119
    SRC_TABLE_ITEM(Env1),
120
    SRC_TABLE_ITEM(Env2),
121
    SRC_TABLE_ITEM(Lfo1),
122
    SRC_TABLE_ITEM(Lfo2),
123
    SRC_TABLE_ITEM(Mod1),
124
    SRC_TABLE_ITEM(Mod2),
125
    SRC_TABLE_ITEM(Mod3),
126
    SRC_TABLE_ITEM(Mod4),
127
    SRC_TABLE_ITEM(Key),
128
    SRC_TABLE_ITEM(Vel),
129
    SRC_TABLE_ITEM(MdW),
130
    SRC_TABLE_ITEM(PBn),
131
    SRC_TABLE_ITEM(Aft),
132
    SRC_TABLE_ITEM(Knb1),
133
    SRC_TABLE_ITEM(Knb2),
134
    SRC_TABLE_ITEM(Knb3),
135
    SRC_TABLE_ITEM(Knb4),
136
    SRC_TABLE_ITEM(Knb5),
137
    SRC_TABLE_ITEM(Knb6),
138
    SRC_TABLE_ITEM(Knb7),
139
    SRC_TABLE_ITEM(Knb8),
140
    SRC_TABLE_ITEM(Ain1),
141
    SRC_TABLE_ITEM(Ain2),
142
    SRC_TABLE_ITEM(Ain3),
143
    SRC_TABLE_ITEM(Ain4),
144
    SRC_TABLE_ITEM(Ain5),
145
    SRC_TABLE_ITEM(Ain6),
146
    SRC_TABLE_ITEM(Ain7),
147
    SRC_TABLE_ITEM(Ain8),
148
    SRC_TABLE_ITEM(SeqEnvM),
149
    SRC_TABLE_ITEM(SeqAcc),
150
};
151
 
152
 
153
/////////////////////////////////////////////////////////////////////////////
154
// Modulation Operations
155
/////////////////////////////////////////////////////////////////////////////
156
 
157
#define CREATE_OP_FUNCTION(name, str, modifyCode) \
158
    static const char name##OpString[] = str; \
159
    static s16 modifyOp##name(MbCvEnvironment *env, MbCvMod* mod, u8 num, s16 src1, s16 src2) { modifyCode; }
160
 
161
typedef struct {
162
    const char *nameString;
163
    s16 (*modifyFunct)(MbCvEnvironment *env, MbCvMod *mod, u8 num, s16 src1, s16 src2);
164
} MbCvModOpTableEntry_t;
165
 
166
#define OP_TABLE_ITEM(name) \
167
    { name##OpString, modifyOp##name }
168
 
169
CREATE_OP_FUNCTION(None,     "--- ", return 0);
170
CREATE_OP_FUNCTION(Src1Only, "Src1", return src1);
171
CREATE_OP_FUNCTION(Src2Only, "Src2", return src2);
172
CREATE_OP_FUNCTION(Plus,     "1+2 ", return src1 + src2);
173
CREATE_OP_FUNCTION(Minus,    "1-2 ", return src1 - src2);
174
CREATE_OP_FUNCTION(Multiply, "1*2 ", return (src1 * src2) / 8192); // / 8192 to avoid overrun
175
CREATE_OP_FUNCTION(Xor,      "XOR ", return src1 ^ src2);
176
CREATE_OP_FUNCTION(Or,       "OR  ", return src1 | src2);
177
CREATE_OP_FUNCTION(And,      "AND ", return src1 & src2);
178
CREATE_OP_FUNCTION(Min,      "MIN ", return (src1 < src2) ? src1 : src2);
179
CREATE_OP_FUNCTION(Max,      "MAX ", return (src1 > src2) ? src1 : src2);
180
CREATE_OP_FUNCTION(Lt,       "1<2 ", return (src1 < src2) ? 0x7fff : 0x0000);
181
CREATE_OP_FUNCTION(Gt,       "1>2 ", return (src1 > src2) ? 0x7fff : 0x0000);
182
CREATE_OP_FUNCTION(Eq,       "1=2 ", s32 diff = src1 - src2; return (diff > -64 && diff < 64) ? 0x7fff : 0x0000);
183
CREATE_OP_FUNCTION(SandH,    "S&H ", u8 old_mod_transition = mod->modTransition; if( src2 < 0 ) { mod->modTransition &= ~(1 << num); } else { mod->modTransition |= (1 << num); } return (mod->modTransition != old_mod_transition && src2 >= 0) ? src1 : mod->modOut[num]);
184
CREATE_OP_FUNCTION(Fts,      "FTS ", s32 sum = src1 + src2; if( sum >= 0 ) { return env->scaleValue(sum / 256) * 256; } else { return -(env->scaleValue(-sum / 256) * 256); });
185
 
186
 
187
static const MbCvModOpTableEntry_t mbCvModOpTable[MBCV_NUM_MOD_OP] = {
188
    OP_TABLE_ITEM(None),
189
    OP_TABLE_ITEM(Src1Only),
190
    OP_TABLE_ITEM(Src2Only),
191
    OP_TABLE_ITEM(Plus),
192
    OP_TABLE_ITEM(Minus),
193
    OP_TABLE_ITEM(Multiply),
194
    OP_TABLE_ITEM(Xor),
195
    OP_TABLE_ITEM(Or),
196
    OP_TABLE_ITEM(And),
197
    OP_TABLE_ITEM(Min),
198
    OP_TABLE_ITEM(Max),
199
    OP_TABLE_ITEM(Lt),
200
    OP_TABLE_ITEM(Gt),
201
    OP_TABLE_ITEM(Eq),
202
    OP_TABLE_ITEM(SandH),
203
    OP_TABLE_ITEM(Fts),
204
};
205
 
206
 
207
/////////////////////////////////////////////////////////////////////////////
1398 tk 208
// Modulation Matrix Handler
209
/////////////////////////////////////////////////////////////////////////////
210
void MbCvMod::tick(void)
211
{
212
    // dirty... we handle MbCvEnvironment like a singleton
213
    MbCvEnvironment* env = APP_GetEnv();
214
    if( !env )
215
        return;
216
 
217
    // calculate modulation pathes
218
    ModPatchT *mp = modPatch;
219
    for(int i=0; i<MBCV_NUM_MOD; ++i, ++mp) {
220
        if( mp->depth != 0 ) {
221
 
222
            // first source
1960 tk 223
            s32 mod_src1_value = 0;
224
            if( mp->src1 && mp->src1_chn < CV_SE_NUM ) {
1398 tk 225
                if( mp->src1 & (1 << 7) ) {
226
                    // constant range 0x00..0x7f -> +0x0000..0x38f0
227
                    mod_src1_value = (mp->src1 & 0x7f) << 7;
1960 tk 228
                } else if( mp->src1 < MBCV_NUM_MOD_SRC ) {
1398 tk 229
                    // modulation range +/- 0x3fff
1960 tk 230
                    const MbCvModSrcTableEntry_t *srcItem = &mbCvModSrcTable[mp->src1];
231
                    mod_src1_value = srcItem->getFunct(env, mp->src1_chn) / 2;
1398 tk 232
                }
233
            }
234
 
235
            // second source
1960 tk 236
            s32 mod_src2_value = 0;
237
            if( mp->src2 && mp->src2_chn < CV_SE_NUM ) {
1398 tk 238
                if( mp->src2 & (1 << 7) ) {
239
                    // constant range 0x00..0x7f -> +0x0000..0x38f0
240
                    mod_src2_value = (mp->src2 & 0x7f) << 7;
241
                } else {
242
                    // modulation range +/- 0x3fff
1960 tk 243
                    const MbCvModSrcTableEntry_t *srcItem = &mbCvModSrcTable[mp->src2];
244
                    mod_src2_value = srcItem->getFunct(env, mp->src2_chn) / 2;
1398 tk 245
                }
246
            }
247
 
248
            // apply operator
1960 tk 249
            u8 opNum = mp->op & 0xf;
250
            s16 mod_result = 0;
251
            if( opNum < MBCV_NUM_MOD_OP ) {
252
                const MbCvModOpTableEntry_t *opItem = &mbCvModOpTable[opNum];
253
                mod_result = opItem->modifyFunct(env, this, i, mod_src1_value, mod_src2_value);
1398 tk 254
            }
255
 
256
            // store in modulator source array for feedbacks
1960 tk 257
            // use value w/o depth and offset, this has two advantages:
1398 tk 258
            // - maximum resolution when forwarding the data value
259
            // - original MOD value can be taken for sample&hold feature
260
            // bit it also has disadvantage:
261
            // - the user could think it is a bug when depth doesn't affect the feedback MOD value...
1960 tk 262
            modOut[i] = mod_result;
1398 tk 263
 
264
            // forward to destinations
1960 tk 265
            if( mod_result || mp->offset ) {
1398 tk 266
                s32 scaled_mod_result = (s32)mp->depth * mod_result / 64; // (+/- 0x7fff * +/- 0x7f) / 128
267
                // invert result if requested
268
                s32 mod_dst1 = (mp->op & (1 << 6)) ? -scaled_mod_result : scaled_mod_result;
269
                s32 mod_dst2 = (mp->op & (1 << 7)) ? -scaled_mod_result : scaled_mod_result;
270
 
1960 tk 271
                // add result + offset to modulation target array
1398 tk 272
                u8 dst1 = mp->dst1;
273
                if( dst1 && dst1 <= MBCV_NUM_MOD_DST )
1960 tk 274
                    modDst[dst1] += mod_dst1 + 512 * mp->offset;
1398 tk 275
 
276
                u8 dst2 = mp->dst2;
277
                if( dst2 && dst2 <= MBCV_NUM_MOD_DST )
1960 tk 278
                    modDst[dst2] += mod_dst2 + 512 * mp->offset;
1398 tk 279
            }
280
        }
281
    }
282
}
283
 
284
/////////////////////////////////////////////////////////////////////////////
285
// Takes and clears destination value
286
/////////////////////////////////////////////////////////////////////////////
287
s32 MbCvMod::takeDstValue(const u8& ix)
288
{
289
    if( ix >= MBCV_NUM_MOD_DST )
290
        return 0;
291
 
292
    s32 *dst = (s32 *)&modDst[ix];
293
    s32 ret = *dst;
294
    *dst = 0;
295
    return ret;
296
}
297