beatrix

clones de Hammond et cabines Leslies, Hammond séries électroniques, modèles, caractéristiques, avis, comparaisons avec les originaux
Répondre
manu.c
Présentés
Messages : 113
Enregistré le : dim. oct. 22, 2006 6:29 pm
Localisation : Dieppe
Contact :

beatrix

Message par manu.c »

Bonjour à tous,

J'ai enfin réussit à faire fonctionner Beatrix (pas facile Linux quand tu ne connais pas). Le son est plutot chaud, je trouve par contre les percussions trop agressive sur le dernier octave (je n'ose pas jouer dessus je m'explose les oreilles). La simu de leslie ne pas franchement emballée.
Coté utilisation c'est tout sauf convivial, des fichiers de configuration à renseigner. Pour le controle de l'engin, j'ai utilisé mon module b4d (tirettes+boutons) que j'ai déclaré dans beatrix. Ca marche sauf les tirettes qui sont inversée : tout à 0 =plein jeu. Si quelqu'un a une solution je suis preneur.

Ma conclusion : difficile à mettre en oeuvre, pas convivial, peu d'info sur internet mais on sent qu'il y a du potentiel, le son global est très correct.

Pour ma part je continue d'utiliser B4 mais je vai poursuivre mes investigations sur Beatrix

Manu

Avatar du membre
bruno micheli
Présentés
Messages : 12247
Enregistré le : jeu. sept. 30, 2004 8:17 am
Localisation : Groland (Mufflin)
Contact :

Message par bruno micheli »

/*
* midi.c
* 27-sep-2004/FK Symbolic MIDI controller assignment.
* 16-sep-2004/FK Struggling with channel A split.
* NOTE: Drop the leftmost-rightmost stuff and this line when done.
* 10-sep-2004/FK It basically works. Whee...
* 09-sep-2004/FK Close to testing.
* 05-sep-2004/FK Work continues (slowly)
* 28-aug-2004/FK Working...
* 25-aug-2004/FK Generalised version of midiIn.c.
*
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/soundcard.h>
#include <limits.h>
#include <assert.h>

#include "config.h"
#include "midi.h"
#include "tonegen.h"
#include "preamp.h"
#include "scanner.h"
#include "program.h"
#include "whirl.h"

/*
* The size of the MIDI input buffer.
*/
#define BUFFER_SIZE_BYTES 1024

/*
* Symbolic names for functions that can be governed by MIDI controllers.
* These names are used by the configuration machinery to allow arbitrary
* mappings of controllers. This is how it works:
* Other modules, like the tonegenerator and the effects, call the function
* useMIDIControlFunction (name, function)
* with a name and a pointer to a function. The function implements some
* reaction to a MIDI controller, e.g. a drawbar setting. The name is a
* symbolic name that identifies the function. The name must be defined
* in array ccFuncNames[] (immediately below) and its position in the array
* is used as an opaque numeric id for the reaction. That numeric id is then
* used to examine the three arrays ctrlUseA, ctrlUseB and ctrlUseC in turn.
* When the accessed element contain a value less than 128 the function is
* entered in the corresponding ctrlvecA, ctrlvecB and ctrlvecC table, which
* are the runtime maps from MIDI controller numbers to functions.
*
* If you are with me so far, the tables cltrUse* define how reactions are
* mapped to MIDI controllers. The ctrlUse* tables are filled in on two
* occasions. The first, that always take place, is the function
* midiPrimeControllerMapping()
* which simplay provides the default initialization.
* The second, which MAY happen, is the configuration processing where the
* user can provide config options on the format:
* midi.controller.{upper,lower,pedals}.<cc>=<name>
* Here, again, the <name> is defined in ccFuncNames and the keywords upper,
* lower and pedals will determine which of the three ctrlUse* tables that are
* updated with the controller number <cc>.
*/

char * ccFuncNames[] = {
"upper.drawbar16",
"upper.drawbar513",
"upper.drawbar8",
"upper.drawbar4",
"upper.drawbar223",
"upper.drawbar2",
"upper.drawbar135",
"upper.drawbar113",
"upper.drawbar1",

"lower.drawbar16",
"lower.drawbar513",
"lower.drawbar8",
"lower.drawbar4",
"lower.drawbar223",
"lower.drawbar2",
"lower.drawbar135",
"lower.drawbar113",
"lower.drawbar1",

"pedal.drawbar16",
"pedal.drawbar513",
"pedal.drawbar8",
"pedal.drawbar4",
"pedal.drawbar223",
"pedal.drawbar2",
"pedal.drawbar135",
"pedal.drawbar113",
"pedal.drawbar1",

"percussion.enable", /* off/normal/soft/off */
"percussion.decay", /* fast/slow */
"percussion.harmonic", /* 3rd/2nd */

"vibrato.knob", /* off/v1/c1/v2/c2/v3/c3 */
"vibrato.routing", /* off/lower/upper/both */

"swellpedal1", /* Volume, for primary ctrlr (mod wheel) */
"swellpedal2", /* Volume, for secondary ctrlr (expression) */

"overdrive.character",

"rotary.speed-select", /* stop, slow, fast, stop */
"rotary.speed-toggle", /* sustain pedal */

"whirl.horn.filter.a.type",
"whirl.horn.filter.a.hz",
"whirl.horn.filter.a.q",
"whirl.horn.filter.a.gain",

"whirl.horn.filter.b.type",
"whirl.horn.filter.b.hz",
"whirl.horn.filter.b.q",
"whirl.horn.filter.b.gain",

"whirl.comb.a.feedback",
"whirl.comb.a.delay",

"whirl.comb.b.feedback",
"whirl.comb.b.delay",

"whirl.drum.filter.type",
"whirl.drum.filter.hz",
"whirl.drum.filter.q",
"whirl.drum.filter.gain",

"xov.ctl_biased",
"xov.ctl_biased_fb",
"xov.ctl_biased_fb2",
"xov.ctl_biased_gfb",
"xov.ctl_sagtobias",

"xov.inputgain",
"xov.outputgain",

NULL
};

/*
* States for the MIDI parser.
*/
enum parserState {
stIgnore, dtaIgnore,
stNoteOff, dtaNoteOff1, dtaNoteOff2,
stNoteOn, dtaNoteOn1, dtaNoteOn2,
stControlChg, dtaControlChg1, dtaControlChg2,
stProgramChg, dtaProgramChg
};

/*
* The row definition of the statusTable. The state field tells the parser
* where to go next and the handback is a pointer to further data dependent
* on the channel encapsulated in the status byte.
*/
typedef struct statusTableRowStruct {
int state;
void * handback;
} StatusTableRow;

/* Indexed by the MIDI status byte, positions 0-127 are unused because
* they represent data bytes. Wasteful? We trade 128*8=1024 bytes for
* a few CPU cycles.
*/
static StatusTableRow statusTable[256];

/* Used by the MIDI parser to record message bytes */
static unsigned char byte1;
static unsigned char byte2;
static unsigned char byte3;

static int midi_fd; /* File descriptor for the MIDI device */
static char * midiDevice = "/dev/midi00"; /* Default path to MIDI device */
static char midiDeviceBuffer[PATH_MAX + 1]; /* Actual path to MIDI device */

static unsigned char rcvChA = 0; /* MIDI receive channel */
static unsigned char rcvChB = 1; /* MIDI receive channel */
static unsigned char rcvChC = 2; /* MIDI receive channel */

/*
* The all channel transpose is used to transpose the entire instrument
* into a different mode and is a common function on synthesizers.
* The channel- and split-dependent transposes are for adjusting the
* reach of the user's MIDI controller(s) to the desired range.
*/

static int transpose = 0; /* All channel transpose */

static int nshA = 0; /* Channel A transpose (no split) */
static int nshA_U = 0; /* Channel A upper region transpose */
static int nshA_PL = 0; /* Channel A pedal region transpose */
static int nshA_UL = 0; /* Channel A lower region transpose */
static int nshB = 0; /* Channel B transpose */
static int nshC = 0; /* Channel C transpose */

static int splitA_PL = 0; /* A channel pedal region */
static int splitA_UL = 0; /* A channel lower region */

/*
* This flag controls how to map MIDI input that falls outside of
* the virtual instrument's manuals. A value of zero means such MIDI notes
* make no sound. A value of one means that the MIDI notes map back
* into the nearest octave with a playable key, a mechanism similar to
* the foldback used in some organ models.
*/
static int userExcursionStrategy = 0;

#ifdef COMMENT
/* MIDI note numbers on the user's controller. */
static int leftmost_MIDINoteA = 36; /* Input device ch A (default 61 key) */
static int rightmostMIDINoteA = 96; /* Input device ch A (default 61 key) */
static int leftmost_MIDINoteB = 36; /* Input device ch B (default 61 key) */
static int rightmostMIDINoteB = 96; /* Input device ch B (default 61 key) */
static int leftmost_MIDINoteC = 36; /* Input device ch C (default 61 key) */
static int rightmostMIDINoteC = 96; /* Input device ch C (default 61 key) */
#endif /* COMMENT */

static unsigned char inBuffer [BUFFER_SIZE_BYTES]; /* Input buffer */

static unsigned char keyTableA[128]; /* MIDI note to Beatrix key transl. tbl */
static unsigned char keyTableB[128]; /* MIDI note to Beatrix key transl. tbl */
static unsigned char keyTableC[128]; /* MIDI note to Beatrix key transl. tbl */

static unsigned char * keyTable; /* Activated table */

/* Arrays that map from usage codes to MIDI controller numbers. */

#define CTRL_USE_MAX 128

static unsigned char ctrlUseA[CTRL_USE_MAX];
static unsigned char ctrlUseB[CTRL_USE_MAX];
static unsigned char ctrlUseC[CTRL_USE_MAX];

/* Arrays of pointers to functions that handle controller values. */

static void (*ctrlvecA[128])(unsigned char uc);
static void (*ctrlvecB[128])(unsigned char uc);
static void (*ctrlvecC[128])(unsigned char uc);

static void (**ctrlvec) (unsigned char); /* Activated table */

static unsigned char controllerMap[3][128];

#define IS_SYSTEM_REAL_TIME(C) ((0xF8 & (C)) == 0xF8)
#define IS_STATUS(C) ((C) & 0x80)
#define GET_MIDI_CHANNEL(C) ((C) & 0x0F)

#define IS_CHANNEL(C) ((0 <= (C)) && ((C) < 16))

/* ---------------------------------------------------------------- */

/*
*
*/
static int getCCFunctionId (const char * name) {
int i;
assert (name != NULL);
for (i = 0; ccFuncNames != NULL; i++) {
if (0 == strcmp (name, ccFuncNames)) {
return i;
}
}
return -1;
}

/*
* This is the default (empty) controller function. It does nothing at all
* and therefore we initialize the ctrlvec tables with pointers to it.
*/
static void emptyControlFunction (unsigned char uc) {}

/*
* Assigns a control function to a MIDI controller.
* This function is programmed to recognise multiple allocations that do
* not refer to the no-op function. It MAY be an error if a controller
* is allocated twice, so the code just prints a warning.
*
* @param vec Array of pointers to control functions.
* @param controller MIDI controller number
* @param f Pointer to control function to assign to controller
*/
static void assignMIDIControllerFunction (void (* vec []) (unsigned char),
unsigned char controller,
void (*f) (unsigned char)) {
assert (vec != NULL);
if (f != NULL) {
if ((vec[controller] != emptyControlFunction) &&
(vec[controller] != NULL)) {
fprintf (stderr,
"midiIn.c:WARNING, multiple allocation of controller %d!",
(int) controller);
}
vec[controller] = f;

#if 0
if (vec == ctrlvecA) {
fprintf (stdout, "A[%d]=%x\n", (int) controller, f);
}
#endif

}
else {
vec[controller] = emptyControlFunction;
}
}

/*
* This function sets the controller function for the given MIDI controller.
* If the provided function pointer is NULL, the external controller is
* released. (I do not expect this feature to be used, but you never know).
* NOTE: 22-jul-2004/FK In the face of generality, this remain as a backwards
* compatible option for channel A (upper).
*/
void setMIDIControllerFunction (unsigned char controller,
void (*f) (unsigned char c)) {

fprintf (stderr, "Rogue call to setMIDIControllerFunction(controller=%d,");
fprintf (stderr, " f=...);\n", controller);
return;

assignMIDIControllerFunction (ctrlvecA, controller, f);
}

/*
* 22-jul-2004: new function to assign controllers to any of three MIDI
* channels. Utility refers to the sections that are separated by MIDI
* channels, not the channels themselves.
*/
void setuMIDIControllerFunction (int utility,
unsigned char controller,
void (*f) (unsigned char)) {

fprintf (stderr, "Rogue call to setuMIDIControllerFunction(utility=%d,");
fprintf (stderr, " controller=%d, f=...);\n", utility, controller);
return;

switch (utility) {
case MIDI_UTIL_SWELL:
assignMIDIControllerFunction (ctrlvecA, controller, f);
break;
case MIDI_UTIL_GREAT:
assignMIDIControllerFunction (ctrlvecB, controller, f);
break;
case MIDI_UTIL_PEDAL:
assignMIDIControllerFunction (ctrlvecC, controller, f);
break;
default:
assert (0);
break;
}
}

/*
* 26-sep-2004/FK This is the entry point for modules that wish to register
* functions that accept MIDI controller data. Functions entered through this
* interface can be freely remapped by the user via configuration files.
*
* @param cfname The symbolic name (defined in ccFuncNames) of the reaction
* implemented by the function pointed to by the f parameter.
* @param f Pointer to function that acts on the controller message.
*/
void useMIDIControlFunction (char * cfname, void (* f) (unsigned char)) {

int x = getCCFunctionId (cfname);

assert (-1 < x);

if (ctrlUseA[x] < 128) {
assignMIDIControllerFunction (ctrlvecA, ctrlUseA[x], f);
}
if (ctrlUseB[x] < 128) {
assignMIDIControllerFunction (ctrlvecB, ctrlUseB[x], f);
}
if (ctrlUseC[x] < 128) {
assignMIDIControllerFunction (ctrlvecC, ctrlUseC[x], f);
}

}

/*
* This initializes the MIDI controller vector tables.
*/
static void loadControllerTable () {
int i;
for (i = 0; i < 128; i++) {
if (ctrlvecA == NULL) {
ctrlvecA = emptyControlFunction;
}
if (ctrlvecB == NULL) {
ctrlvecB = emptyControlFunction;
}
if (ctrlvecC == NULL) {
ctrlvecC = emptyControlFunction;
}
}
}

/*
* This function is used to map a region of the MIDI keyboard to a
* region of Beatrix keys. The supplied translation table will only be
* written in the specified MIDI range.
*
* @param translationTable Pointer to lookup table used by parser.
* @param firstMIDINote MIDI note number of the first note in the input.
* @param lastMIDINote MIDI note number of the last note in the input.
* @param firstKey First key number in the target region.
* @param lastKey Last key number in the target region.
* @param transpose Applies a small transpose to the target region.
* @param excursionStrategy If zero, MIDI notes mapped outside the target
* become silent. If 1, notes outside the target
* wraps around to the closest octave key.
*/
static void loadKeyTableRegion (unsigned char * translationTable,
int first_MIDINote,
int last_MIDINote,
int firstKey,
int lastKey,
int transpose,
int excursionStrategy)
{
int note;
int offset = transpose + firstKey - first_MIDINote;
int firstKeyAdjust = firstKey + 12 - (firstKey % 12);
int lastKeyAdjust = lastKey - (lastKey % 12) - 12;

for (note = first_MIDINote; note <= last_MIDINote; note++) {
int key = note + offset;
if (key < firstKey) {
key = (excursionStrategy == 1) ? firstKeyAdjust + (key % 12) : 255;
}
else if (lastKey < key) {
key = (excursionStrategy == 1) ? lastKeyAdjust + (key % 12) : 255;
}
/* This may happen if the key range is smaller than an octave. */
if ((key < firstKey) || (lastKey < key)) {
key = 255;
}
translationTable[note] = key;
}
}

/*
* Clears a note-to-key translation table by setting all entries to 255.
*/
static void clearKeyTable (unsigned char * table) {
int i;
for (i = 0; i < 128; i++) {
table = 255;
}
}

/*
* This function loads the channel A note-to-key translation table.
*/
static void loadKeyTableA () {
int left = 0;
int first_MIDI_Note;

clearKeyTable (keyTableA);

if (0 < splitA_PL) {
loadKeyTableRegion (keyTableA,
24, splitA_PL - 1,
128, 159,
transpose + nshA_PL,
0);
left = splitA_PL;
}

if (left < splitA_UL) {
first_MIDI_Note = (36 < left) ? left : 36;
loadKeyTableRegion (keyTableA,
first_MIDI_Note, splitA_UL - 1,
64 + (first_MIDI_Note % 12), 124,
transpose + nshA_UL,
0);
left = splitA_UL;
}

first_MIDI_Note = (36 < left) ? left : 36;

/*
* Here we allow the upper MIDI
* parameter to extend up to 127 (maximum). That way a liberal use of
* nshA_U (noteshift for upper manual in split mode) can exploit a
* wide controller (e.g. 88 keys).
*/

loadKeyTableRegion (keyTableA,
first_MIDI_Note, 127,
0 + (first_MIDI_Note - 36), 60,
transpose + ((0 < left) ? nshA_U : nshA),
0);

} /* loadKeyTableA */

/*
* Loads the B channel (lower manual) MIDI to key mapping table.
*/
static void loadKeyTableB () {

clearKeyTable (keyTableB);

loadKeyTableRegion (keyTableB,
36, 96,
64, 124,
transpose + nshB,
userExcursionStrategy);

}

/*
* Loads the C channel (pedals) MIDI to key mapping table.
*/
static void loadKeyTableC () {

clearKeyTable (keyTableC);

loadKeyTableRegion (keyTableC,
24, 55,
128, 159,
transpose + nshC,
userExcursionStrategy);

}

/*
* External interface to set and unset the A keyboard split points.
*/
void setKeyboardSplitMulti (int flags,
int p_splitA_PL,
int p_splitA_UL,
int p_nshA_PL,
int p_nshA_UL,
int p_nshA_U)
{
if (flags & 1) splitA_PL = p_splitA_PL;
if (flags & 2) splitA_UL = p_splitA_UL;
if (flags & 4) nshA_PL = p_nshA_PL;
if (flags & 8) nshA_UL = p_nshA_UL;
if (flags & 16) nshA_U = p_nshA_U;

loadKeyTableA ();
}

void setKeyboardTransposeA (int transpose) {
nshA = transpose;
loadKeyTableA ();
}

void setKeyboardTransposeB (int transpose) {
nshB = transpose;
loadKeyTableB ();
}

void setKeyboardTransposeC (int transpose) {
nshC = transpose;
loadKeyTableC ();
}

void setKeyboardTranspose (int trsp) {
transpose = trsp;
loadKeyTableA ();
loadKeyTableB ();
loadKeyTableC ();
}

/*
* Loads the status table. The table is used by the MIDI parser to look
* up status bytes. The table gives the parser's initial state and a pointer
* to items used in the processing of the data in the message. For example,
* note on/off messages uses a pointer to a note-to-key translation table.
*/
static void loadStatusTable () {
int i;

for (i = 128; i < 256; i++) {
statusTable.state = stIgnore;
statusTable[i].handback = NULL;
}

i = MIDI_NOTEOFF | rcvChA;
statusTable[i].state = stNoteOff;
statusTable[i].handback = (void *) keyTableA;

i = MIDI_NOTEOFF | rcvChB;
statusTable[i].state = stNoteOff;
statusTable[i].handback = (void *) keyTableB;

i = MIDI_NOTEOFF | rcvChC;
statusTable[i].state = stNoteOff;
statusTable[i].handback = (void *) keyTableC;

i = MIDI_NOTEON | rcvChA;
statusTable[i].state = stNoteOn;
statusTable[i].handback = (void *) keyTableA;

i = MIDI_NOTEON | rcvChB;
statusTable[i].state = stNoteOn;
statusTable[i].handback = (void *) keyTableB;

i = MIDI_NOTEON | rcvChC;
statusTable[i].state = stNoteOn;
statusTable[i].handback = (void *) keyTableC;

i = MIDI_CTL_CHANGE | rcvChA;
statusTable[i].state = stControlChg;
statusTable[i].handback = (void *) ctrlvecA;

i = MIDI_CTL_CHANGE | rcvChB;
statusTable[i].state = stControlChg;
statusTable[i].handback = (void *) ctrlvecB;

i = MIDI_CTL_CHANGE | rcvChC;
statusTable[i].state = stControlChg;
statusTable[i].handback = (void *) ctrlvecC;

i = MIDI_PGM_CHANGE | rcvChA;
statusTable[i].state = stProgramChg;
statusTable[i].handback = NULL;


}

/*
* Auxillary function to midiPrimeControllerMapping below.
*/
static void loadCCMap (char * cfname,
int ccn,
unsigned char * A,
unsigned char * B,
unsigned char * C) {
int x = getCCFunctionId (cfname);
if (!(-1 < x)) {
fprintf (stderr, "Unrecognized controller function name:'%s'\n", cfname);
assert (-1 < x);
}
if (A != NULL) A[x] = (unsigned char) ccn;
if (B != NULL) B[x] = (unsigned char) ccn;
if (C != NULL) C[x] = (unsigned char) ccn;
}

/*
* Sets the initial state of the tables that map from a controllable function
* id to a MIDI controller number. This function must be
* run before the configuration sequence because it is part of the static
* default. Maintaining a static default in source becomes much to odious
* when things move around.
* What we do is that we load the tables ctrlUseA, ctrlUseB and ctrlUseC
*/
void midiPrimeControllerMapping () {

int i;
for (i = 0; i < CTRL_USE_MAX; i++) {
ctrlUseA[i] = 255;
ctrlUseB[i] = 255;
ctrlUseC[i] = 255;
}

loadCCMap ("swellpedal1", 1, ctrlUseA, ctrlUseB, ctrlUseC);
loadCCMap ("swellpedal2", 11, ctrlUseA, ctrlUseB, ctrlUseC);

loadCCMap ("xov.ctl_biased", 3, ctrlUseA, NULL, NULL);
loadCCMap ("xov.ctl_biased_fb", 9, ctrlUseA, NULL, NULL);
loadCCMap ("xov.ctl_biased_fb2", 14, ctrlUseA, NULL, NULL);
loadCCMap ("xov.ctl_biased_gfb", 15, ctrlUseA, NULL, NULL);
loadCCMap ("xov.ctl_sagtobias", 20, ctrlUseA, NULL, NULL);

loadCCMap ("xov.inputgain", 21, ctrlUseA, NULL, NULL);
loadCCMap ("xov.outputgain", 22, ctrlUseA, NULL, NULL);

loadCCMap ("whirl.drum.filter.type", 23, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.drum.filter.hz", 24, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.drum.filter.q", 25, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.drum.filter.gain", 26, ctrlUseA, NULL, NULL);

loadCCMap ("whirl.horn.filter.a.type", 27, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.horn.filter.a.hz", 28, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.horn.filter.a.q", 29, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.horn.filter.a.gain", 30, ctrlUseA, NULL, NULL);

/* 32-63 are least significant bits of controller 0-31 */

loadCCMap ("rotary.speed-toggle", 64, ctrlUseA, ctrlUseB, ctrlUseC);

loadCCMap ("upper.drawbar16", 70, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar513", 71, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar8", 72, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar4", 73, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar223", 74, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar2", 75, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar135", 76, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar113", 77, ctrlUseA, NULL, NULL);
loadCCMap ("upper.drawbar1", 78, ctrlUseA, NULL, NULL);

loadCCMap ("lower.drawbar16", 70, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar513", 71, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar8", 72, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar4", 73, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar223", 74, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar2", 75, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar135", 76, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar113", 77, NULL, ctrlUseB, NULL);
loadCCMap ("lower.drawbar1", 78, NULL, ctrlUseB, NULL);

loadCCMap ("pedal.drawbar16", 70, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar513", 71, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar8", 72, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar4", 73, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar223", 74, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar2", 75, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar135", 76, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar113", 77, NULL, NULL, ctrlUseC);
loadCCMap ("pedal.drawbar1", 78, NULL, NULL, ctrlUseC);

loadCCMap ("percussion.enable", 80, ctrlUseA, NULL, NULL);
loadCCMap ("percussion.decay", 81, ctrlUseA, NULL, NULL);
loadCCMap ("percussion.harmonic", 82, ctrlUseA, NULL, NULL);

loadCCMap ("vibrato.knob", 83, ctrlUseA, NULL, NULL);
loadCCMap ("vibrato.routing", 92, ctrlUseA, NULL, NULL);

loadCCMap ("whirl.horn.filter.b.type", 85, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.horn.filter.b.hz", 86, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.horn.filter.b.q", 87, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.horn.filter.b.gain", 88, ctrlUseA, NULL, NULL);

loadCCMap ("whirl.comb.a.feedback", 89, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.comb.a.delay", 90, ctrlUseA, NULL, NULL);

loadCCMap ("rotary.speed-select", 91, ctrlUseA, NULL, NULL);

loadCCMap ("overdrive.character", 93, ctrlUseA, NULL, NULL);

loadCCMap ("whirl.comb.b.feedback", 102, ctrlUseA, NULL, NULL);
loadCCMap ("whirl.comb.b.delay", 103, ctrlUseA, NULL, NULL);
}

/*
* Initialises the MIDI file descriptor and loads tables.
*/
int prepareMIDI () {
int timeToWait = 1;
int version;

if ((midi_fd = open (midiDevice, O_RDONLY, 0)) == -1) {
perror (midiDevice);
exit (1);
}

#ifdef COMMENT /* This worked under Red Hat 6.2 but not under Debian */
if (ioctl (midi_fd, SNDCTL_MIDI_PRETIME, & timeToWait) == -1) {
perror ("SNDCTL_MIDI_PRETIME");
exit (1);
}

if (ioctl (midi_fd, OSS_GETVERSION, & version) == -1) {
perror ("OSS_GETVERSION");
exit (1);
}

fprintf (stderr, "MIDI DRIVER VERSION %x\n", version);
#endif /* COMMENT */

/* Load the tables */

loadControllerTable ();
loadKeyTableA ();
loadKeyTableB ();
loadKeyTableC ();
loadStatusTable ();

return 0;
} /* prepareMIDI */

/*
*
*/
void setMIDIDevice (char * s) {
if (s != NULL) {
strncpy (midiDeviceBuffer, s, PATH_MAX);
midiDevice = midiDeviceBuffer;
}
}

/*
* Deprecated and impotent.
*/
void setMIDIChannelSwell (int ch) {

}

/*
* Sets global transpose (for playing in alternate scales).
*/
void setMIDINoteShift (char offset) {
transpose = offset;
loadKeyTableA ();
loadKeyTableB ();
loadKeyTableC ();
}

/*
* This call configures this module.
*/
int midiConfig (ConfigContext * cfg) {
int v;
int ack = 0;
if ((ack = getConfigParameter_ir ("midi.upper.channel",
cfg,
&v,
1, 16)) == 1) {
rcvChA = v - 1;
}
else if ((ack = getConfigParameter_ir ("midi.lower.channel",
cfg,
&v,
1, 16)) == 1) {
rcvChB = v - 1;
}
else if ((ack = getConfigParameter_ir ("midi.pedals.channel",
cfg,
&v,
1, 16)) == 1) {
rcvChC = v - 1;
}
else if ((ack = getConfigParameter_ir ("midi.transpose",
cfg,
&v,
-127, 127)) == 1) {
transpose = v;
}
else if ((ack = getConfigParameter_ir ("midi.upper.transpose",
cfg,
&v,
-127, 127)) == 1) {
nshA = v;
}
else if ((ack = getConfigParameter_ir ("midi.lower.transpose",
cfg,
&v,
-127, 127)) == 1) {
nshB = v;
}
else if ((ack = getConfigParameter_ir ("midi.pedals.transpose",
cfg,
&v,
-127, 127)) == 1) {
nshC = v;
}
else if ((ack = getConfigParameter_ir ("midi.pedals.transpose.split",
cfg,
&v,
-127, 127)) == 1) {
nshA_PL = v;
}
else if ((ack = getConfigParameter_ir ("midi.lower.transpose.split",
cfg,
&v,
-127, 127)) == 1) {
nshA_UL = v;
}
else if ((ack = getConfigParameter_ir ("midi.upper.transpose.split",
cfg,
&v,
-127, 127)) == 1) {
nshA_U = v;
}
else if (strcasecmp (cfg->name, "midi.device") == 0) {
setMIDIDevice (cfg->value);
ack++;
}
/*
* The syntax for this config option is:
* midi.controller.{upper,lower,pedals}.<cc>=<fname>
* where <cc> is a MIDI controller number, and
* <fname> is the symbolic name of a controllable function.
*/
else if (strncasecmp (cfg->name, "midi.controller.", 16) == 0) {
unsigned char * ctrlUse = ctrlUseA;
int ccIdx = 0;
if (strncasecmp ((cfg->name) + 16, "upper", 5) == 0) {
ctrlUse = ctrlUseA;
ccIdx = 22;
}
else if (strncasecmp ((cfg->name) + 16, "lower", 5) == 0) {
ctrlUse = ctrlUseB;
ccIdx = 22;
}
else if (strncasecmp ((cfg->name) + 16, "pedals", 6) == 0) {
ctrlUse = ctrlUseC;
ccIdx = 23;
}
else {
showConfigfileContext (cfg, "directive 'upper', 'lower' or 'pedals' expected");
}

/* If the code above managed to parse a channel name... */
if (0 < ccIdx) {
int ccn;
/* ... and we manage to parse a controller number... */
if (sscanf ((cfg->name) + ccIdx, "%d", &ccn) == 1) {
/* ...and the controller number is in the allowed range... */
if ((0 <= ccn) && (ccn < 128)) {
int i = getCCFunctionId (cfg->value);
if (-1 < i) {
/* Store the controller number indexed by abstract function id */
ctrlUse[i] = ccn;
ack++;
}
else {
/* No match found for symbolic function name. */
showConfigfileContext (cfg,
"name of controllable function not found");
}
}
else {
showConfigfileContext (cfg, "controller number out of range");
}
}
}
}

return ack;
}

/*
*
*/
int closeMIDI () {
(void) close (midi_fd);
return 0;
}

/*
* This is the entry point of the MIDI reader thread.
*/
void * MIDIInReader (void * arg) {
int inBytes;
unsigned char * mbp;
unsigned char * mbpEnd;
int state = stIgnore;

(void) prepareMIDI ();

while (1) {

/* Read the next chunk of waiting MIDI bytes */

if ((inBytes = read (midi_fd,
(void *) inBuffer,
(size_t) BUFFER_SIZE_BYTES)) == -1) {
perror ("read midi_fd");
return NULL;
}

if (inBytes == 0) continue;

/* Point to start and end of input bytes in buffer */

mbp = inBuffer;
mbpEnd = mbp + inBytes;

/* Feed each byte to the parser */

while (mbp < mbpEnd) {

unsigned char B = * mbp++; /* Get next MIDI byte from buffer */

if (IS_SYSTEM_REAL_TIME(B)) {
continue; /* Ignore */
}
else if (IS_STATUS(B)) {
byte1 = B;
state = statusTable.state;
}

switch (state) {

case stNoteOff:
keyTable = (unsigned char *) statusTable.handback;
state = dtaNoteOff1;
break; /* stNoteOff */

case dtaNoteOff1:
byte2 = B; /* Note number */
state = dtaNoteOff2;
break; /* dtaNoteOff1 */

case dtaNoteOff2:
oscKeyOff (keyTable[byte2]); /* B is release velocity */
state = dtaNoteOff1;
break; /* dtaNoteOff2 */

case stNoteOn:
keyTable = (unsigned char *) statusTable.handback;
state = dtaNoteOn1;
break; /* stNoteOn */

case dtaNoteOn1:
byte2 = B; /* Note number */
state = dtaNoteOn2;
break; /* dtaNoteOn1 */

case dtaNoteOn2:
if (0 < B) { /* B is note on velocity */
oscKeyOn (keyTable[byte2]);
} else {
oscKeyOff (keyTable[byte2]); /* Zero velocity on = off */
}
state = dtaNoteOn1;
break; /* dtaNoteOn2 */

case stControlChg:
ctrlvec = (void (**) (unsigned char)) statusTable.handback;
state = dtaControlChg1;
break; /* stControlChg */

case dtaControlChg1:
byte2 = B; /* Controller number */
state = dtaControlChg2;
break; /* dtaControlChg1 */

case dtaControlChg2:
(ctrlvec[byte2])(B); /* B is controller data */
state = dtaControlChg1;
break; /* dtaControlChg2 */

case stProgramChg:
state = dtaProgramChg;
break; /* stProgramChg */

case dtaProgramChg:
installProgram (B); /* B is program number */
state = dtaProgramChg;
break;

case stIgnore:
state = dtaIgnore;
break; /* stIgnore */

case dtaIgnore:
state = dtaIgnore;
break; /* dtaIgnore */

default:
assert (0);
break;

} /* switch state */

} /* while MIDI bytes remain in the input buffer */
} /* while true */
}
Tous ces gens qui n'ont pas de talent...que deviendraient ils, s'il n'existait pas tous ces gens qui n'ont pas de goût (Gilbert Cesbron)

Avatar du membre
bruno micheli
Présentés
Messages : 12247
Enregistré le : jeu. sept. 30, 2004 8:17 am
Localisation : Groland (Mufflin)
Contact :

Message par bruno micheli »

ceci est la dernière implantation midi de beatrix en logiciel libre, vous constaterez qu'elle est de 2004 :)
Tous ces gens qui n'ont pas de talent...que deviendraient ils, s'il n'existait pas tous ces gens qui n'ont pas de goût (Gilbert Cesbron)

Daniel

Message par Daniel »

eh ben Bruno, tu nous avais habitués à de longues tirades, mais là, record battu!!! :D

Avatar du membre
bruno micheli
Présentés
Messages : 12247
Enregistré le : jeu. sept. 30, 2004 8:17 am
Localisation : Groland (Mufflin)
Contact :

Message par bruno micheli »

je me suis laché :) :) :)
Tous ces gens qui n'ont pas de talent...que deviendraient ils, s'il n'existait pas tous ces gens qui n'ont pas de goût (Gilbert Cesbron)

Avatar du membre
MarcGriff
Présentés
Messages : 1085
Enregistré le : jeu. mars 24, 2005 11:53 am
Localisation : Ile de France

Message par MarcGriff »

T'as fait un dump post-mortem de ton cerveau ou quoi ?
B3/L22, A102/L251, E300/L351, PR40 et .....
Un clone MarcGriff pilotant le NI B4 II.
Projet detaillé sur [url]http://hammondcloneorganb4.over-blog.com/[/url]

Avatar du membre
bruno micheli
Présentés
Messages : 12247
Enregistré le : jeu. sept. 30, 2004 8:17 am
Localisation : Groland (Mufflin)
Contact :

Message par bruno micheli »

non :) un copier coller du code source d'une partie du midi
Tous ces gens qui n'ont pas de talent...que deviendraient ils, s'il n'existait pas tous ces gens qui n'ont pas de goût (Gilbert Cesbron)

Avatar du membre
MarcGriff
Présentés
Messages : 1085
Enregistré le : jeu. mars 24, 2005 11:53 am
Localisation : Ile de France

Message par MarcGriff »

Non, sans blague :roll:

:lol: :lol: :lol:
B3/L22, A102/L251, E300/L351, PR40 et .....
Un clone MarcGriff pilotant le NI B4 II.
Projet detaillé sur [url]http://hammondcloneorganb4.over-blog.com/[/url]

Avatar du membre
bruno micheli
Présentés
Messages : 12247
Enregistré le : jeu. sept. 30, 2004 8:17 am
Localisation : Groland (Mufflin)
Contact :

Message par bruno micheli »

j'en ai d'autres si tu veux :) :) :)....de quoi remplir un 3eme forum
Tous ces gens qui n'ont pas de talent...que deviendraient ils, s'il n'existait pas tous ces gens qui n'ont pas de goût (Gilbert Cesbron)

fonte
Présentés
Messages : 5
Enregistré le : ven. juin 08, 2007 6:05 am
Localisation : REUNION

Beatrix Complèment.

Message par fonte »

Bonjour,

J'ai fai le test avec le clavier de commande Evolution MK61 programmable
à volonté et ça marche bien.
Mais attention au réglage trés nombreux- beaucoup de paramètre en l'occurence.*
:D

Répondre