Help for Tune Smithy Koch snowflake icon.gif

Monster keyboard c-code sketch

From Tune Smithy

Jump to: navigation, search

See: High numbered velocity keyswitches retuning#Monster keyboard instruments with hundreds or thousands of keys, using this keyswitch method

/************************************
* CODING IDEA FOR MONSTER KEYBOARD
*
* This is just a sketch to show how it might work, not actually tested, except to check that the code
* compiles without error, but programmers may find the idea clearer if written out as c code, in place
* of the description in words. 
* see http://robertinventor.com/ftswiki/High_numbered_keyswitches_retuning#Monster_keyboard_instruments_with_hundreds_or_thousands_of_keys.2C_using_this_keyswitch_method
*
* I use a single structure here instead of several different arrays, written in c (not c++) which has structures, 
* this simplifies the layout of the code a bit.
*************************************/
typedef struct 
 {
  int imidi_note;
  double ddecimal_midi_pitch_assigned;
  BOOL bin_play;
  BOOL breleased;
  time_t treleased; // time when the key was released
 }KEY_STATUS;
 
#define MAX_MONSTER_KEYBOARD_KEYS 10000 
#define MAX_MIDI_NOTE_TO_RETUNE 128
 // Assumes you switch off retuning after every key pressed.
 // So doesn't matter that 126 and 127 are used for the keyswitch retuning instructions (otherwise would be 125 here)
 
KEY_STATUS key_status[MAX_MONSTER_KEYBOARD_KEYS];
 
/************************************
* This routine gets called first on power up to initialize everything
*
* It also makes sure that the first 128 key ids are assigned a midi note and all 128
* midi notes are used (in case where monster keyboard has more than 128 keys
*************************************/
 
void reset_to_12et_or_init(void)
{
 int i=0;
 for(i=0;i<MAX_MONSTER_KEYBOARD_KEYS&&i<=MAX_MIDI_NOTE_TO_RETUNE;i++)
 {
  key_status[i].imidi_note=i;
  key_status[i].ddecimal_midi_pitch_assigned=i;
 }
 for(i=MAX_MIDI_NOTE_TO_RETUNE+1;i<MAX_MONSTER_KEYBOARD_KEYS;i++)
 {
  key_status[i].imidi_note=-1; // Set to -1 if not assigned
 }
}
 
 
/*************************************
* This routine is called when the key is released to mark it as no longer in play
* and to find out the midi note number to switch off
* return value is the midi note to switch off
*************************************/
 
int ikey_released(int ikey_id)
{
 key_status[ikey_id].bin_play=0;
 key_status[ikey_id].breleased=1;
 key_status[ikey_id].treleased=time(NULL);
 return key_status[ikey_id].imidi_note;
}
 
/*************************************
* This routine is called when a key is pressed, with the key id and desired pitch
* as arguments, to find out which midi note to play
* Also does the retuning if necessary
*
* The desired pitch ddecimal_midi_pitch_assigned_note is in decimal midi notation e.g. 60.0 for middle C,
* 60.5 is 50 cents above middle C etc.
*
* Return value is the midi note to play
*************************************/
 
int ioutput_note_for_key(int ichannel,int ikey_id,double ddecimal_midi_pitch_to_play)
{
 /*************************************
 
 * ichannel is the midi channel to send the velocity key switchse on if it needs to be retuned
 * May need other parameters there
 * ikey_id is the internal id used for the key by the monster keyboard
 * ddecimal_midi_pitch_to_play is the desired pitch for that key to play
 *
 * Here where it says 
 *   if(key_status[i].ddecimal_midi_pitch_assigned==ddecimal_midi_pitch_to_play)
 * since floating point figures are prone to rounding errors, may need instead to have something like:
 *   if(fabs(key_status[i].ddecimal_midi_pitch_assigned - ddecimal_midi_pitch_to_play)<1e-10)
 * depending on how rounding errors work for your calculations of ddecimal_midi_pitch_to_play
 *************************************/
 
 
 int i=0;
 int iok_id=-1;
 if(MAX_MONSTER_KEYBOARD_KEYS<=MAX_MIDI_NOTE_TO_RETUNE+1)
  return ikey_id; // Have more midi notes than keys, so just use the id for the midi note
 
 if(!key_status[ikey_id].bin_play)
 if(key_status[ikey_id].imidi_note>=0)
 if(key_status[ikey_id].ddecimal_midi_pitch_assigned==ddecimal_midi_pitch_to_play)
  // ikey_id is already retuned to the desired pitch, no change needed
  return key_status[ikey_id].imidi_note;
 
 /*************************************
 * Otherwise need to look through the keys not in play 
 * and look for, in order of preference:
 * 1. key already tuned to the right pitch, or else
 * 2. key that hasn't been played at all
 * 3. key released longest ago
 * If found, then can swap midi note numbers with it.
 *************************************/
 
 
 // First is any key already tuned to the right pitch?
 for(i=0;i<MAX_MONSTER_KEYBOARD_KEYS;i++)
 {
  if(!key_status[i].bin_play)
  if(key_status[i].ddecimal_midi_pitch_assigned==ddecimal_midi_pitch_to_play)
  // One of the notes is already retuned to the desired pitch, so use that.
  {
   iok_id=i;
   break;
  }
 }
 
 // Look for keys not yet played
 //
 // Doesn't matter which of these you use
  if(!key_status[ikey_id].imidi_note>=0)
 
  if(!key_status[ikey_id].bin_play)
  if(!key_status[ikey_id].breleased)
   iok_id=ikey_id; // ikey_id has not yet been assigned a pitch so just use this one.
 if(iok_id<0)
 for(i=0;i<MAX_MONSTER_KEYBOARD_KEYS;i++)
 {
  if(!key_status[i].imidi_note>=0) // So it's already been assigned a midi note to play
  if(!key_status[i].bin_play)
  if(!key_status[i].breleased)
  {
   iok_id=i;
   break;
  }
 }
 
 // Look for the key released longest ago
 if(iok_id<0)
 {
  time_t tsince_release_max=0;
  time_t tnow=time(NULL);
  for(i=0;i<MAX_MONSTER_KEYBOARD_KEYS;i++)
  {
   if(!key_status[i].bin_play)
   if(key_status[i].breleased)
   {
    unsigned int tsince_release=(unsigned int)(tnow-key_status[i].treleased);
    if(tsince_release>tsince_release_max)
    {
     tsince_release_max=tsince_release;
     iok_id=i;
    }
   }
  }
 }
 
 // Have found a suitable key
 if(iok_id>=0)
 {
  // iok_id is no longer needed
  //
  // Swap the information for ikey_id and iok_id
  KEY_STATUS key_temp=key_status[iok_id];
  key_status[iok_id]=key_status[ikey_id];
  key_status[ikey_id]=key_temp;
  if(key_status[ikey_id].ddecimal_midi_pitch_assigned!=ddecimal_midi_pitch_to_play)
  {
   // TO DO
   // Send the midi tuning messages to retune key_status[ikey_id].imidi_note
   // to ddecimal_midi_pitch_to_play in channel ichannel
   // 
   //
   key_status[ikey_id].ddecimal_midi_pitch_assigned=ddecimal_midi_pitch_to_play;
  }
  key_status[ikey_id].bin_play=1;
  return key_status[ikey_id].imidi_note;
 }
 return -1;// Should only get here if you have more than MAX_MIDI_NOTE_TO_RETUNE +1 notes held down at once
}

Personal tools
Namespaces
Variants
Actions
Navigation
How to use the wiki
More
Toolbox