// Backup Band for Linux
// Copyright 2013 Jeff Glatt
// Backup Band is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Backup Band is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Backup Band. If not, see <http://www.gnu.org/licenses/>.
static const char MusicianNameStrs[] = "Drums\0Bass\0Guitar\0Pad\0Human";
const char * getMusicianName(register unsigned char robotNum)
{
register const char * strs;
strs = MusicianNameStrs;
while (robotNum--)
{
while (*strs++);
}
return strs;
}
#ifndef BB_NO_GUI
#include "Main.h"
#include "Robots.h"
#include "MVerb.h"
#include "Prefs.h"
#include "MidiIn.h"
#include "MidiOut.h"
#include "AccompSeq.h"
#include "AudioPlay.h"
#include "FileLoad.h"
#include "Editor.h"
#include "Setup.h"
#include "SongSheet.h"
#include "StyleData.h"
#include "Version.h"
//======================================================
// SETUP SCREEN
//======================================================
VOIDRETFUNC ReturnFunc;
static unsigned char MusicianAssignChange;
static unsigned char PanelSelect = 0;
//static unsigned char MusicianMuteChange;
static const char GeneralHelpStr[] = "\x13 Flash error\x11 automatically dismisses any error message after 5 seconds. Be sure to enable this \
if you're running BackupBand without a computer keyboard or mouse.\n\n\x13 Clock\x11 offers 3 settings for timing. The faster settings invoke \
less overhead, but may result in the robots playing at an erratic tempo, depending upon your system. Choose the fastest clock that doesn't \
adversely affect the robots' rhythm.\x13 MIDI\x11 clock is used only if you wish to slave BackupBand to some other hardware/software's tempo, \
using MIDI clock messages. You must set the tempo, and start/stop play, from the other device.\n\nIncreasing\x13 Click delay\x11 causes \
BackupBand to be less sensitive to mouse button double-clicks. Adjust this setting if you're using a touchscreen that tends to generate \
false double-clicks, or when using a USB pedal configured as a mouse it does likewise.\n\n\x13 Transpose\x11 transposes the drum, guitar, \
pad, and human solo instruments up/down by half steps. Unlike the Transpose setting in the main screen, the Setup screen's \
transpose is maintained each time you run BackupBand.";
static const char RobotsHelpStr[] = "\x16Instruments Change\x11 determines when the robots' instruments change automatically.\x13 Always\x11 is the default behavior. The \
robots automatically change instruments whenever the style is selected, during play or stopped.\x13 When stopped\x11 changes the instruments only when you change styles with \
playback stopped. Instruments do not change automatically during play. With\x13 Manually\x11, the instruments never change automatically. They change only when you manually change \
them.\x13 Articulations\x11 is like\x13 Manually\x11 except that articulations can change automatically during play. (ie, The guitarist can mute strings on one Variation, and unmute \
on another. But he can't change the instrument itself, for example, change from a Les Paul to a Nylon string. He must play the instrument you manually choose.)\n\n\
When\x13 Autostart\x11 is\x13 On\x11, as soon as you play a chord, the robots all start to play along (assuming you haven't muted/disabled them) \
in the current style. When Autostart is\x13 Off\x11, the drummer does nothing and the bass/guitar strum rubato chords (in time with your chords), \
until you manually start play. Only when you start play do the robots all begin playing in the current style.\x13 Toggle\x11 automatically \
turns on Autostart whenever you select a style (while play is stopped), and then automatically turns it off when play starts. This allows you \
to play rubato chords at the ending of a style without causing play to automatically restart.";
static const char HumanHelpStr[] = "The\x16 Chords Model\x11 determines how you wish to play chords upon your \
controller.\x13 Split Piano\x11 means that you intend to divide your controller's note range into two halves. The bottom half is \
where you will play chords for BackupBand to follow, and the top half is where you can play anything you'd like, such as a \
solo.\x13 One finger\x11 model allows you to play minor or major chords with 1 or 2 fingers (on your controller's bottom half). \
For a major chord, just play the root note. (Play a C note for a C major chord). For a minor chord, add the note a half or whole \
step up. (Play a C note, along with either a Db or D note, for a C minor chord).\x13 Full piano\x11 means you intend to play a \
two-handed freeform part, across the entire note range, and BackupBand should deduce chords from that.\x13 Sensitivity\x11 sets how \
many notes you must simultaneously play before BackupBand will recognize a chord. For example, if Sensitivity is 4, then you must hold \
at least 4 notes simultaneously in order to change the chord.\n\n\x13 Foot (or Bass) pedals\x11 indicates you will play minor or major chords \
on at least a full octave (C to high C) of pedals. For a major chord, just play the root pedal. For a minor chord, play the root pedal, \
simultaneously with the high C pedal. You must set the high C pedal as the\x13 Minor Pedal\x11 note.\n\n\x13 Wind model\x11 uses 2 \
devices. One device is a monophonic controller where you play the root note. The other device is a switch or pedal that you press for \
a minor chord, or release for major. If you use a USB pedal that emulates a mouse, then set\x13 Minor by\x11 to \"Mouse\", and click \
the adjacent button to configure the pedal. If you instead use a pedal that sends MIDI controller, then set\x13 Minor by\x11 to \
\"Controller\", and click the adjacent button to enter the controller number.\n\n\x13 Guitar\x11 model is for a MIDI guitar. \
BackupBand's robot musicians change chord only when you strum a chord on at least 4 strings.\n\n\x13 Drum Pads\x11 model assigns \
a different chord to each midi note number. Alternately you can set\x13 Trigger by\x11 to instead use Aftertouch or Program Change \
numbers. Or you can use one MIDI Controller. See the manual for a chart.\n\n\x13 Change on\x11 determines whether the robots can \
change the chord on the downbeat of every measure, or only the first and third beats.\n\nWhen\x13 Chord Hold\x11 is on, then the \
robots continue playing the chord even after you release the notes on your controller. When off, the bass, guitar, and pad robots play only \
while you're sustaining (holding) the notes of the chord. The drummer continues regardless.\n\nThe\x16 MIDI Controller\x11 section \
is where you set what MIDI device you wish BackupBand's robot musicians to \"follow\" for changing chords, and receiving remote \
commands. Click on the\x13 Device\x11 button to choose one device from a list of external MIDI hardware, or other software programs, \
which BackupBand can follow. Click the Split button, and play the note on your controller where you want to split it into 2 note \
ranges. Note that\x13 Full Piano\x11 and\x13 Guitar\x11 chord models do not need the split note set.\n\nThe\x13 Test\x11 button \
opens a screen that displays information about each MIDI message received from your controller. Also indicated is what BackupBand \
does with that message.\n\nThe\x13 Master Chan\x11 indicates what MIDI channel you will set your controller to play chords upon. This \
channel is also used to control Master settings that affect all robots, such as transpose, tempo, etc. If set it to \"Auto\", then all \
notes from your controller (on any channel) will play chords below the split point. Also, all non-note events will control Master \
settings.\n\nThe\x16 Solo Instrument\x11 section are settings for the upper half of your controller (above the split note). You can \
play any of BackupBand's sampled instruments on its Internal Synth. Or you can set the playback to one of the 4 MIDI choices of software \
synths or external MIDI hardware synths.\x13 Channel\x11 determines which MIDI channel you will set your controller to play the \
\"Solo\" instrument. If the \x13 Master channel\x11 is set to \"Auto\", then the solo channel is ignored, and all notes above the split point \
play the Solo patch.\n\nWhen Master channel is set to to \"Basic\", then this automatically disables the guitar, bass, and \
pad robots (but not the drummer). This is useful if you don't need BackupBand's accompaniment features and instead wish only to use \
BackupBand as a sound module that you yourself play. Note that the Solo Instrument settings still allow you to do splits and layers.";
static const char CommandsHelpStr[] = "Set\x13 Switch Note\x11 only if you want to use a range of notes for issuing commands to BackupBand \
(instead of playing sampled instruments), such as start/stop play, transpose, increase/decrease tempo, etc.";
static const char * HelpStrs[5] = {&GeneralHelpStr[0], &RobotsHelpStr[0], &HumanHelpStr[0], &CommandsHelpStr[0], 0};
static int32_t getPlayDevStr(void *, GUIAPPHANDLE);
static uint32_t set_playdev_assign(register GUICTL_ARROWS *, register uint32_t);
static void updateBussBtns(void);
static void setup_msg_handler(void);
/******************* updateDevice() *******************
* Called by GUI thread when user selects an audio/midi
* device.
*/
static void updateDevice(register SOUNDDEV * sounddev)
{
#if !defined(NO_ALSA_AUDIO_SUPPORT) || !defined(NO_JACK_SUPPORT)
if (!sounddev)
{
#ifndef NO_SAMPLERATE_SUPPORT
setSampleRateCtl(waveSampleRateFactor(0xff));
#endif
sounddev = getNextAudioOutDev(0);
}
#endif
GuiApp->WinInfo.Banner.Text = sounddev->DevName;
if (doPickSoundDevDlg(sounddev))
{
register const char * errmsg;
// Open new dev
if (sounddev->DevFlags & DEVFLAG_INPUTDEV)
{
switch (sounddev->DevType)
{
#ifndef NO_ALSA_AUDIO_SUPPORT
// case DEVTYPE_AUDIO:
// {
// break;
// }
#endif
#if !defined(NO_MIDI_IN_SUPPORT) || !defined(NO_SEQ_IN_SUPPORT)
case DEVTYPE_RAWMIDI:
openMidiIn(sounddev);
break;
#endif
err: show_msgbox(errmsg);
err2: return;
}
}
else switch (sounddev->DevType)
{
#if !defined(NO_ALSA_AUDIO_SUPPORT) || !defined(NO_JACK_SUPPORT)
case DEVTYPE_AUDIO:
{
#ifndef NO_JACK_SUPPORT
if (!sounddev->DevHash)
{
if ((errmsg = open_libjack())) goto err;
}
else
#endif
{
// Get dialog's sample rate in case user changed it
if (setFrameSize(1)) SaveConfigFlag |= SAVECONFIG_OTHER;
}
if (!loadDataSets(LOADFLAG_INSTRUMENTS)) goto err2;
MusicianAssignChange = 0;
allocAudio();
break;
}
#endif
#ifndef NO_MIDI_OUT_SUPPORT
case DEVTYPE_RAWMIDI:
if ((errmsg = openMidiOut(sounddev))) goto err;
break;
#endif
#ifndef NO_SEQ_OUT_SUPPORT
case DEVTYPE_SEQ:
if ((errmsg = openSeqOut(sounddev))) goto err;
#endif
}
SaveConfigFlag |= SAVECONFIG_DEVICES;
}
}
#ifndef NO_ALSA_AUDIO_SUPPORT
/************ doPickAudioOutDev() ************
* Called by GUI thread when user clicks on the
* XRun indication GUICTL (to adjust the audio
* driver settings).
*/
void doPickAudioOutDev(void)
{
updateDevice(0);
showMainScreen();
}
#endif
#if !defined(NO_MIDI_IN_SUPPORT) || !defined(NO_SEQ_IN_SUPPORT)
static uint32_t ctl_set_midi_in(register GUICTL * ctl)
{
updateDevice(getNextMidiInDev(0));
updateBussBtns();
doSetupScreen();
return 0;
}
#endif
#if !defined(NO_ALSA_AUDIO_SUPPORT) || !defined(NO_JACK_SUPPORT)
static uint32_t ctl_set_intsynth_dev(register GUICTL * ctl)
{
updateDevice(0);
updateBussBtns();
doSetupScreen();
return 0;
}
#endif
#if !defined(NO_MIDI_OUT_SUPPORT) || !defined(NO_SEQ_OUT_SUPPORT)
static uint32_t ctl_set_midiout_dev(register GUICTL * ctl)
{
register uint32_t i;
register SOUNDDEV * sounddev;
i = ((((GUICTL_PUSH *)ctl)->Ctl.IdNumber & 0x2f));
sounddev = 0;
while ((sounddev = getNextMidiOutDev(sounddev)))
{
if (!i)
{
updateDevice(sounddev);
break;
}
--i;
}
updateBussBtns();
doSetupScreen();
return 0;
}
#endif
static const char CtlNames[] = {0,'B','a','n','k','S','w',' ','H',0,
1,'M','o','d',' ','H',0,
2,'B','r','e','a','t','h',' ','H',0,
4,'F','o','o','t','P','d',' ','H',0,
5,'P',' ','T','i','m','e',' ','H',0,
6,'D','a','t','a',' ','H',0,
7,'V','o','l','u','m','e',' ','H',0,
8,'B','a','l','a','n','c',' ','H',0,
10,'P','a','n',' ','H',0,
11,'E','x','p','r','e','s',' ','H',0,
12,'E','f','f','c',' ','1',' ','H',0,
13,'E','f','f','c',' ','2',' ','H',0,
16,'G','e','n','e','r','l',' ','1',0,
17,'G','e','n','e','r','l',' ','2',0,
18,'G','e','n','e','r','l',' ','3',0,
19,'G','e','n','e','r','l',' ','4',0,
32,'B','a','n','k','S','w',' ','L',0,
33,'M','o','d',' ','L',0,
34,'B','r','e','a','t','h',' ','L',0,
36,'F','o','o','t','P','d',' ','L',0,
37,'P',' ','T','i','m','e',' ','L',0,
38,'D','a','t','a',' ','L',0,
39,'V','o','l','u','m','e',' ','L',0,
40,'B','a','l','a','n','c',' ','L',0,
42,'P','a','n',' ','L',0,
43,'E','x','p','r','e','s',' ','L',0,
44,'E','f','f','c',' ','1',' ','L',0,
45,'E','f','f','c',' ','2',' ','L',0,
64,'H','o','l','d',' ','P','e','d',0,
65,'P','o','r','t','a',' ','O','n',0,
66,'S','u','s','t','e','n','u','t',0,
67,'S','o','f','t',' ','P','e','d',0,
68,'L','e','g','a','t','o','P','d',0,
69,'H','o','l','d','2','P','e','d',0,
70,'S','n','d',' ','V','a','r','i',0,
71,'T','i','m','b','r','e',0,
72,'R','e','l',' ','T','i','m','e',0,
73,'A','t','k',' ','T','i','m','e',0,
74,'B','r','i','g','h','t','n','s',0,
75,'S','n','d','C','t','l',' ','6',0,
76,'S','n','d','C','t','l',' ','7',0,
77,'S','n','d','C','t','l',' ','8',0,
78,'S','n','d','C','t','l',' ','9',0,
79,'S','n','d','C','t','l','1','0',
80,'G','e','n','e','r','l',' ','5',0,
81,'G','e','n','e','r','l',' ','6',0,
82,'G','e','n','e','r','l',' ','7',0,
83,'G','e','n','e','r','l',' ','8',0,
91,'E','f','f','e','c','t','s',0,
92,'T','r','e','m','u','l','o',0,
93,'C','h','o','r','u','s',0,
94,'C','e','l','e','s','t','e',0,
95,'P','h','a','s','e','r',0,
96,'D','a','t','a',' ','+',0,
97,'D','a','t','a',' ','-',0,
98,'N','R','P','N',' ','L',0,
99,'N','R','P','N',' ','H',0,
100,'R','P','N',' ','L',0,
101,'R','P','N',' ','H',0,
120,'S','o','u','n','d','O','f','f',0,
121,'C','o','n','t','l','O','f','f',0,
122,'L','o','c','a','l','K','e','y',0,
123,'N','o','t','e','s','O','f','f',0,
124,'O','m','n','i',' ','O','f','f',0,
125,'O','m','n','i',' ','O','n',0,
126,'M','o','n','o',' ','O','n',0,
127,'P','o','l','y',' ','O','n',0,
-1};
/********************* getGmCtl() *********************
* Retrieves the General MIDI Controller Name for a
* controller number.
*/
const char * getGmCtl(unsigned char ctlNum)
{
register const char * ptr;
ptr = &CtlNames[0];
while (ctlNum > (unsigned char)ptr[0]) ptr += (strlen(ptr + 1) + 2);
return (ctlNum == (unsigned char)ptr[0] ? ptr + 1 : 0);
}
#ifndef NO_MIDI_IN_SUPPORT
// =========================================================
// Set split, command note, bass octave
// =========================================================
static const char PlayNoteStr[] = "Play the desired key for the split point on your MIDI controller. (Typically the center key.) I'm listening for it...";
static const char PlayPedalStr[] = "Play the desired pedal to change the chord to minor (instead of major). I'm listening for it...";
static void * setNotePoint(register void * signalHandle, register unsigned char * msg)
{
if (msg[0] >= 0x90 && msg[0] <= 0x9F && msg[2])
{
register unsigned char note;
note = msg[1];
if (isNoteAssign())
{
if (note <= (CmdSwitchNote & 0x7f) || note >= (CmdSwitchNote & 0x7f) + 88)
{
#ifdef DEBUG_GUIWINSIGNAL
GuiWinSignal(GuiApp, signalHandle, SIGNALMAIN_CMDSWITCHERR, "setNotePoint");
#else
GuiWinSignal(GuiApp, signalHandle, SIGNALMAIN_CMDSWITCHERR);
#endif
goto ignore;
}
note -= (CmdSwitchNote & 0x7f);
}
// Settings must be saved to disk if done via Setup screen
if (ReturnFunc == &doSetupScreen) SaveConfigFlag |= SAVECONFIG_OTHER;
// Set the note
*BytePtr = note;
// Wake up main thread
#ifdef DEBUG_GUIWINSIGNAL
GuiWinSignal(GuiApp, signalHandle, SIGNALMAIN_MIDIIN, "setNotePoint");
#else
GuiWinSignal(GuiApp, signalHandle, SIGNALMAIN_MIDIIN);
#endif
// Don't siphon any more
return 0;
}
ignore:
// Continue siphoning midi input
return (void *)-1;
}
void endNotePoint(void)
{
setMidiInSiphon(&setNotePoint, 0);
ReturnFunc();
}
static void midinote_msg_handler(void)
{
if (GuiApp->Command == (GUIMSG_TYPE_SERVICE|GUIMSG_ACTION_SIGNAL))
{
if (GuiApp->Signal & SIGNALMAIN_MIDIIN) goto end;
if (GuiApp->Signal & SIGNALMAIN_CMDSWITCHERR)
show_msgbox("You can't assign an action to the note that switches command mode on/off.");
}
else if (GuiMsgIsPresetClick(GuiApp->Command))
{
if (GuiApp->SelectedSubCtl == GUIBTN_DEL) *BytePtr = 128;
end: endNotePoint();
}
}
void doNoteScreen(register const char * title, register unsigned char delFlag)
{
register GUIAPPHANDLE app;
app = GuiApp;
{
register GUIBANNER * hdr;
hdr = (GUIBANNER *)&app->WinInfo.Banner;
hdr->Text = title;
hdr->Color = GUICOLOR_PURPLE;
hdr->Options = GUIDRAW_Y_CENTER;
}
// No other ctls
app->WinInfo.ControlsList = 0;
app->WinInfo.Options = GUIWIN_OPT_SPACE_AS_ENTER|GUIWIN_OPT_TAB_NEXT_CTL|GUIWIN_OPT_ENTER_AS_CLICK|GUIWIN_OPT_ESC_KEY_CANCEL|GUIWIN_OPT_CUSTOM_DRAWING;
// "Cancel" and "Delete" lower preset btns
app->WinInfo.Presets.LowerMask = (delFlag) ? GUIBTN_DEL_SHOW|GUIBTN_CANCEL_SHOW : GUIBTN_CANCEL_SHOW;
GuiMsgFunc = midinote_msg_handler;
init_setup_panel(GUI_WIN_SET_CONTROLS|GUI_WIN_SET_PRESET_LOWER|GUI_WIN_SET_OPTIONS|GUI_WIN_SET_BANNER_TEXT|GUI_WIN_SET_BANNER_COLOR|GUI_WIN_SET_BANNER_OPTIONS);
// Tell Midi In thread to pass each midi msg to setNotePoint()
setMidiInSiphon(&setNotePoint, 1);
}
#endif // NO_MIDI_IN_SUPPORT
// =========================================================
// Human Settings
// =========================================================
/******************** numToPitch() *********************
* Converts a MIDI note number to a note name (ie,
* nul-terminated string). For example, MIDI note number 60
* returns "C 3". Note number 61 returns "C#3", etc. (Note
* "A -2", so the first octave is -2). The
* resulting string is stored in the passed buffer (which should
* be large enough to hold at least 5 characters including nul).
*/
static unsigned char NtnNams[] = {'C',' ','C','#','D',' ','D','#','E',' ','F',' ','F','#','G',' ','G','#','A',' ','A','#','B',' ','C'};
char * numToNoteName(register char * buffer, register unsigned char noteNum)
{
register unsigned char * name;
name = &NtnNams[(noteNum % 12) << 1];
*buffer++ = *name++;
*buffer++ = *name;
if (*name != ' ') *buffer++ = ' ';
return buffer;
}
void numToPitch(void * buffer, unsigned char noteNum)
{
register unsigned char * ptr;
register unsigned char * name;
register unsigned char oct;
// save ptr
ptr = (unsigned char *)buffer;
// Get note name
name = &NtnNams[(noteNum % 12) << 1];
// Get sharp or space char after name
oct = *(name+1);
// Store note name (and incidental)
*(ptr)++ = *name;
if (oct == '#') *(ptr)++ = oct;
// Get octave
if (!(oct = noteNum/12))
{
*(ptr)++ = '-';
*(ptr)++ = '2';
}
else if (oct < 2)
{
*(ptr)++ = '-';
*(ptr)++ = '1';
}
else
*(ptr)++ = 46 + oct;
// Nul-terminate
*ptr = 0;
}
#ifndef NO_MIDI_IN_SUPPORT
static uint32_t ctl_set_split(register GUICTL * ctl)
{
BytePtr = &SplitPoint;
ReturnFunc = &doSetupScreen;
doNoteScreen((AppFlags & APPFLAG_2KEY) ? &PlayPedalStr[0] : &PlayNoteStr[0], 0);
// Not yet done setting this parameter. user must enter data..
return 0;
}
static int32_t getSplitStr(void * appdata, GUIAPPHANDLE app)
{
register unsigned char num;
if (app->Command & GUICMD_GET_STR)
{
num = SplitPoint;
wide: numToPitch((char *)app->Buffer, num);
return 0;
}
if (app->Command & GUICMD_GET_STR_WIDTH)
{
num = 61;
goto wide;
}
return 0;
}
static uint32_t ctl_set_midi_test(register GUICTL * ctl)
{
startMidiTest();
return 0;
}
#endif
// ===================================================
// Human
// ===================================================
#if !defined(NO_MIDI_OUT_SUPPORT) || !defined(NO_SEQ_OUT_SUPPORT)
static const char PlaybackStr[] = "Playback on";
#else
static const char PlaybackStr[] = "Playback";
#endif
#ifndef NO_MIDI_IN_SUPPORT
static const char CModelsStr[] = {'S','p','l','i','t',' ','P','i','a','n','o',0,'F','u','l','l',' ','P','i','a','n','o',0,
'1',' ','F','i','n','g','e','r',0, 'F','o','o','t',' ','P','e','d','a','l','s',0,
'B','r','e','a','t','h','/','W','i','n','d',0,'G','u','i','t','a','r',0,'D','r','u','m','/','P','a','d','s',0};
static const char DrumChordStrs[] = "Note\0Aftertouch\0Controller\0Program";
static const char TriggerByStr[] = "Trigger by";
static const char WindChordStrs[] = "Mouse\0Controller";
static const char MinorByStr[] = "Minor by";
static const char SensitivityStr[] = "Sensitivity";
static unsigned char TempChordTrigger;
static uint32_t ctl_set_chordtrigger(register GUICTL *);
static uint32_t ctl_set_model_triggerby(register GUICTL *);
static int32_t get_chord_vlabel(void *, GUIAPPHANDLE);
static uint32_t ctl_set_chordsens(register GUICTL *);
static uint32_t ctl_update_chordsens(register GUICTL *);
static uint32_t ctl_set_chordmodel(register GUICTL *);
static uint32_t ctl_update_chordmodel(register GUICTL *);
static uint32_t ctl_set_curve(register GUICTL *);
static uint32_t ctl_update_curve(register GUICTL *);
static uint32_t ctl_set_lower_split(register GUICTL *);
static uint32_t ctl_update_lower_split(register GUICTL *);
static uint32_t ctl_set_upper_split(register GUICTL *);
static uint32_t ctl_update_upper_split(register GUICTL *);
static int32_t getBassOctLabel(void *, GUIAPPHANDLE);
static uint32_t ctl_set_low_oct(register GUICTL *);
static uint32_t ctl_set_solo_midichan(register GUICTL *);
static uint32_t ctl_update_solo_midichan(register GUICTL *);
static uint32_t ctl_set_solo_playdev(register GUICTL *);
#endif // NO_MIDI_IN_SUPPORT
static uint32_t ctl_set_bound(register GUICTL *);
static uint32_t ctl_update_bound(register GUICTL *);
static uint32_t ctl_set_chordhold(register GUICTL *);
static uint32_t ctl_update_chordhold(register GUICTL *);;
#define HUMANCTLS &ChordsGroupCtl.Ctl
// =================== Controller
#ifndef NO_MIDI_IN_SUPPORT
static GUI_DEF_PUSH_CMD(SplitNoteCtl, getSplitStr) GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR|DRAW_ON_UPDATE, .NumOfLabels=1, .Ctl.Ptr=&ctl_set_split,
GUI_NO_NEXT_CTL()
static GUI_DEF_LABEL(SplitTextCtl, "Split\nNote:") 0, .NumOfLabels=1, .Ctl.LineNum=-1, GUI_NEXT_CTL(SplitNoteCtl)
#endif
#ifndef NO_QWERTY_PIANO
static uint32_t ctl_set_qwerty(register GUICTL *);
static uint32_t ctl_update_qwerty(register GUICTL *);
static GUICTLFUNCS QwertyFunc = {ctl_update_qwerty, ctl_set_qwerty};
static GUI_DEF_RADIO(QwertyCtl,"Off\0On\0Qwerty Piano") GUICFLAG_LABELBOX, .Ctl.Ptr=&QwertyFunc, .NumOfLabels=2,
#ifndef NO_MIDI_IN_SUPPORT
GUI_NEXT_CTL(SplitTextCtl)
#else
GUI_NO_NEXT_CTL()
#endif
static uint32_t ctl_set_qwerty(register GUICTL * ctl)
{
if (QwertyCtl.Select) AppFlags2 |= APPFLAG2_QWERTYKEYS;
else AppFlags2 &= ~APPFLAG2_QWERTYKEYS;
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_qwerty(register GUICTL * ctl)
{
return ((AppFlags2 & APPFLAG2_QWERTYKEYS) ? 1 : 0);
}
#endif // NO_QWERTY_PIANO
#ifndef NO_MIDI_IN_SUPPORT
static GUI_DEF_PUSH(MidiInTestCtl, "Test") SETFUNC_ONLY_PTR, .NumOfLabels=1, .Ctl.Ptr=&ctl_set_midi_test,
#ifndef NO_QWERTY_PIANO
GUI_NEXT_CTL(QwertyCtl)
#else
GUI_NEXT_CTL(SplitTextCtl)
#endif
static int32_t getMasterChanLabel(void * appdata, GUIAPPHANDLE);
static uint32_t ctl_update_masterchan(register GUICTL *);
static uint32_t ctl_set_masterchan(register GUICTL *);
static uint32_t ctl_update_solo_playdev(register GUICTL *);
static GUICTLFUNCS MasterChanFunc = {ctl_update_masterchan, ctl_set_masterchan};
static GUI_DEF_ARROWS_CMD(MidiInChanCtl, getMasterChanLabel, "Master Chan") 0, .Range.Low=1, .Range.High=18, .Ctl.Ptr=&MasterChanFunc,
GUI_NEXT_CTL(MidiInTestCtl)
static int32_t getMasterChanLabel(void * appdata, GUIAPPHANDLE app)
{
register unsigned char labelNum;
if (app->Command & GUICMD_GET_STR)
{
labelNum = app->StrCount;
if (labelNum > 15)
app->Buffer = (labelNum > 16 ? "Basic" : "Auto");
else
sprintf((char *)app->Buffer, "%u", labelNum + 1);
}
else if (app->Command & GUICMD_GET_STR_WIDTH)
app->Buffer = MidiInChanCtl.Heading;
return 0;
}
static uint32_t ctl_update_masterchan(register GUICTL * ctl)
{
return MasterMidiChan;
}
static uint32_t ctl_set_masterchan(register GUICTL * ctl)
{
MasterMidiChan = GuiApp->ArrowsValue;
return CTLMASK_SETCONFIGSAVE;
}
static GUI_DEF_PUSH(MidiInDevCtl, "Device") SETFUNC_ONLY_PTR, .NumOfLabels=1, .Ctl.Color=GUICOLOR_GRAY | (GUICOLOR_BLACK << 4),
.Ctl.Ptr=&ctl_set_midi_in,
GUI_NEXT_CTL(MidiInChanCtl)
static GUI_DEF_GROUPBOX(MidiInGroupCtl, "Controller", MidiInDevCtl) 0, .Ctl.LineNum=-1, GUI_NO_NEXT_CTL()
//=================== Upper Layer
static uint32_t ctl_set_curve(register GUICTL *);
static uint32_t ctl_update_curve(register GUICTL *);
static GUICTLFUNCS CurveFunc = {ctl_update_curve, ctl_set_curve};
static GUI_DEF_ARROWS(VelCurveCtl, "Normal\0Compress", "Vel Curve") 0, .Ctl.Ptr=&CurveFunc, .Range.High=1, GUI_NO_NEXT_CTL()
static uint32_t ctl_set_curve(register GUICTL * ctl)
{
VelCurve = GuiApp->ArrowsValue;
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_curve(register GUICTL * ctl)
{
return VelCurve;
}
static GUICTLFUNCS UpperFunc = {ctl_update_upper_split, ctl_set_upper_split};
static GUI_DEF_RADIO(UpperLayerCtl, "Off\0Pad\0Upper Layer") GUICFLAG_LABELBOX, .Ctl.Ptr=&UpperFunc, .NumOfLabels=2, .Ctl.LineNum=-1,
GUI_NEXT_CTL(VelCurveCtl)
//=================== Lower Split
static GUI_DEF_PUSH_CMD(OctaveCtl, getBassOctLabel) GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR, .Ctl.Ptr=&ctl_set_low_oct, .NumOfLabels=1
GUI_NO_NEXT_CTL()
static GUI_DEF_LABEL(OctaveTextCtl, "Octave:") 0, .NumOfLabels=1, GUI_NEXT_CTL(OctaveCtl)
static GUICTLFUNCS LowerFunc = {ctl_update_lower_split, ctl_set_lower_split};
static GUI_DEF_RADIO(LowSplitCtl, "Off\0Bass\0Legato Bass\0Drums") 0, .Ctl.Ptr=&LowerFunc, .NumOfLabels=4, GUI_NEXT_CTL(OctaveTextCtl)
static GUI_DEF_GROUPBOX(LowerGroupCtl, "Lower split", LowSplitCtl) 0, .Ctl.LineNum=-1, GUI_NEXT_CTL(UpperLayerCtl)
// ==================== Solo instrument
static GUICTLFUNCS SoloPlayDevFunc = {ctl_update_solo_playdev, ctl_set_solo_playdev};
static GUI_DEF_ARROWS_CMD(SoloDevCtl, getPlayDevStr, PlaybackStr) 0, .Ctl.Ptr=&SoloPlayDevFunc, .Range.High=1, GUI_NEXT_CTL(LowerGroupCtl)
static GUI_DEF_ARROWS(SoloVolCtl, 0, VolStr) GUICFLAG_NOSTRINGS|GUICFLAG_RESERVED, .Ctl.Ptr=(void *)CTLSTR_PATCHVOL, .Range.High=100,
GUI_NEXT_CTL(SoloDevCtl)
static GUICTLFUNCS SoloMidiChanFunc = {ctl_update_solo_midichan, ctl_set_solo_midichan};
static GUI_DEF_ARROWS(SoloMidiChanCtl, 0, "Channel") GUICFLAG_NOSTRINGS, .Ctl.Ptr=&SoloMidiChanFunc, .Range.Low=1, .Range.High=16,
GUI_NEXT_CTL(SoloVolCtl)
static GUI_DEF_GROUPBOX(SoloInsGroupCtl, "Solo instrument", SoloMidiChanCtl) 0, .Ctl.LineNum=-1, GUI_NEXT_CTL(MidiInGroupCtl)
#endif // NO_MIDI_IN_SUPPORT
// ==================== Chords
static GUICTLFUNCS ChordHoldFunc = {ctl_update_chordhold, ctl_set_chordhold};
static GUI_DEF_CHECK(ChordHoldCtl, "Chord Hold") 0, .Ctl.Ptr=&ChordHoldFunc, .NumOfLabels=1,
#if defined(NO_MIDI_IN_SUPPORT) && !defined(NO_QWERTY_PIANO)
GUI_NEXT_CTL(QwertyCtl)
#else
GUI_NO_NEXT_CTL()
#endif
static GUICTLFUNCS ChordBoundFunc = {ctl_update_bound, ctl_set_bound};
static GUI_DEF_ARROWS(ChordBoundCtl, "Every Beat\0Beats 1+3", "Change on") 0, .Ctl.Ptr=&ChordBoundFunc, .Range.High=1,
#ifndef NO_MIDI_IN_SUPPORT
.Ctl.LineNum=-1,
#endif
GUI_NEXT_CTL(ChordHoldCtl)
#ifndef NO_MIDI_IN_SUPPORT
static GUI_DEF_PUSH_CMD(TriggerAssignCtl, get_chord_vlabel) GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR|DRAW_ON_UPDATE,
.Ctl.Ptr=&ctl_set_model_triggerby, .NumOfLabels=1,
GUI_NEXT_CTL(ChordBoundCtl)
static GUI_DEF_LABEL(MinorPedalCtl, "Minor\nPedal:") 0, .NumOfLabels=1, GUI_NO_NEXT_CTL()
// ChordTriggerByCtl and ChordSensCtl are never simultaneously visible,
// so they can be located at the same spot
static GUICTLFUNCS ChordSensFunc = {ctl_update_chordsens, ctl_set_chordsens};
static GUI_DEF_ARROWS(ChordSensCtl, 0, SensitivityStr) GUICFLAG_NOSTRINGS, .Ctl.Ptr=&ChordSensFunc, .Range.High=6, .Range.Low=2, .Value=2,
GUI_NO_NEXT_CTL()
static GUI_DEF_ARROWS(ChordTriggerByCtl, DrumChordStrs, TriggerByStr) SETFUNC_ONLY_PTR, .Ctl.Ptr=&ctl_set_chordtrigger, .Range.High=3,
GUI_NEXT_CTL(TriggerAssignCtl)
static GUICTLFUNCS ChordModelFunc = {ctl_update_chordmodel, ctl_set_chordmodel};
static GUI_DEF_ARROWS(ChordModelCtl, CModelsStr, "Model:") 0, .Ctl.Ptr=&ChordModelFunc, .Range.High=6, GUI_NEXT_CTL(ChordTriggerByCtl)
#endif // NO_MIDI_IN_SUPPORT
#ifndef NO_MIDI_IN_SUPPORT
static GUI_DEF_GROUPBOX(ChordsGroupCtl, "Chords", ChordModelCtl) 0, GUI_NEXT_CTL(SoloInsGroupCtl)
#else
static GUI_DEF_GROUPBOX(ChordsGroupCtl, "Chords", ChordBoundCtl) 0, GUI_NO_NEXT_CTL()
#endif
#ifndef NO_MIDI_IN_SUPPORT
/**************** ctl_set_wndmodel_mousebtn() *********************
* Called when user clicks on the value button for "Wind" or
* "Drum pads" chord models to set Controller #.
*/
// Sets the mouse btn # used by Wind controller chord model's "Minor by"
static uint32_t ctl_set_wndmodel_mousebtn(register GUICTL * ctl)
{
doMouseChordBtn();
SaveConfigFlag |= SAVECONFIG_OTHER;
return 0;
}
static void showChordParams(void)
{
register uint32_t hideFlag;
hideFlag = 0;
// Only Drums and Wind models use ChordTriggerByCtl/MinorBy. Other models will
// either use the Sensitivity ctl, or no other ctl
if (AppFlags & (APPFLAG_DRUMPAD|APPFLAG_WINDCTL))
{
ChordModelCtl.Ctl.Next = &ChordTriggerByCtl.Ctl;
ChordTriggerByCtl.Ctl.Next = &TriggerAssignCtl.Ctl;
TriggerAssignCtl.Ctl.Ptr = ctl_set_model_triggerby;
if (AppFlags & APPFLAG_DRUMPAD)
{
ChordTriggerByCtl.Heading = &TriggerByStr[0];
ChordTriggerByCtl.Ctl.Label = &DrumChordStrs[0];
ChordTriggerByCtl.Range.High=3;
// If "Trigger by" != "Controller" (2), then DON'T show the VALUE button
if (ChordTriggerByCtl.Value != 2) ChordTriggerByCtl.Ctl.Next = &ChordBoundCtl.Ctl;
}
else
{
ChordTriggerByCtl.Heading = &MinorByStr[0];
ChordTriggerByCtl.Ctl.Label = &WindChordStrs[0];
ChordTriggerByCtl.Range.High=2;
if (ChordTriggerByCtl.Value >= 2) ChordTriggerByCtl.Value = 1;
if (!ChordTriggerByCtl.Value) TriggerAssignCtl.Ctl.Ptr = ctl_set_wndmodel_mousebtn;
}
}
// Foot Pedals and 1 Finger don't use Sensitivity
else if (AppFlags & APPFLAG_1FINGER)
ChordModelCtl.Ctl.Next = &ChordBoundCtl.Ctl;
// Foot pedals has a "Minor Pedal" setting
else if (AppFlags & APPFLAG_2KEY)
{
ChordModelCtl.Ctl.Next = &MinorPedalCtl.Ctl;
TriggerAssignCtl.Ctl.Ptr = ctl_set_split;
// Remove "Split Note" ctl
hideFlag = GUICFLAG_HIDE|GUICFLAG_VALUE_CHANGE;
}
// All other models use Sensitivity
else
ChordModelCtl.Ctl.Next = &ChordSensCtl.Ctl;
if ((SplitTextCtl.Ctl.Flags & GUICFLAG_HIDE) != hideFlag)
{
GuiCtlUpdate(GuiApp, MainWin, &SplitTextCtl.Ctl, hideFlag);
GuiCtlUpdate(GuiApp, MainWin, &SplitNoteCtl.Ctl, hideFlag);
}
// Updating the groupbox updates all its ctls
ctl_update_full_ctl(&ChordsGroupCtl.Ctl);
}
static uint32_t ctl_set_chordtrigger(register GUICTL * ctl)
{
showChordParams();
return CTLMASK_SETCONFIGSAVE;
}
/**************** ctl_set_model_triggerby() *********************
* Called when user clicks on the value button for "Wind" or
* "Drum pads" chord models to set a Controller #.
*/
static uint32_t ctl_set_model_triggerby(register GUICTL * ctl)
{
if (!doNumeric("Enter value 0 to 127", 0, 127) && GuiApp->NumpadValue < 128)
{
TempChordTrigger = (unsigned char)GuiApp->NumpadValue;
SaveConfigFlag |= SAVECONFIG_OTHER;
}
// doSetupScreen();
return 0;
}
static int32_t get_chord_vlabel(void * appdata, GUIAPPHANDLE app)
{
if (app->Command & GUICMD_GET_STR)
{
register const char * str;
register char ctlNum;
// Bass pedals has a "Minor Pedal" setting (which sets SplitNote)
if (AppFlags & APPFLAG_2KEY)
{
numToPitch((char *)app->Buffer, SplitPoint);
goto ret0;
}
if ((AppFlags & APPFLAG_WINDCTL) && !ChordTriggerByCtl.Value)
{
app->SelectedSubCtl = 1;
goto ret;
}
ctlNum = TempChordTrigger < 127 ? TempChordTrigger : 64;
sprintf((char *)app->Buffer, "%u", ctlNum);
if ((str = getGmCtl(ctlNum)))
sprintf((char *)app->Buffer + strlen(app->Buffer), " (%s)", str);
}
else if (app->Command & GUICMD_GET_STR_WIDTH)
{
app->SelectedSubCtl = 0;
ret: formatMouseBtnLabel((char *)app->Buffer, 1);
}
ret0:
return 0;
}
static uint32_t ctl_set_chordsens(register GUICTL * ctl)
{
setChordSensitivity(ChordSensCtl.Value + 1);
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_chordsens(register GUICTL * ctl)
{
return setChordSensitivity(0xff) - 1;
}
static uint32_t ctl_set_chordmodel(register GUICTL * ctl)
{
register unsigned char val;
AppFlags &= ~(APPFLAG_2KEY|APPFLAG_1FINGER|APPFLAG_WINDCTL|APPFLAG_GTRCHORD|APPFLAG_FULLKEY|APPFLAG_DRUMPAD);
clearChord(0|GUITHREADID);
if ((val = ChordModelCtl.Value))
AppFlags |= (APPFLAG_FULLKEY << (val - 1));
val = (AppFlags & APPFLAG_GTRCHORD) ? 3 : 1;
if (AppFlags & APPFLAG_FULLKEY) val = 2;
setChordSensitivity(val);
ctl_update_chordsens(&ChordSensCtl.Ctl);
showChordParams();
// Done setting this parameter. Let caller redraw the ctl
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_chordmodel(register GUICTL * ctl)
{
register unsigned char val, flags;
val = 0;
if ((flags = (AppFlags & (APPFLAG_2KEY|APPFLAG_1FINGER|APPFLAG_WINDCTL|APPFLAG_GTRCHORD|APPFLAG_FULLKEY|APPFLAG_DRUMPAD))))
{
flags >>= 1;
do
{
val++;
flags >>= 1;
} while (!(flags & 0x01));
}
ChordModelCtl.Value = val;
showChordParams();
return val;
}
static uint32_t ctl_set_lower_split(register GUICTL * ctl)
{
AppFlags &= ~(APPFLAG_BASS_LEGATO|APPFLAG_BASS_ON);
AppFlags |= LowSplitCtl.Select;
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_lower_split(register GUICTL * ctl)
{
return (AppFlags & (APPFLAG_BASS_LEGATO|APPFLAG_BASS_ON));
}
static uint32_t ctl_set_upper_split(register GUICTL * ctl)
{
AppFlags4 &= ~APPFLAG4_UPPER_PAD;
if (UpperLayerCtl.Select) AppFlags4 |= APPFLAG4_UPPER_PAD;
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_upper_split(register GUICTL * ctl)
{
return (AppFlags4 & APPFLAG4_UPPER_PAD) ? 1 : 0;
}
static int32_t getBassOctLabel(void * appdata, GUIAPPHANDLE app)
{
register char labelNum;
if (app->Command & GUICMD_GET_STR_WIDTH)
{
labelNum = -5;
goto wide;
}
if (app->Command & GUICMD_GET_STR)
{
labelNum = (BassOct - 28) / 12;
wide: sprintf((char *)app->Buffer, "%d", labelNum);
}
return 0;
}
static uint32_t ctl_set_low_oct(register GUICTL * ctl)
{
BytePtr = (unsigned char *)&BassOct;
ReturnFunc = &doSetupScreen;
doNoteScreen("Play the note on your controller where you want the bass low E to sound.", 0);
return 0;
}
static uint32_t ctl_set_solo_midichan(register GUICTL * ctl)
{
RobotInfo[MUSICIAN_SOLO].MidiChan = SoloMidiChanCtl.Value;
updChansInUse();
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_solo_midichan(register GUICTL * ctl)
{
return RobotInfo[MUSICIAN_SOLO].MidiChan;
}
#endif
static uint32_t ctl_set_bound(register GUICTL * ctl)
{
ChordBoundary = (ChordBoundCtl.Value ? 24*2 : 24);
// Done setting this parameter. Let caller redraw the ctl
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_bound(register GUICTL * ctl)
{
return ChordBoundary != 24;
}
static uint32_t ctl_set_chordhold(register GUICTL * ctl)
{
AppFlags4 &= ~APPFLAG4_NOCHORDHOLD;
if (!ChordHoldCtl.SelectMask) AppFlags |= APPFLAG4_NOCHORDHOLD;
return clearChord(2|GUITHREADID) | CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_chordhold(register GUICTL * ctl)
{
return (AppFlags4 & APPFLAG4_NOCHORDHOLD) ? 0 : 1;
}
// =============================================================
// General settings
// =============================================================
static GUI_DEF_LABEL(VersionCtl, VERSIONSTRING) GUICFLAG_SMALLTEXT,
.NumOfLabels=1
GUI_NO_NEXT_CTL()
static uint32_t ctl_update_flash(register GUICTL *);
static uint32_t ctl_set_flash(register GUICTL *);
static GUICTLFUNCS FlashFunc = {ctl_update_flash, ctl_set_flash};
static GUI_DEF_CHECK(FlashErrCtl, "Flash error") 0, .Ctl.Ptr=&FlashFunc, .NumOfLabels=1, GUI_NEXT_CTL(VersionCtl)
static uint32_t ctl_update_flash(register GUICTL * ctl)
{
return (AppFlags2 & APPFLAG2_TIMED_ERR) ? 1 : 0;
}
static uint32_t ctl_set_flash(register GUICTL * ctl)
{
AppFlags2 &= ~APPFLAG2_TIMED_ERR;
if (FlashErrCtl.SelectMask) AppFlags2 |= APPFLAG2_TIMED_ERR;
// Done setting this parameter. Let caller redraw the ctl
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_click(register GUICTL *);
static uint32_t ctl_set_click(register GUICTL *);
static GUICTLFUNCS ClickFunc = {ctl_update_click, ctl_set_click};
static GUI_DEF_ARROWS(ClickDelayCtl, 0, "Click delay") GUICFLAG_NOSTRINGS,
.Ctl.LineNum=-1,
.Ctl.Ptr=&ClickFunc,
.Range.High=255, .Range.Low=1, .Value=GUI_CLICKDELAY,
GUI_NEXT_CTL(FlashErrCtl)
static uint32_t ctl_update_click(register GUICTL * ctl)
{
return GuiApp->ClickDelay;
}
static uint32_t ctl_set_click(register GUICTL * ctl)
{
GuiApp->ClickDelay = (unsigned char)ClickDelayCtl.Value;
// Done setting this parameter. Let caller redraw the ctl
return CTLMASK_SETCONFIGSAVE;
}
unsigned char get_click_delay(void)
{
return (unsigned char)ClickDelayCtl.Value;
}
void set_click_delay(register unsigned char val)
{
ClickDelayCtl.Value = val;
ctl_set_click(0);
}
// ================= Reverb
#ifndef NO_REVERB_SUPPORT
static uint32_t ctl_set_revparam(register GUICTL * ctl)
{
setReverbParam(((GUICTL_ARROWS *)ctl)->Value, 0x00000001 << ctl->IdNumber);
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_get_revparam(register GUICTL * ctl)
{
return getReverbParam(0x00000001 << ctl->IdNumber);
}
static GUICTLFUNCS ReverbParamFuncs = {&ctl_get_revparam, &ctl_set_revparam};
static GUI_DEF_ARROWS(RevDampingCtl, 0, "Damping Freq") GUICFLAG_NOSTRINGS,
.Range.High=100,
.Ctl.IdNumber = REVPARAM_DAMPINGFREQ,
.Ctl.Ptr=&ReverbParamFuncs,
GUI_NO_NEXT_CTL()
static GUI_DEF_ARROWS(RevPreDelayCtl,0,"Pre-Delay") GUICFLAG_NOSTRINGS, .Range.High=100,
.Ctl.Ptr=&ReverbParamFuncs,
.Ctl.IdNumber = REVPARAM_PREDELAY,
GUI_NEXT_CTL(RevDampingCtl)
static GUI_DEF_ARROWS(RevDecayCtl, 0, "Decay") GUICFLAG_NOSTRINGS, .Range.High=100,
.Ctl.LineNum=-1,
.Ctl.Ptr=&ReverbParamFuncs,
.Ctl.IdNumber = REVPARAM_DECAY,
GUI_NEXT_CTL(RevPreDelayCtl)
static GUI_DEF_ARROWS(RevEarlyCtl, 0, "Early reflect") GUICFLAG_NOSTRINGS, .Range.High=100,
.Ctl.Ptr=&ReverbParamFuncs,
.Ctl.IdNumber = REVPARAM_EARLYLATE,
GUI_NEXT_CTL(RevDecayCtl)
static GUI_DEF_ARROWS(RevSizeCtl, 0, "Room Size") GUICFLAG_NOSTRINGS, .Range.High=100,
.Ctl.Ptr=&ReverbParamFuncs,
.Ctl.IdNumber = REVPARAM_SIZE,
GUI_NEXT_CTL(RevEarlyCtl)
static GUI_DEF_ARROWS(RevVolCtl, 0, VolStr) GUICFLAG_RESERVED|GUICFLAG_NOSTRINGS, .Range.High=100,
.Ctl.Ptr=(void *)CTLSTR_REVERBVOL,
.Ctl.IdNumber = REVPARAM_REVLEVEL,
GUI_NEXT_CTL(RevSizeCtl)
static GUI_DEF_CHECK(RevOnCtl, "Enable") GUICFLAG_RESERVED,
.Ctl.Ptr=(void *)CTLSTR_REVERBMUTE,
.NumOfLabels=1,
.SelectMask=1,
GUI_NEXT_CTL(RevVolCtl)
static GUI_DEF_GROUPBOX(RevGroupCtl, ReverbStr, RevOnCtl) 0, .Ctl.LineNum=-1, GUI_NEXT_CTL(ClickDelayCtl)
#endif
// ================= Flash Err, Clock
static uint32_t ctl_update_clock(register GUICTL *);
static uint32_t ctl_set_clock(register GUICTL *);
static GUICTLFUNCS ClockFunc = {ctl_update_clock, ctl_set_clock};
#ifndef NO_MIDICLOCK_IN
static GUI_DEF_ARROWS(ClockSrcCtl, "Normal\0Fast\0Fastest\0MIDI", "Clock") 0,
#else
static GUI_DEF_ARROWS(ClockSrcCtl, "Normal\0Fast\0Fastest", "Clock") 0,
#endif
#ifndef NO_MIDICLOCK_IN
.Range.High=3,
#else
.Range.High=2,
#endif
.Ctl.Ptr=&ClockFunc,
#ifndef NO_REVERB_SUPPORT
GUI_NEXT_CTL(RevGroupCtl)
#else
GUI_NEXT_CTL(ClickDelayCtl)
#endif
static uint32_t ctl_update_clock(register GUICTL * ctl)
{
return (AppFlags2 & APPFLAG2_CLOCKMASK);
}
static uint32_t ctl_set_clock(register GUICTL * ctl)
{
AppFlags2 = (AppFlags2 & ~APPFLAG2_CLOCKMASK) | ClockSrcCtl.Value;
set_clock_type();
// Done setting this parameter. Let caller redraw the ctl
return CTLMASK_SETCONFIGSAVE;
}
// ================= Master
static GUI_DEF_ARROWS(MasterTransposeCtl, &TransStr[10], TransStr) GUICFLAG_RESERVED,
.Ctl.Ptr=(void *)CTLSTR_TRANSPOSE,
.Range.High=9,
GUI_NO_NEXT_CTL()
static GUI_DEF_ARROWS(MasterVolCtl, 0, VolStr) GUICFLAG_RESERVED|GUICFLAG_NOSTRINGS,
.Ctl.IdNumber=15,
.Ctl.Ptr=(void *)CTLSTR_MASTERVOL,
.Range.High=100,
GUI_NEXT_CTL(MasterTransposeCtl)
static GUI_DEF_GROUPBOX(MasterGroupCtl, "Master", MasterVolCtl) 0, .Ctl.LineNum=-1, GUI_NEXT_CTL(ClockSrcCtl)
// ================= Playback Devs
#if !defined(NO_MIDI_OUT_SUPPORT) || !defined(NO_SEQ_OUT_SUPPORT)
static GUI_DEF_PUSH(MidiOutDev4Ctl, "External\nSynth 4") GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR,
.Ctl.IdNumber=3,
.Ctl.Ptr=&ctl_set_midiout_dev,
.NumOfLabels=1
GUI_NO_NEXT_CTL()
static GUI_DEF_PUSH(MidiOutDev3Ctl, "External\nSynth 3") GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR,
.Ctl.IdNumber=2,
.Ctl.Ptr=&ctl_set_midiout_dev,
.NumOfLabels=1,
GUI_NEXT_CTL(MidiOutDev4Ctl)
static GUI_DEF_PUSH(MidiOutDev2Ctl, "External\nSynth 2") GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR,
.Ctl.IdNumber=1,
.Ctl.Ptr=&ctl_set_midiout_dev,
.NumOfLabels=1,
GUI_NEXT_CTL(MidiOutDev3Ctl)
static GUI_DEF_PUSH(MidiOutDev1Ctl, "External\nSynth 1") SETFUNC_ONLY_PTR,
.Ctl.Ptr=&ctl_set_midiout_dev,
.NumOfLabels=1,
GUI_NEXT_CTL(MidiOutDev2Ctl)
#endif
#if !defined(NO_ALSA_AUDIO_SUPPORT) || !defined(NO_JACK_SUPPORT)
#if defined(NO_MIDI_OUT_SUPPORT) && defined(NO_SEQ_OUT_SUPPORT)
#define GLOBALCTLS &IntSynthTextCtl.Ctl
static GUI_DEF_PUSH(IntSynthCtl, "Playback\nDevice") GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR,
.Ctl.Ptr=&ctl_set_intsynth_dev,
.NumOfLabels=1,
GUI_NEXT_CTL(MasterGroupCtl)
static GUI_DEF_LABEL(IntSynthTextCtl, "Internal Synth:") 0,
.NumOfLabels=1,
GUI_NEXT_CTL(IntSynthCtl)
#else
static GUI_DEF_PUSH(IntSynthCtl, "Internal\nSynth") GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR,
.Ctl.Ptr=&ctl_set_intsynth_dev,
.NumOfLabels=1,
GUI_NEXT_CTL(MidiOutDev1Ctl)
#define GLOBALCTLS &PlayDevGroupCtl.Ctl
#if defined(NO_ALSA_AUDIO_SUPPORT) && defined(NO_JACK_SUPPORT)
#define PLAYDEV1CTL MidiOutDev1Ctl
#else
#define PLAYDEV1CTL IntSynthCtl
#endif
static GUI_DEF_GROUPBOX(PlayDevGroupCtl, "Playback Devices", PLAYDEV1CTL) 0, GUI_NEXT_CTL(MasterGroupCtl)
#endif
#endif
static void updateBussBtns(void)
{
register GUICTL * ctl;
register SOUNDDEV * sounddev;
register unsigned char color, flag;
flag = 0;
#if !defined(NO_ALSA_AUDIO_SUPPORT) || !defined(NO_JACK_SUPPORT)
sounddev = getNextAudioOutDev(0);
color = (sounddev->Handle && sounddev->DevType) ? GUICOLOR_LIGHTBLUE | (GUICOLOR_BLACK << 4) : GUICOLOR_GRAY | (GUICOLOR_BLACK << 4);
if (IntSynthCtl.Ctl.Color != color)
{
flag = 1;
IntSynthCtl.Ctl.Color = color;
}
#endif
#if !defined(NO_SEQ_IN_SUPPORT) && !defined(NO_MIDI_IN_SUPPORT)
sounddev = getNextMidiInDev(0);
color = (sounddev->Handle && sounddev->DevType) ? GUICOLOR_LIGHTBLUE | (GUICOLOR_BLACK << 4) : GUICOLOR_GRAY | (GUICOLOR_BLACK << 4);
if (MidiInDevCtl.Ctl.Color != color)
{
flag = 1;
MidiInDevCtl.Ctl.Color = color;
}
#endif
#if !defined(NO_SEQ_OUT_SUPPORT) && !defined(NO_MIDI_OUT_SUPPORT)
sounddev = 0;
ctl = &MidiOutDev1Ctl.Ctl;
while (ctl && /* ctl->Ptr == &MidiOutFunc && */ (sounddev = getNextMidiOutDev(sounddev)))
{
color = (sounddev->Handle && sounddev->DevType) ? GUICOLOR_LIGHTBLUE | (GUICOLOR_BLACK << 4) : GUICOLOR_GRAY | (GUICOLOR_BLACK << 4);
if (ctl->Color != color)
{
flag <<= 1;
flag |= 1;
ctl->Color = color;
}
ctl = ctl->Next;
}
#endif
if (flag) clearMainWindow();
}
#ifndef NO_REVERB_SUPPORT
void updateReverbCtls(void)
{
if (APPFLAG3_NOREVERB & AppFlags3)
{
// if (!RevOnCtl.Ctl.Next) goto out;
RevOnCtl.SelectMask = 0;
RevOnCtl.Ctl.Next = 0;
}
else
{
register GUICTL * ctl;
RevOnCtl.SelectMask = 1;
// if (RevOnCtl.Ctl.Next) goto out;
RevOnCtl.Ctl.Next = ctl = &RevVolCtl.Ctl;
do
{
ctl_get_revparam(ctl);
} while ((ctl = ctl->Next));
}
ctl_update_full_ctl(&RevGroupCtl.Ctl);
}
#endif
// ===================================================
// Commands
// ===================================================
static uint32_t actionsListFunc(register GUICTL *);
#ifndef NO_MIDI_IN_SUPPORT
static void update_cmd_ctls(void);
#endif
#ifndef NO_MIDI_IN_SUPPORT
static const char CmdNoteStr1[] = "Play the key that will switch into command mode. (Typically, the lowest note.) Or click delete to disable command mode.";
static const char CmdNoteStr2[] = "Play the key that will split your controller between chords and commands. (Typically, the center note.) Or click delete to disable command mode.";
uint32_t ctl_set_cmd_switch(register GUICTL * ctl)
{
BytePtr = &CmdSwitchNote;
ReturnFunc = &enterSetupScreen;
doNoteScreen((MasterMidiChan > 15 ? &CmdNoteStr1[0] : &CmdNoteStr2[0]), 1);
return 0;
}
static int32_t getCmdSwitchStr(void * appdata, GUIAPPHANDLE app)
{
register unsigned char labelNum;
if (app->Command & GUICMD_GET_STR_WIDTH)
{
labelNum = 61;
goto wide;
}
if (app->Command & GUICMD_GET_STR)
{
labelNum = CmdSwitchNote;
if (labelNum > 127)
app->Buffer = "Off";
else
wide: numToPitch((char *)app->Buffer, labelNum);
}
return 0;
}
#endif
static GUI_DEF_LIST(ActionsCtl, drawActionsList) GUICFLAG_SMALLTEXT|SETFUNC_ONLY_PTR,
.Ctl.LineNum=-1,
.Ctl.Ptr=&actionsListFunc,
GUI_NO_NEXT_CTL()
static uint32_t ctl_set_erase1(register GUICTL * ctl)
{
eraseSelAction();
return 0;
}
#ifndef NO_MIDI_IN_SUPPORT
// ===========================
// -----------------------------
// Command menu bar on/off
static uint32_t ctl_update_cmd_always(register GUICTL *);
static uint32_t ctl_set_cmd_always(register GUICTL *);
static GUICTLFUNCS CmdOnFunc = {ctl_update_cmd_always, ctl_set_cmd_always};
static GUI_DEF_CHECK(AlwaysOnCtl, "Always on") GUICFLAG_SMALLTEXT,
.Ctl.Ptr=&CmdOnFunc,
.NumOfLabels=1
GUI_NO_NEXT_CTL()
static uint32_t ctl_update_cmd_always(register GUICTL * ctl)
{
return (AppFlags4 & APPFLAG4_CMD_ALWAYS_ON) ? 1 : 0;
}
static uint32_t ctl_set_cmd_always(register GUICTL * ctl)
{
AppFlags4 &= ~APPFLAG4_CMD_ALWAYS_ON;
if (AlwaysOnCtl.SelectMask) AppFlags4 |= APPFLAG4_CMD_ALWAYS_ON;
endCmdMode();
return CTLMASK_SETCONFIGSAVE;
}
// --------------------------
// Tool tips
static uint32_t ctl_update_tooltips(register GUICTL *);
static uint32_t ctl_set_tooltips(register GUICTL *);
static GUICTLFUNCS TooltipsFunc = {ctl_update_tooltips, ctl_set_tooltips};
static GUI_DEF_CHECK(TooltipsCtl, "Statusbar") GUICFLAG_SMALLTEXT|GUICFLAG_OFF_AS_ON,
.Ctl.Ptr=&TooltipsFunc,
.NumOfLabels=1,
.Ctl.Next = &AlwaysOnCtl.Ctl
};
static uint32_t ctl_update_tooltips(register GUICTL * ctl)
{
return (AppFlags4 & APPFLAG4_CMD_NOSTATUSBAR) ? 1 : 0;
}
static uint32_t ctl_set_tooltips(register GUICTL * ctl)
{
AppFlags4 &= ~APPFLAG4_CMD_NOSTATUSBAR;
if (TooltipsCtl.SelectMask) AppFlags4 |= APPFLAG4_CMD_NOSTATUSBAR;
return CTLMASK_SETCONFIGSAVE;
}
// --------------------------
// Set Command note
static GUI_DEF_PUSH_CMD(CmdSwitchCtl, getCmdSwitchStr) GUICFLAG_NOPADDING|GUICFLAG_SMALLTEXT|SETFUNC_ONLY_PTR|DRAW_ON_UPDATE,
.Ctl.Ptr=&ctl_set_cmd_switch,
.NumOfLabels=1,
GUI_NEXT_CTL(TooltipsCtl)
static GUI_DEF_LABEL(SwitchNoteTextCtl, "Switch\nNote:") 0,
.NumOfLabels=1,
GUI_NEXT_CTL(CmdSwitchCtl)
static GUI_DEF_GROUPBOX(CmdGroupCtl, "Command notes", SwitchNoteTextCtl) 0,
.Ctl.LineNum=-1,
GUI_NEXT_CTL(ActionsCtl)
#endif
static GUI_DEF_PUSH(RemAssignCtl, "Remove\nAssignment") GUICFLAG_NOPADDING|SETFUNC_ONLY_PTR,
.Ctl.LineNum=-1,
.Ctl.Ptr=&ctl_set_erase1,
.NumOfLabels=1,
#ifndef NO_MIDI_IN_SUPPORT
GUI_NEXT_CTL(CmdGroupCtl)
#else
GUI_NEXT_CTL(ActionsCtl)
#endif
static GUI_DEF_LABEL(AssignedToCtl, "Assigned:") GUICFLAG_SMALLTEXT,
.NumOfLabels=1,
GUI_NEXT_CTL(RemAssignCtl)
static uint32_t ctl_update_list_asn(register GUICTL *);
static uint32_t ctl_set_list_asn(register GUICTL *);
static GUICTLFUNCS AsnListFunc = {ctl_update_list_asn, ctl_set_list_asn};
#ifndef NO_MIDI_IN_SUPPORT
static GUI_DEF_RADIO(CmdCategoryCtl, "Mouse Button\0PC Key\0Midi Knob\0Midi Note\0Assign action to") GUICFLAG_LABELBOX|GUICFLAG_SMALLTEXT,
.NumOfLabels=4,
#else
static GUI_DEF_RADIO(CmdCategoryCtl, "Mouse Button\0PC Key\0Assign action to") GUICFLAG_LABELBOX|GUICFLAG_SMALLTEXT,
.NumOfLabels=2,
#endif
.Ctl.Ptr=&AsnListFunc,
GUI_NEXT_CTL(AssignedToCtl)
static uint32_t ctl_update_list_asn(register GUICTL * ctl)
{
return CmdCategoryCtl.Select;
}
static uint32_t ctl_set_list_asn(register GUICTL * ctl)
{
chooseActionsList(CmdCategoryCtl.Select);
resetActionsList(&ActionsCtl);
#ifndef NO_MIDI_IN_SUPPORT
update_cmd_ctls();
#endif
// GuiApp->Command = GUIMSG_ACTION_CLICK;
actionsListFunc(&ActionsCtl.Ctl);
ctl_update_full_ctl(&ActionsCtl.Ctl);
return 1;
}
#define CMDCTLS &CmdCategoryCtl.Ctl
static unsigned char AsnFlags;
static void draw_helpbox(void)
{
if (GuiApp->DrawFlags & GUIWFLAG_DRAW_CUSTOM)
{
GUIBOX box;
register unsigned char flags;
flags = AsnFlags;
// Clear the area where we display the assignment. We
// don't need to do this if the entire win is already erased
box.Left = AssignedToCtl.Ctl.X + AssignedToCtl.Ctl.Width + GuiGetMetric(GuiApp, GUIMETRIC_XSPACE);
box.Right = GuiApp->DrawParams.FreeArea.Width;
box.Top = AssignedToCtl.Ctl.Y + GuiApp->DrawParams.FreeArea.Top;
box.Bottom = box.Top + AssignedToCtl.Ctl.Height;
if ((flags & 0x01) && !(GuiApp->DrawFlags & GUIWFLAG_DRAW_BACKGROUND))
GuiWinRect(GuiApp, &box, GUIRECT_USE_RIGHT_BOTTOM);
GuiTextSetColor(GuiApp, GUICOLOR_BLACK);
GuiTextSetSmall(GuiApp, MainWin);
AsnFlags = (drawActionAssign(box.X, box.Y) ? 0x01 : 0x00);
// Do the same for help description
box.Top = box.Bottom;
box.Left = AssignedToCtl.Ctl.X;
box.Bottom = ActionsCtl.Ctl.Y - GuiGetMetric(GuiApp, GUIMETRIC_LINEHEIGHT) + AssignedToCtl.Ctl.Height;
if ((flags & 0x02) && !(GuiApp->DrawFlags & GUIWFLAG_DRAW_BACKGROUND))
GuiWinRect(GuiApp, &box, GUIRECT_USE_RIGHT_BOTTOM);
if (makeAsnHelpStr())
{
AsnFlags |= 0x02;
GuiTextDrawMsg(GuiApp, (char *)TempBuffer, &box, GUICOLOR_VIOLET|GUIDRAW_SMALLTEXT);
}
}
}
/**************** actionsListFunc() *******************
* Called by cmdasn_msg_handler() to handle a mouse
* event upon the Actions List control.
*/
static uint32_t actionsListFunc(register GUICTL * ctl)
{
register uint32_t cmd;
cmd = GuiApp->Command;
if (GuiMsgIsValueChange(cmd))
{
// Make sure user didn't click on a category
checkForCatSelection();
// Cause draw_helpbox() to be called upon next window draw
GuiWinUpdate(GuiApp, MainWin, GUIWFLAG_DRAW_CUSTOM);
}
if (GuiMsgActionIs(cmd, GUIMSG_ACTION_LIST_DONE))
{
switch (CmdCategoryCtl.Select)
{
#ifndef NO_MIDI_IN_SUPPORT
case 3:
doMidiNoteAsn();
break;
case 2:
doMidiMsgAsn();
break;
#endif
case 1:
doPcKeyAsn();
break;
case 0:
doMouseBtnAsn();
}
}
return CTLMASK_NONE;
}
#ifndef NO_MIDI_IN_SUPPORT
static void update_cmd_ctls(void)
{
// Hide the "Command Note" related controls if user not displaying Command note listing
if (CmdCategoryCtl.Select == 3)
{
if (RemAssignCtl.Ctl.Next != &CmdGroupCtl.Ctl)
{
RemAssignCtl.Ctl.Next = &CmdGroupCtl.Ctl;
upd: clearMainWindowNoSize();
}
}
else if (RemAssignCtl.Ctl.Next == &CmdGroupCtl.Ctl)
{
RemAssignCtl.Ctl.Next = &ActionsCtl.Ctl;
goto upd;
}
}
#endif
static void cmdasn_msg_handler(void)
{
if (GuiApp->Command == (GUIMSG_TYPE_WINDOW|GUIMSG_ACTION_WINDOW_DRAW))
draw_helpbox();
// One of the preset btns
else
setup_msg_handler();
}
// ============================================================
// Robots settings
// ============================================================
static uint32_t ctl_set_polarity(register GUICTL *);
static uint32_t ctl_update_patch_chg(register GUICTL *);
static uint32_t ctl_set_patch_chg(register GUICTL *);
static uint32_t set_playdev_assign(register GUICTL_ARROWS *, register uint32_t);
static uint32_t ctl_set_robot_playdev(register GUICTL *);
static uint32_t ctl_update_robot_playdev(register GUICTL *);
static uint32_t ctl_set_robot_midichan(register GUICTL *);
static uint32_t ctl_update_robot_midichan(register GUICTL *);
static uint32_t ctl_set_CurrentRobot(register GUICTL *);
static uint32_t ctl_set_robot_mute(register GUICTL *);
static uint32_t ctl_update_robot_mute(register GUICTL *);
static uint32_t ctl_update_autostart(register GUICTL *);
static uint32_t ctl_set_autostart(register GUICTL *);
static uint32_t ctl_update_polarity(register GUICTL *);
static GUICTLFUNCS PatchChgFunc = {ctl_update_patch_chg, ctl_set_patch_chg};
static GUICTLFUNCS AutostartFunc = {ctl_update_autostart, ctl_set_autostart};
static GUICTLFUNCS HHPolFunc = {ctl_update_polarity, ctl_set_polarity};
static GUICTLFUNCS RobotMuteFunc = {ctl_update_robot_mute, ctl_set_robot_mute};
static GUICTLFUNCS RobotPlayDevFunc = {ctl_update_robot_playdev, ctl_set_robot_playdev};
static GUICTLFUNCS RobotMidiChanFunc = {ctl_update_robot_midichan, ctl_set_robot_midichan};
// ==================Individual robot settings
static GUI_DEF_RADIO(PolarityCtl, "Pos\0Neg\0HiHat Polarity") GUICFLAG_LABELBOX,
.Ctl.Ptr=&HHPolFunc,
.NumOfLabels=2
GUI_NO_NEXT_CTL()
static GUI_DEF_ARROWS_CMD(RobotDevCtl, getPlayDevStr, PlaybackStr) 0,
.Ctl.LineNum=-1,
.Ctl.Ptr=&RobotPlayDevFunc,
.Range.High=1,
GUI_NEXT_CTL(PolarityCtl)
static GUI_DEF_ARROWS(RobotVolCtl,0, VolStr) GUICFLAG_NOSTRINGS|GUICFLAG_RESERVED,
.Ctl.Ptr=(void *)CTLSTR_DRUMVOL,
.Range.High=100,
GUI_NEXT_CTL(RobotDevCtl)
static GUI_DEF_CHECK(RobotMuteCtl, "Mute robot") 0,
.Ctl.Ptr=&RobotMuteFunc,
.NumOfLabels=1,
GUI_NEXT_CTL(RobotVolCtl)
static GUI_DEF_ARROWS(RobotChanCtl, 0, "Channel") GUICFLAG_NOSTRINGS,
.Ctl.LineNum=-1,
.Ctl.Ptr=&RobotMidiChanFunc,
.Range.Low=1, .Range.High=16,
GUI_NEXT_CTL(RobotMuteCtl)
static GUI_DEF_RADIO(RobotNameCtl, MusicianNameStrs) SETFUNC_ONLY_PTR,
.Ctl.Ptr=&ctl_set_CurrentRobot,
.NumOfLabels=NUM_OF_ROBOTS,
// .Select=0,
GUI_NEXT_CTL(RobotChanCtl)
static GUI_DEF_GROUPBOX(RobotGroupCtl, "Robot", RobotNameCtl) 0, .Ctl.LineNum=-1, GUI_NO_NEXT_CTL()
static GUI_DEF_CHECK(VarCycleCtl, "Variation Cycle") GUICFLAG_RESERVED|GUICFLAG_OFF_AS_ON,
.Ctl.Ptr=(void *)CTLSTR_CYCLEVARIATION,
.NumOfLabels=1,
GUI_NEXT_CTL(RobotGroupCtl)
static GUI_DEF_ARROWS(PgmChangeCtl, "Always\0When stopped\0Manually\0Articulations\0Instruments", "Change") GUICFLAG_LABELBOX,
.Ctl.Ptr=&PatchChgFunc,
.Range.High=3,
GUI_NEXT_CTL(VarCycleCtl)
static GUI_DEF_ARROWS(AutoStartCtl, "Off\0On\0Toggle", "Autostart") 0,
.Ctl.Ptr=&AutostartFunc,
.Range.High=2,
GUI_NEXT_CTL(PgmChangeCtl)
#define ROBOTCTLS &AutoStartCtl.Ctl
/**************** show_robotctls() ****************
* Shows/hides all robot individual ctls based upon
* whether the robot's Playback destination ("Playback on")
* is set to "Off".
*/
static void show_robotctls(void)
{
// Only drums use polarity
if (RobotNameCtl.Select)
PolarityCtl.Ctl.Flags |= GUICFLAG_HIDE;
else
PolarityCtl.Ctl.Flags &= ~GUICFLAG_HIDE;
// If PlayDev isn't off, show all the other ctls
RobotNameCtl.Ctl.Next = (RobotInfo[RobotNameCtl.Select].PlayDev) ? &RobotChanCtl.Ctl : &RobotDevCtl.Ctl;
ctl_update_full_ctl(&RobotGroupCtl.Ctl);
}
static uint32_t ctl_update_polarity(register GUICTL * ctl)
{
return ((AppFlags2 & APPFLAG2_POLARITY) ? 0 : 1);
}
static uint32_t ctl_set_polarity(register GUICTL * ctl)
{
AppFlags2 &= ~APPFLAG2_POLARITY;
if (PolarityCtl.Select) AppFlags2 |= APPFLAG2_POLARITY;
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_set_solo_playdev(register GUICTL * ctl)
{
return set_playdev_assign(&SoloDevCtl, MUSICIAN_SOLO);
}
static uint32_t ctl_update_solo_playdev(register GUICTL * ctl)
{
return getDeviceIndex(RobotInfo[MUSICIAN_SOLO].PlayDev);
}
static int32_t getPlayDevStr(void * appdata, GUIAPPHANDLE app)
{
register uint32_t labelNum;
if (app->Command & GUICMD_GET_STR)
{
if ((labelNum = app->StrCount))
{
//app->Buffer = "On";
//if (RobotDevCtl.Range.High > 1)
{
register SOUNDDEV * sounddev;
sounddev = 0;
while ((sounddev = getNextOutDevice(sounddev)))
{
if (sounddev->Handle && !(--labelNum))
{
app->Buffer = sounddev->DevName;
goto out;
}
}
}
}
app->Buffer = "Off";
}
else if (app->Command & GUICMD_GET_STR_WIDTH)
app->Buffer = getNextOutDevice(0)->DevName;
out:
return 0;
}
static uint32_t ctl_update_patch_chg(register GUICTL * ctl)
{
return (AppFlags2 & (APPFLAG2_PATCHCHG_MANUAL|APPFLAG2_PATCHCHG_STOPPED)) >> 6;
}
static uint32_t ctl_set_patch_chg(register GUICTL * ctl)
{
AppFlags2 = (AppFlags2 & ~(APPFLAG2_PATCHCHG_MANUAL|APPFLAG2_PATCHCHG_STOPPED)) | (PgmChangeCtl.Value << 6);
// Done setting this parameter. Let caller redraw the ctl
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t set_playdev_assign(register GUICTL_ARROWS * ctl, register uint32_t robotNum)
{
register SOUNDDEV * sounddev;
register uint32_t devNum;
sounddev = 0;
// "Off" ?
if (!(devNum = GuiApp->ArrowsValue))
{
set: RobotInfo[robotNum].PlayDev = sounddev;
MusicianAssignChange |= (0x01 << robotNum);
show_robotctls();
return CTLMASK_SETCONFIGSAVE;
}
while ((sounddev = getNextOutDevice(sounddev)))
{
if (sounddev->Handle && !(--devNum)) goto set;
}
return 0;
}
static uint32_t ctl_update_robot_playdev(register GUICTL * ctl)
{
return getDeviceIndex(RobotInfo[RobotNameCtl.Select].PlayDev);
}
static uint32_t ctl_set_robot_playdev(register GUICTL * ctl)
{
return set_playdev_assign(&RobotDevCtl, RobotNameCtl.Select);
}
static uint32_t ctl_update_robot_midichan(register GUICTL * ctl)
{
return RobotInfo[RobotNameCtl.Select].MidiChan;
}
static uint32_t ctl_set_robot_midichan(register GUICTL * ctl)
{
RobotInfo[RobotNameCtl.Select].MidiChan = RobotChanCtl.Value;
updChansInUse();
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_set_CurrentRobot(register GUICTL * ctl)
{
RobotVolCtl.Ctl.Ptr = getVolCtlDataPtr(RobotNameCtl.Select);
show_robotctls();
ctl = &RobotChanCtl.Ctl;
do
{
update_ctl_value(ctl);
} while ((ctl = ctl->Next));
// Redraw the group ctl to also redraw all children
ctl_update_full_ctl(&RobotGroupCtl.Ctl);
return 0;
}
static uint32_t ctl_update_robot_mute(register GUICTL * ctl)
{
return ((AppFlags3 & (APPFLAG3_NODRUMS << (RobotNameCtl.Select))) ? 1 : 0);
}
static uint32_t ctl_set_robot_mute(register GUICTL * ctl)
{
register unsigned char musicianNum;
musicianNum = RobotNameCtl.Select;
setAppFlags(APPFLAG3_NODRUMS << musicianNum, RobotMuteCtl.SelectMask);
// MusicianMuteChange |= (0x01 << musicianNum);
return CTLMASK_SETCONFIGSAVE;
}
static uint32_t ctl_update_autostart(register GUICTL * ctl)
{
register unsigned char val;
if (AppFlags3 & APPFLAG3_AUTOSTARTARM)
val = 2;
else
val = ((AppFlags3 & APPFLAG3_NOAUTOSTART) >> AUTOSTART_SHIFT) ^ 0x01;
return val;
}
static uint32_t ctl_set_autostart(register GUICTL * ctl)
{
AppFlags3 &= ~(APPFLAG3_AUTOSTARTARM|APPFLAG3_NOAUTOSTART);
TempFlags &= ~(TEMPFLAG_AUTOSTART);
switch (AutoStartCtl.Value)
{
case 2:
AppFlags3 |= APPFLAG3_AUTOSTARTARM;
case 1:
TempFlags |= TEMPFLAG_AUTOSTART;
break;
case 0:
AppFlags3 |= APPFLAG3_NOAUTOSTART;
break;
}
return CTLMASK_SETCONFIGSAVE;
}
#ifndef NO_SONGSHEET_SUPPORT
static uint32_t ctl_set_edsong(register GUICTL * ctl)
{
songEdit();
return 0;
}
static uint32_t ctl_set_crsong(register GUICTL * ctl)
{
songCreate(1);
return 0;
}
static uint32_t ctl_set_crsongb(register GUICTL * ctl)
{
songCreate(0);
return 0;
}
static GUICTLFUNCPTR * SongEdFunc[] = {&ctl_set_edsong, &ctl_set_crsong, &ctl_set_crsongb};
static GUI_DEF_PUSH(EditSongCtl, "Edit\0New\0New\nEmpty\0Songs") GUICFLAG_LABELBOX|SETFUNC_ONLY_PTR,
.Ctl.Ptr=&SongEdFunc[0],
.Ctl.LineNum=-1,
.NumOfLabels=3
GUI_NO_NEXT_CTL()
#endif
//=======================
static uint32_t ctl_set_edit_style(register GUICTL * ctl)
{
doStyleEdit();
return 0;
}
static uint32_t ctl_set_reloads(register GUICTL * ctl)
{
freeAccompStyles();
loadDataSets(LOADFLAG_STYLES);
doSetupScreen();
return 0;
}
static GUICTLFUNCPTR * StyleEditFunc[] = {&ctl_set_edit_style, &ctl_set_reloads};
static GUI_DEF_PUSH(EditStylesCtl, "Edit\0Reload all\0Styles") GUICFLAG_LABELBOX|SETFUNC_ONLY_PTR,
.Ctl.Ptr=&StyleEditFunc[0],
.NumOfLabels=2,
.Ctl.LineNum=-1,
#ifndef NO_SONGSHEET_SUPPORT
GUI_NEXT_CTL(EditSongCtl)
#else
GUI_NO_NEXT_CTL()
#endif
//=======================
static uint32_t ctl_edit_drum(register GUICTL * ctl)
{
return 0;
}
static uint32_t ctl_new_drum(register GUICTL * ctl)
{
return 0;
}
static uint32_t ctl_import_drum(register GUICTL * ctl)
{
return 0;
}
static uint32_t ctl_export_drum(register GUICTL * ctl)
{
return 0;
}
static GUICTLFUNCPTR * DrumPtnEditFunc[] = {&ctl_edit_drum, &ctl_new_drum, &ctl_import_drum, &ctl_export_drum};
static GUI_DEF_PUSH(DrumsGroupCtl, "Edit\0Create\0Import\nMIDI\0Export\nMIDI\0Drum Pattern\0") GUICFLAG_LABELBOX|SETFUNC_ONLY_PTR,
.Ctl.Ptr=&DrumPtnEditFunc[0],
.NumOfLabels=4,
GUI_NEXT_CTL(EditStylesCtl)
#define EDITORCTLS &DrumsGroupCtl.Ctl
/********************** setup_msg_handler() ************************
* Called by GUI thread when user operates a ctl in the Setup
* main screens.
*/
static void setup_msg_handler(void)
{
register uint32_t cmd;
cmd = GuiApp->Command;
// One of the preset btns
if (GuiMsgIsPreset(cmd))
{
if (GuiApp->SelectedSubCtl == GUIBTN_HELP) goto help;
// Exit setup btn?
if (GuiApp->SelectedSubCtl == GUIBTN_EXITSETUP || GuiApp->SelectedSubCtl == GUIBTN_CANCEL) // ESC key
{
#ifndef NO_MIDI_IN_SUPPORT
midiviewDone();
#endif
// if ((MusicianMuteChange | MusicianAssignChange))
// hideMainCtls();
if (MusicianAssignChange)
{
loadDataSets(LOADFLAG_INSTRUMENTS|LOADFLAG_SONGS);
#ifndef NO_MIDI_IN_SUPPORT
updChansInUse();
#endif
}
#ifndef NO_MIDI_IN_SUPPORT
if (AppFlags & APPFLAG_WINDCTL)
{
if (ChordTriggerByCtl.Value) goto midi;
ChordTrigger = limitMouseBtn(0xff) + 0xf1;
}
else if (ChordTriggerByCtl.Value != 2)
ChordTrigger = (ChordTriggerByCtl.Value + 9) << 4;
else
midi: ChordTrigger = TempChordTrigger;
#endif
showMainScreen();
}
goto out;
}
if (GuiMsgIsValueChange(cmd) || GuiMsgActionIs(cmd, GUIMSG_ACTION_LIST_DONE))
handle_ctl_click();
else switch (GuiMsgAction(cmd))
{
// ================ Panel bar ================
case GUIMSG_ACTION_FOCUS_PANEL:
case GUIMSG_ACTION_PANEL_SELECT:
{
PanelSelect = GuiApp->PanelNum;
doSetupScreen();
break;
}
case GUIMSG_ACTION_SHOW_HELP:
{
help: showHelpScreen(HelpStrs[PanelSelect]);
// doSetupScreen();
}
}
out:
return;
}
//====================================
// Panel bar
//====================================
void play_off_state(void)
{
#ifndef NO_MIDI_IN_SUPPORT
endCmdMode();
#endif
abrupt_stop_play(GUITHREADID);
#ifndef NO_SONGSHEET_SUPPORT
selectSongSheet(0, GUITHREADID);
#endif
}
static void updateSetupCtls(register GUICTL * ctl)
{
while (ctl)
{
if (GuiCtlIsGroup(ctl))
updateSetupCtls(((GUICTL_GROUPBOX *)ctl)->Child);
else
update_ctl_value(ctl);
ctl = ctl->Next;
}
}
static void doGeneralDlg(GUIAPPHANDLE app)
{
GuiMsgFunc = 0;
GuiApp->WinInfo.ControlsList = GLOBALCTLS;
init_setup_panel(GUI_WIN_SET_CONTROLS);
// Update the Bus buttons
updateBussBtns();
// Update rev ctls
updateReverbCtls();
updateSetupCtls(GLOBALCTLS);
}
static void doRobotsDlg(GUIAPPHANDLE app)
{
GuiMsgFunc = 0;
GuiApp->WinInfo.ControlsList = ROBOTCTLS;
init_setup_panel(GUI_WIN_SET_CONTROLS);
updateSetupCtls(ROBOTCTLS);
}
static void doCommandsDlg(GUIAPPHANDLE app)
{
play_off_state();
GuiMsgFunc = 0;
#ifndef NO_MIDI_IN_SUPPORT
update_cmd_ctls();
#endif
resetActionsList(&ActionsCtl);
GuiApp->WinInfo.Options = GUIWIN_OPT_LIST_KEY_FOCUS|GUIWIN_OPT_TAB_NEXT_PANEL|GUIWIN_OPT_TAB_NEXT_CTL|
GUIWIN_OPT_ENTER_AS_CLICK|GUIWIN_OPT_SHOW_HELP|GUIWIN_OPT_SPACE_AS_ENTER|GUIWIN_OPT_ESC_KEY_CANCEL|GUIWIN_OPT_CUSTOM_DRAWING;
GuiApp->WinInfo.ControlsList = CMDCTLS;
init_setup_panel(GUI_WIN_SET_OPTIONS|GUI_WIN_SET_CONTROLS);
GuiMsgFunc = &cmdasn_msg_handler;
updateSetupCtls(CMDCTLS);
}
GUICTL_LIST * getActionsList(void)
{
return &ActionsCtl;
}
static void doHumanDlg(GUIAPPHANDLE app)
{
GuiMsgFunc = 0;
GuiApp->WinInfo.ControlsList = HUMANCTLS;
init_setup_panel(GUI_WIN_SET_CONTROLS);
updateSetupCtls(HUMANCTLS);
}
static void doEditorDlg(GUIAPPHANDLE app)
{
GuiMsgFunc = 0;
GuiApp->WinInfo.ControlsList = EDITORCTLS;
init_setup_panel(GUI_WIN_SET_CONTROLS);
updateSetupCtls(EDITORCTLS);
}
static GUI_PANEL_ITEM SetupEditor = {.Label="Editor",
.UserData=doEditorDlg,
.IdNumber=4,
.Color = (GUICOLOR_GREEN << 4) | GUICOLOR_DARKGREEN
};
static GUI_PANEL_ITEM SetupCommands = {.Label="Commands",
.Next=&SetupEditor,
.UserData=doCommandsDlg,
.IdNumber=3,
.Color = (GUICOLOR_GREEN << 4) | GUICOLOR_DARKGREEN
};
static GUI_PANEL_ITEM SetupHuman = {.Label="Human",
.Next=&SetupCommands,
.UserData=doHumanDlg,
.IdNumber=2,
.Color = (GUICOLOR_GREEN << 4) | GUICOLOR_DARKGREEN
};
static GUI_PANEL_ITEM SetupRobots = {.Label="Robots",
.Next=&SetupHuman,
.UserData=doRobotsDlg,
.IdNumber=1,
.Color = (GUICOLOR_GREEN << 4) | GUICOLOR_DARKGREEN
};
static GUI_PANEL_ITEM SetupGeneral = {.Label="General",
.Next=&SetupRobots,
.UserData=doGeneralDlg,
.IdNumber=0,
.Color = (GUICOLOR_GREEN << 4) | GUICOLOR_DARKGREEN
};
void init_setup_panel(register uint32_t flags)
{
register uint32_t setflags;
setflags = 0;
// Attach Setup panel bar, and specify msg handler = setup_msg_handler if GuiMsgFunc=0
if (!GuiMsgFunc)
{
register GUIPANEL * panel;
GuiMsgFunc = &setup_msg_handler;
panel = &GuiApp->WinInfo.Panel;
panel->List = &SetupGeneral;
panel->PanelNum = PanelSelect;
panel->Reserve.Width = 0;
GuiApp->SelectedSubCtl = GUIBTN_EXITSETUP;
GuiApp->WinInfo.Presets.LowerMask = GUIBTN_HELP_SHOW|GUIBTN_EXITSETUP_SHOW;
flags |= GUI_WIN_SET_PANEL_RESERVE|GUI_WIN_SET_PANEL_NUM|GUI_WIN_SET_PANEL_ITEMS|GUI_WIN_SET_PRESET_LOWER|GUI_WIN_SET_FOCUS;
}
else if (!(flags & GUI_WIN_SET_PANEL_ITEMS))
{
setflags = GUI_WIN_SET_PANEL_ITEMS;
GuiApp->WinInfo.Panel.List = 0;
}
if (flags)
{
// If caller didn't specify preset btns, then none
if (!(flags & GUI_WIN_SET_PRESET_LOWER))
GuiApp->WinInfo.Presets.LowerMask = 0;
else
{
// If caller didn't specify a default btn, then set to lower "Cancel"
if (!(flags & GUI_WIN_SET_FOCUS))
{
GuiApp->SelectedSubCtl = GUIBTN_CANCEL;
setflags |= GUI_WIN_SET_FOCUS;
}
GuiApp->SelectedCtl = GUISELECT_LOWERBTN;
}
// If caller didn't specify flags, then use this default
if (!(flags & GUI_WIN_SET_OPTIONS)) GuiApp->WinInfo.Options = GUIWIN_OPT_TAB_NEXT_PANEL|GUIWIN_OPT_TAB_NEXT_CTL|GUIWIN_OPT_ENTER_AS_CLICK|GUIWIN_OPT_SHOW_HELP|GUIWIN_OPT_ESC_KEY_CANCEL;
setflags |= GUI_WIN_SET_OPTIONS | GUI_WIN_SET_PRESET_LOWER;
}
// No Banner string if not specified
if (!(flags & GUI_WIN_SET_BANNER_TEXT))
{
GuiApp->WinInfo.Banner.Text = 0;
setflags |= GUI_WIN_SET_BANNER_TEXT;
}
GuiApp->Window = MainWin;
GuiWinSetValue(GuiApp, setflags|flags);
// clearMainWindow();
}
void showHelpScreen(register const char * ptr)
{
GuiApp->HelpText = ptr;
GuiApp->HelpFlags = GUIHELP_REUSE_WIN;
GuiApp->HelpColor = 0;
if (!GuiHelpShow(GuiApp, MainWin))
{
while (GuiAppGetMsg(GuiApp) >= 0);
}
return;
}
// ====================================================
/********************* doSetupScreen() ***********************
* Shows/operates the "Setup" screen's current panel.
*/
void doSetupScreen(void)
{
#ifndef NO_MIDI_IN_SUPPORT
midiviewDone();
endCmdMode();
#endif
setShownCtls(0);
ReturnFunc = doSetupScreen;
RobotDevCtl.Range.High = SoloDevCtl.Range.High = get_out_dev_count();
((VOIDRETFUNC)(get_panel_item(&SetupGeneral, PanelSelect)->UserData))();
clearMainWindow();
}
void enterSetupScreen(void)
{
// Indicate setup screen is being operated
setupScreenIsOn();
#ifndef NO_MIDI_IN_SUPPORT
TempChordTrigger = ChordTrigger;
if (AppFlags & APPFLAG_WINDCTL)
{
if (TempChordTrigger < 128)
{
ChordTriggerByCtl.Value = 1;
limitMouseBtn(1);
}
else
{
limitMouseBtn(TempChordTrigger - 0xf1);
ChordTriggerByCtl.Value = 0;
}
}
else
{
ChordTriggerByCtl.Value = 2;
if (TempChordTrigger > 127)
ChordTriggerByCtl.Value = (TempChordTrigger >> 4) - 9;
}
#endif
// MusicianMuteChange =
MusicianAssignChange = 0;
doSetupScreen();
}
unsigned char isHumanScreen(void)
{
return (!isMainScreen() && PanelSelect == 2) ? 1 : 0;
}
/*************** positionSetupGui() ****************
* Sets initial position/scaling of GUI ctls based
* upon font size.
*/
void positionSetupGui(void)
{
fixup_setup_ctls(GLOBALCTLS);
fixup_setup_ctls(HUMANCTLS);
fixup_setup_ctls(ROBOTCTLS);
// fixup_setup_ctls(CMDCTLS);
GuiApp->CreateFlags = 0;
GuiApp->SelectedCtl = GLOBALCTLS;
GuiCtlScale(GuiApp);
GuiApp->SelectedCtl = HUMANCTLS;
GuiCtlScale(GuiApp);
GuiApp->SelectedCtl = ROBOTCTLS;
GuiCtlScale(GuiApp);
GuiApp->SelectedCtl = CMDCTLS;
GuiCtlScale(GuiApp);
GuiApp->SelectedCtl = EDITORCTLS;
GuiCtlScale(GuiApp);
GuiApp->SelectedCtl = &ChordSensCtl.Ctl;
GuiCtlScale(GuiApp);
#ifndef NO_MIDI_IN_SUPPORT
ChordSensCtl.Ctl.X = ChordTriggerByCtl.Ctl.X;
ChordSensCtl.Ctl.Y = ChordTriggerByCtl.Ctl.Y;
ChordSensCtl.Ctl.Next = &ChordBoundCtl.Ctl;
GuiApp->SelectedCtl = &MinorPedalCtl.Ctl;
GuiCtlScale(GuiApp);
MinorPedalCtl.Ctl.X = TriggerAssignCtl.Ctl.X - (MinorPedalCtl.Ctl.Width + GuiGetMetric(GuiApp, GUIMETRIC_XSPACE));
MinorPedalCtl.Ctl.Y = TriggerAssignCtl.Ctl.Y;
MinorPedalCtl.Ctl.Next = &TriggerAssignCtl.Ctl;
#endif
}
void set_default_lower_preset(register unsigned char guiBtn)
{
GuiApp->SelectedCtl = GUISELECT_LOWERBTN;
GuiApp->SelectedSubCtl = guiBtn;
GuiApp->WinInfo.Presets.UpperMask = 0;
GuiApp->WinInfo.Panel.List = 0;
}
#endif // BB_NO_GUI