diff --git a/HOWTO b/HOWTO index 37ffeab..61a50aa 100644 --- a/HOWTO +++ b/HOWTO @@ -135,7 +135,7 @@ sudo make install This step need to be run as root as, unless you have been very selective with the ./configure options then parts of bristol will be written to parts of the /usr filesystem which is typically read-only for user accounts. By default this -should install bristol and associated apps to /usr/local/ with data commponets +should install bristol and associated apps to /usr/local/ with data components into /usr/local/share. To run the application you should now be able to use the startBristol script however that does depend on /usr/local/bin being in your path. @@ -201,11 +201,11 @@ Many more options, along with the full list of synths can be found by doing 4. ALSA Interface Configuration To see the MIDI connections that can be built you need to look at aconnect -commmand: +command: aconnect -io -Here is a sammple of its output: +Here is a sample of its output: client 0: 'System' [type=kernel] 0 'Timer ' @@ -263,7 +263,7 @@ audio and midi. 5.1 Using qjackctl -Using qjackctl you can easily connect midi controlloers by clicking on either +Using qjackctl you can easily connect midi controllers by clicking on either the 'Midi' tab or 'Alsa' tab, depending on which midi driver you've selected to use with bristol and then clicking the controller you want on the left pane and the 'Bristol' input on the right and clicking 'connect'. @@ -279,7 +279,7 @@ work in a specific environment gives it flexibility but also makes it sometimes difficult to use. To quote one person, "It can be an inspiration killer". There are a few third party apps such as monoBristol that provide graphical -front ends to the commandline options to make starting bristol easier. Bristol +front ends to the command line options to make starting bristol easier. Bristol itself supports a runcom file where a user can specify common preferred params that are then included with every invocation. @@ -302,7 +302,7 @@ or -jack -jackstats -count 256 -rate 48000 Both of these will have the same affect as they are all summed together. If -bristol is started as 'startBristol -mini' then the actual commmandline will be +bristol is started as 'startBristol -mini' then the actual command line will be startBristol -jack -jackstats -count 256 -rate 48000 -mini @@ -370,15 +370,17 @@ cutoff/resonance, etc. 8.1 Keyboard Mappings. -Bristol supports GUI shortcuts and playing the synths via a QWERTY keyboard. -Playing bristol via the QWERTY on the B3 has C2 starting on '\' and going up +Bristol supports GUI shortcuts and playing the synths with any keyboard. A set of +emulator profile files is provided by default for QWERTY keyboards. + +For alternative keyboards such as AZERTY ones, it is necessary to customize the +emulator profile files (see § 8.3 below). + +Playing bristol with a QWERTY keyboard on the B3 has C2 starting on '\' and going up to F3 on '/' on the bottom manual, while the top manual goes from C4 on Q to G5 on ']'. On a single keyboard synth, such as the polysix, C1 starts on '\' and goes up F2 on '/' and C3 starts on Q and ends at G4 on ']'. -For alternative mappings such as AZERTY it is necessary to manually edit the -emulator profile files. - 8.2 Keyboard Accelerators Useful shortcuts are: @@ -395,7 +397,38 @@ Arrow keys can control pot/slider movement with Shift being an accelerator. The GUI devices also support VI style j/k up/down with Shift and Control options. + 8.3 Customizing profile + +Any keyboard can be used, e.g. AZERTY. But only QWERTY emulator profile files are provided by default. + +A bash script is provided to generate french AZERTY emulator profile files. Run: + + [PROFILE_FILE_NAME=] [PROFILE_SRC_DIR=] azerty4bristol.sh + +The result may not be what you expected. Tune the map with a text editor. + +By default: +- PROFILE_FILE_NAME: mini, +- PROFILE_SRC_DIR: /usr/local/share/bristol/memory/profiles/ (i.e. default bristol manual installation, see § 2.5 above). + +Any key can be used to map a note, even dead keys (e.g. the key "^" between "p" and "$" on +a french azerty keyboard is one of them...) or extended ascii keys. + +The format of key mapping entries is: + KM: Extended_ASCII MIDI_note [MIDI_chan [key_code]] + +To map a dead key, you have to provide: +- Extended_ASCII: an arbitrary extended ASCII code not used on the keyboard or with another dead key, +- key_code: the key code returned by the keyboard on hitting the dead key. + +If any extended ascii character is used then the profile file must be coded in some ISO 8859 encoding scheme(°) +to keep such a character on one byte(°°). + +If the changes are made with an editor, the profile file must be saved with some ISO 8859 encoding scheme(°). + +Note. (°) To avoid any surprise, stay with ISO 8859-1. +Note. (°°) At the moment, bristol doesn't manage characters with C type wchar_t, then is unable to deal with UTF-8. 9. Basics of Subtractive Synthesis. @@ -431,8 +464,8 @@ Low Pass Filter High Pass Band Reject -Low Pass filters remove high frequencies (i.e they pass low freqencies). -High Pass filters remove low freqencies +Low Pass filters remove high frequencies (i.e they pass low frequencies). +High Pass filters remove low frequencies Band Reject filters remove both low and high filters in a specific range and allow a certain 'mid-range' of frequencies through. @@ -443,7 +476,7 @@ Frequency Resonance. Frequency Cutoff allows you to control how much of the sound gets filtered. Resonance amplifies the narrow band of frequencies that are close to the cutoff point. - 9.3.Low Frequency Oscillators (LFOs) + 9.3. Low Frequency Oscillators (LFOs) LFOs are exactly like normal oscillators (they have waveforms, like sine, square and triangle), but they sound below what a human can hear. In this way, diff --git a/brighton/brightonControllers.c b/brighton/brightonControllers.c index 00a8f81..ad37128 100644 --- a/brighton/brightonControllers.c +++ b/brighton/brightonControllers.c @@ -112,7 +112,9 @@ static void brightonMapKeyboard(brightonWindow *bwin, brightonApp *app, int channel, char *param) { - int from, to, chan; + // int from, to, chan; + unsigned char from; + int to, chan, key; from = param[0]; @@ -135,6 +137,17 @@ int channel, char *param) bwin->kbdmap[from][KM_CHAN] = chan; /* printf("Keymap %c to %i on channel %i\n", from, to, chan); */ + if ((param = index(++param, ' ')) == NULL) + { + /* printf("Keymap %c to %i on channel %i\n", from, to, chan); */ + return; + } + + key = atoi(++param); + + addInAndOutKeysToKeymapFilter(key, from, bwin->filter); + /* printf("Keymap %i (%i) to %i on channel %i with key %i\n", + getOutkeyForInkeyFromKeymapFilter(key, bwin->filter), from, to, chan, key); */ } static void @@ -952,6 +965,60 @@ brightonControlKeyInput(brightonWindow *cid, int asckey, int on) * one. For best results we would need to disable key repeat on entering the * window. FFS. */ + +brightonKeymapFilter* +brightonCreateKeymapFilter() +{ + brightonKeymapFilter* filter = malloc(sizeof(brightonKeymapFilter)); + filter->keyin = NULL; + filter->keyout = NULL; + filter->size = 0; + return filter; +} + +int +addInAndOutKeysToKeymapFilter(BRIGHTON_MAP_BASE_TYPE in, BRIGHTON_MAP_BASE_TYPE out, brightonKeymapFilter* filter) +{ + if (!filter) return BRIGHTON_INVALID_KEYMAP_FILTER; + if (in < 0) return BRIGHTON_INVALID_INPUT_KEY; + if (out < 0) return BRIGHTON_INVALID_OUTPUT_KEY; + + filter->size++; + filter->keyin = realloc(filter->keyin, (filter->size) * sizeof(in)); + filter->keyout = realloc(filter->keyout, (filter->size) * sizeof(out)); + filter->keyin[filter->size - 1] = in; + filter->keyout[filter->size - 1] = out; + return filter->size; +} + +BRIGHTON_MAP_BASE_TYPE +getOutkeyForInkeyFromKeymapFilter(BRIGHTON_MAP_BASE_TYPE in, brightonKeymapFilter* filter) +{ + if (!filter || filter->size == 0) return in; + + int i; + for (i = 0; i < filter->size; i++) + { + if (filter->keyin[i] == in) return filter->keyout[i]; + } + return in; +} + +void* +deleteKeymapFilter(brightonKeymapFilter* filter) +{ + free(filter->keyin); + free(filter->keyout); + free(filter); + return NULL; +} + +void* +brightonFreeKeymapFilter(brightonWindow * bwin) +{ + return deleteKeymapFilter(bwin->filter); +} + void brightonKeyInput(brightonWindow *cid, int asckey, int on) { @@ -961,6 +1028,7 @@ brightonKeyInput(brightonWindow *cid, int asckey, int on) event.type = BRIGHTON_FLOAT; event.value = 1.0; + asckey = getOutkeyForInkeyFromKeymapFilter(asckey, cid->filter); if ((asckey < 0) || (asckey > 255)) return; diff --git a/include/brighton/brightoninternals.h b/include/brighton/brightoninternals.h index 2e02ded..4dca32d 100644 --- a/include/brighton/brightoninternals.h +++ b/include/brighton/brightoninternals.h @@ -192,6 +192,17 @@ typedef struct BrightonNRPcontrol { #define BRIGHTON_NRP_COUNT 128 #define BRIGHTON_GANG_COUNT 8 +#define BRIGHTON_MAP_BASE_TYPE int +#define BRIGHTON_INVALID_KEYMAP_FILTER -1 +#define BRIGHTON_INVALID_INPUT_KEY -2 +#define BRIGHTON_INVALID_OUTPUT_KEY -3 +typedef struct BrightonKeymapFilter +{ + BRIGHTON_MAP_BASE_TYPE* keyin; + BRIGHTON_MAP_BASE_TYPE* keyout; + int size; +} brightonKeymapFilter; + typedef struct BrightonWindow { unsigned int flags; struct BrightonWindow *next, *last; @@ -247,6 +258,7 @@ typedef struct BrightonWindow { /* CC value mapping tables */ u_char valuemap[128][128]; int kbdmap[256][2]; + brightonKeymapFilter* filter; int dcTimeout; } brightonWindow; @@ -369,5 +381,8 @@ extern void brightonfree(void *); extern void brightonRegisterController(brightonDevice *); +extern void* brightonFreeKeymapFilter(brightonWindow *); +extern brightonKeymapFilter* brightonCreateKeymapFilter(); + #endif /* BRIGHTONINTERNALS_H */ diff --git a/libbrighton/brightonWindowMgt.c b/libbrighton/brightonWindowMgt.c index 345d35d..3024d5c 100644 --- a/libbrighton/brightonWindowMgt.c +++ b/libbrighton/brightonWindowMgt.c @@ -98,6 +98,8 @@ int cmapsize, int flags, int quality, int gs, int x, int y) bwin->next = winlist; winlist = bwin; + bwin->filter = brightonCreateKeymapFilter(); + /* * Force a fake size to ensure the first configure notify is picked up. */ @@ -145,6 +147,7 @@ brightonDestroyWindow(brightonWindow *bwin) bwin->bitmaps->name); bwin->flags = 0; + brightonFreeKeymapFilter(bwin); brightonfree(bwin); } diff --git a/tools/azerty4bristol.sh b/tools/azerty4bristol.sh new file mode 100755 index 0000000..11f4094 --- /dev/null +++ b/tools/azerty4bristol.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# azerty4bristol.sh +# +# Run: +# [PROFILE_FILE_NAME=] [PROFILE_SRC_DIR=] azerty4bristol.sh +# +# By default: +# - PROFILE_FILE_NAME: mini +# - PROFILE_SRC_DIR: /usr/local/share/bristol/memory/profiles/ (i.e. default bristol manual installation, see HOWTO § 2.5) +# +# If needed, launch this script as sudoer. +# In any case, owner and group will be set up as current user. + +pushd ~/.bristol/memory/profiles/ + +if [ "$PROFILE_FILE_NAME" = "" ] +then + PROFILE_FILE_NAME="mini" +fi +echo "Azerty profile for emulator: $PROFILE_FILE_NAME" + +if [ "$PROFILE_SRC_DIR" = "" ] +then + PROFILE_SRC_DIR="/usr/local/share/bristol/memory/profiles/" +fi +echo "New profile based on: $PROFILE_SRC_DIR/$PROFILE_FILE_NAME" + +[ -e "$PROFILE_FILE_NAME" ] && mv "$PROFILE_FILE_NAME" "${PROFILE_FILE_NAME}.$(date --utc +%Y%m%d_%H%M%SZ)" || true + +install -C -o $USER -g $USER "$PROFILE_SRC_DIR/$PROFILE_FILE_NAME" . + +sed -i 's/\(^# Keyboard map format is "KM: \)\(.*MIDI_chan\)\(.*$\)/\1Extended_\2 [key_code]\3/' "$PROFILE_FILE_NAME" + +sed -i -e '0,/^KM: / {/^KM: /i\KM: * 19 1' -e'}' "$PROFILE_FILE_NAME" +sed -i -e '0,/^KM: / {/^KM: /i\KM: < 0 1' -e'}' "$PROFILE_FILE_NAME" +sed -i -e '0,/^KM: / {/^KM: /i\KM: & 23 0' -e'}' "$PROFILE_FILE_NAME" + +sed -i -e 's/\(^KM: \)0/\1à/' -e 's/\(^KM: \)2/\1é/' -e 's/\(^KM: \)3/\1"/' "$PROFILE_FILE_NAME" +sed -i -e 's/\(^KM: \)5/\1(/' -e 's/\(^KM: \)6/\1-/' -e 's/\(^KM: \)7/\1è/' "$PROFILE_FILE_NAME" +sed -i 's/\(^KM: \)9/\1ç/' "$PROFILE_FILE_NAME" + +sed -i 's/\(^KM: \)\[\(.*\)$/\1Æ\2 65106/' "$PROFILE_FILE_NAME" +sed -i 's/\(^KM: \)\]/\1$/' "$PROFILE_FILE_NAME" + +sed -i -e '/^KM:/ s/q/\[q\]/' -e '/^KM:/ s/a/q/' -e '/^KM:/ s/\[q\]/a/' "$PROFILE_FILE_NAME" +sed -i -e '/^KM:/ s/z/\[z\]/' -e '/^KM:/ s/w/z/' -e '/^KM:/ s/\[z\]/w/' "$PROFILE_FILE_NAME" +sed -i -e '/^KM:/ s/m/\[m\]/' -e '/^KM:/ s/,/\[,\]/' "$PROFILE_FILE_NAME" +sed -i -e '/^KM:/ s/\[m\]/,/' -e '/^KM:/ s/\[,\]/;/' "$PROFILE_FILE_NAME" +sed -i -e '/^KM:/ s|/|!|' -e '/^KM:/ s/\./:/' -e "/^KM:/ s/'/ù/" "$PROFILE_FILE_NAME" + +iconv -f UTF8 -t ISO_8859-1 -o "$PROFILE_FILE_NAME" "$PROFILE_FILE_NAME" + +popd