示例#1
0
void readSynthButtons() {
  readFnButton();
  int diff;

  for(byte i=0;i<N_NOTE_BUTTONS;i++) {
    if (buttonPressedNew(i)) {
      if (!fnEnabled) {
	button[i].pitchReading = sampledAnalogRead(PITCH_POT);
      }
      button[i].noteIndex = doNoteOn(selectedSettings+1, button[i].midiVal, MAX_VELOCITY);
      note[button[i].noteIndex].trigger = i;

    } else {
      byte noteIndex = button[i].noteIndex;
      if ((noteIndex != UNSET) && (note[noteIndex].midiVal > NOTE_PENDING_OFF) && (note[noteIndex].trigger == i)) {
	if (buttonHeld(i)) {
	  if (!fnEnabled) {
	    int currentPitchReading = sampledAnalogRead(PITCH_POT);
	    diff = abs(currentPitchReading - button[i].pitchReading);
	    if (diff > 5) {
	      // the pot has moved since the button was pressed
	      button[i].midiVal = map(currentPitchReading, 0, 1024, POT_MIDI_LOW, POT_MIDI_HIGH+1);
	      button[i].pitchReading = currentPitchReading;
	      if (button[i].midiVal < MIDI_LOW) {
		button[i].midiVal = MIDI_LOW;
	      }
	      if (button[i].midiVal > MIDI_HIGH) {
		button[i].midiVal = MIDI_HIGH;
	      }

	      button[i].pitchReading = currentPitchReading;
	      note[noteIndex].midiVal = button[i].midiVal;
	    }
	  }
	} else {
	  if (note[noteIndex].envelopePhase != RELEASE) {
	    // button released
	    note[noteIndex].trigger = UNSET;
	    button[i].noteIndex = UNSET;
	    doNoteOff(selectedSettings+1, button[i].midiVal);
	  }
	}
      }
    }
  }
}
示例#2
0
void grooveboxNoteOn(byte channelNum, byte midiNote, byte velocity) {
  seqLock = true;
  // snap to nearest sequencer position
  byte seqSnapIndex;
  int noteStart = pulseClock;
  // noteStartOffset is the timing error. It is the difference between when the note
  // was pressed and the nearest sequencer note boundary.
  int noteStartOffset = (pulseClock % seqStartPulse);
  boolean snappedForward = false;
  if ((noteStartOffset > 0) && (noteStartOffset <= (seqStartPulse/2))) {
    // snap backward
    seqSnapIndex = seqIndex;
  } else {
    // snap forward
    seqSnapIndex = (seqIndex + 1) % SEQ_LENGTH;
    snappedForward = true;
  }
  if (seqSynchStart) {
    seqSnapIndex = 0;
  }

  sequenceNote_t *sn;
  note_t *n;
  byte currentNoteSeqIndex = track[currentTrack].noteSeqIndex;
  sn = &seq[currentNoteSeqIndex][currentTrack];
  n = &note[sn->noteIndex];
  if (n->trigger == currentTrack) {
    if ((n->envelopePhase != OFF) || (n->isSample)) {
      // A note on the current track is playing.
      if ((!seqPreview) && (seqRunning) && (n->envelopePhase != RELEASE)) {
	// If we are not previewing and sequence is running, and it's
	// not in RELEASE phase yet, adjust its duration and stop the note.
	if ((sn->duration == 0) && (currentNoteSeqIndex != seqSnapIndex)) {
	  // If the note being played has not been released yet, set a duration for it.
	  unsigned int newDuration;
	  if ((snappedForward) && (noteStartOffset > 0)) {
	    newDuration = (noteStart + (seqStartPulse-noteStartOffset)) - sn->startPulse;
	  } else {
	    newDuration = (noteStart - noteStartOffset) - sn->startPulse;
	  }
	  debugprint("setting duration of note ", currentNoteSeqIndex);
	  debugprintln(" to ", newDuration);
	  sn->duration = newDuration;
	}
      }
      stopNote(sn->noteIndex);
      note[sn->noteIndex].trigger = UNSET;
    }
  }

  byte ni = doNoteOn(selectedSettings+1, midiNote, velocity);
  if (channelNum == 10) {
    setDrumParameters(ni, midiNote, velocity);
  }
  note[ni].volumeScale = track[currentTrack].volumeScale;
  if (note[ni].volumeScale != 1.0) {
    if (note[ni].isSample) {
      note[ni].doScale = true;
    }
  }
  note[ni].isPreview = seqPreview;
  if ((!seqPreview) && (seqRunning || seqSynchStart)) {
    sn = &seq[seqSnapIndex][currentTrack];
    sn->noteIndex = ni;
    track[currentTrack].noteSeqIndex = seqSnapIndex;
    
    note[sn->noteIndex].trigger = currentTrack;
    sn->startPulse = noteStart;
    sn->midiVal = midiNote;
    if (channelNum == 10) {
      sn->midiVal = sn->midiVal | 0x80; // set high bit to indicate ch10
    }
    sn->transpose = 0;
    track[currentTrack].state = SEQ_RECORD;
    sn->velocity = velocity;
    sn->duration = 0;
    sn->waveform = note[ni].waveform;
  }
  if (seqSynchStart) seqSynchStart = false;
  seqLock = false;
}
示例#3
0
void doGroovebox() {
  if (!seqRunning) return;
  unsigned int duration;

  sequenceNote_t *sn;
  for(byte t=0;t<SEQ_NUM_TRACKS;t++) {
    sn = &seq[track[t].noteSeqIndex][t];
    note_t *n = &note[sn->noteIndex];
    if (track[t].state == SEQ_PLAY) {
      // check to see if this note's duration is elapsed, but only
      // if it has not been released.
      if ((n->trigger == t) && (n->envelopePhase != RELEASE) && (n->envelopePhase != OFF)) {
	duration = pulseClock - sn->startPulse;
	if (duration >= sn->duration) {
	  // time to release this note
	  if (duration != sn->duration) {
	    debugprintln("track=", t);
	    debugprintln("noteSeqIndex=", track[t].noteSeqIndex);
	    debugprint("ERROR: releasing note with duration ", sn->duration);
	    debugprintln(" at computed duration ", duration);
	    debugprintln("env=", n->envelopePhase);
	    sn->duration = duration;
	  }
	  releaseNote(n);
	}
      }
    }
  }

  if ((pulseClock % seqStartPulse) == 0) {
    sequenceNote_t *sn;
    sequenceNote_t *nextsn;
    seqIndex = (seqIndex + 1) % SEQ_LENGTH;
    if (seqIndex < 10) {
      debugprint(" ", seqIndex);
    } else {
      debugprint("", seqIndex);
    }
    debugprint(":");
  
    seqLEDIndex = seqIndex / (SEQ_LENGTH / 4);
    digitalWrite(led[seqLEDIndex], HIGH);
    ledState[seqLEDIndex] = HIGH;

    // The play/record head has reached a note boundary.
    for(byte t=0;t<SEQ_NUM_TRACKS;t++) {
      sn = &seq[track[t].noteSeqIndex][t];
      note_t *n = &note[sn->noteIndex];
      if (track[t].state == SEQ_PLAY) {
	// Check if it is time to start a new note at this position in the sequence.
	nextsn = &seq[seqIndex][t];
	if (nextsn->midiVal != UNSET) {
	  // There is a note here in the sequence to play
	  // See if there is a currently playing note and stop it.
	  if (n->trigger == t) {
	    if ((n->envelopePhase != RELEASE) && (n->envelopePhase != OFF)) {
	      // A currently playing note should have been released above
	      // because its duration should have elapsed.
	      debugprint(" adjusting note ", track[t].noteSeqIndex);
	      debugprint(" duration from  ", sn->duration);
	      debugprintln(" to ", pulseClock - sn->startPulse);
	      sn->duration = pulseClock - sn->startPulse;
	    }
	    // Stop the note
	    stopNote(sn->noteIndex);
	    n->trigger = UNSET;
	  }

	  if ((pulseClock > nextsn->startPulse) && ((pulseClock - nextsn->startPulse) < seqStartPulse)) {
	    // avoid double hit for short note that was already released but snapped to this position
	    debugprintln("avoiding double hit: ", pulseClock-nextsn->startPulse);
	  } else {
	    byte midiVal = (nextsn->midiVal & 0x7F);
	    boolean isDrumChannel = (nextsn->midiVal) & 0x80; // high bit indicates ch10
	    if (nextsn->waveform < N_WAVEFORMS) {
	      // transpose notes that are not samples
	      midiVal = constrain(nextsn->midiVal + nextsn->transpose, MIDI_LOW, MIDI_HIGH);
	    }
	    nextsn->noteIndex = doNoteOn(t+1, midiVal, nextsn->velocity);
	    if (isDrumChannel) {
	      setDrumParameters(nextsn->noteIndex, midiVal, nextsn->velocity);
	    }
	    note[nextsn->noteIndex].trigger = t;
	    nextsn->startPulse = pulseClock;
	    track[t].noteSeqIndex = seqIndex;
	    // Set the waveform to the one that was recorded.
	    // This only works if we don't call setPhaseIncrement() in doNoteOn()
	    if (!isDrumChannel) {
	      note[nextsn->noteIndex].waveformBuf = waveformBuffers[nextsn->waveform];
	    }
	    if (nextsn->waveform >= N_WAVEFORMS) {
	      note[nextsn->noteIndex].isSample = true;
	      if (!isDrumChannel) {
		// already taken care of in setDrumParameters().
		note[nextsn->noteIndex].sampleLength = sampleLength[nextsn->waveform - N_WAVEFORMS];
		note[nextsn->noteIndex].volIndex = note[nextsn->noteIndex].targetVolIndex;
		note[nextsn->noteIndex].volume = logVolume[note[nextsn->noteIndex].volIndex];
		note[nextsn->noteIndex].volumeNext = note[nextsn->noteIndex].volume;
	      }
	    } else {
	      note[nextsn->noteIndex].isSample = false;
	    }

	    note[nextsn->noteIndex].volumeScale = track[t].volumeScale;
	    if (note[nextsn->noteIndex].volumeScale != 1.0) {
	      if (note[nextsn->noteIndex].isSample) {
		note[nextsn->noteIndex].doScale = true;
	      }
	    }
	  }
	}
      } // track in SEQ_PLAY state


      if (track[t].state == SEQ_RECORD) {
	// a note is currently being held and recorded
	// check to see if there is a note here in the sequence 
	// and if so, overwrite it.
	if ((seq[seqIndex][t].midiVal != UNSET) && (seqIndex != track[t].noteSeqIndex)) {
	  // Only clear the note if it's not the one being recorded.
	  // I may be the one being recorded because the recording started before
	  // the pulseClock reached this point in the sequence and the new note 
	  // "snapped" to this location.
	  seq[seqIndex][t].midiVal = UNSET;
	  seq[seqIndex][t].transpose = 0;
	  // Note that this may not actually be the right thing to do because
	  // the currently recorded note might be released right after the play
	  // head passes this point in the sequence, and the release snaps back to this
	  // point. If that were the case, we'd want to keep the note that is already
	  // here.
	}
      }

      if (seq[seqIndex][t].midiVal != UNSET) {
	debugprint(" ", (seq[seqIndex][t].midiVal & 0x7F));
	if (seq[seqIndex][t].duration > 0) {
	  debugprint("[", seq[seqIndex][t].duration);
	} else {
	  debugprint("[UNKNOWN");
	}
	debugprint("]");
      } else {
	debugprint("   ");
      }
      if (t == (SEQ_NUM_TRACKS-1)) {
	debugprintln("");
      }
    } // for each track

    if (metronomeMode != METRONOME_MODE_OFF) {
      byte tickFrequency;
      if (metronomeMode == METRONOME_MODE_QUARTER) {
	tickFrequency = 4;
      }
      if (metronomeMode == METRONOME_MODE_SIXTEENTH) {
	tickFrequency = 1;
      }
      if ((seqIndex % tickFrequency) == 0) {
	if (seqIndex == 0) {
	  metronomeNoteIndex = metronomeTick(64, MAX_NOTE_VOL);
	} else {
	  metronomeNoteIndex = metronomeTick(60, 40);
	}
      }
    }
  }



  if (((pulseClock - (seqStartPulse/2)) % seqStartPulse) == 0) {
    digitalWrite(led[seqLEDIndex], LOW);
    ledState[seqLEDIndex] = LOW;
  }
}
示例#4
0
void*
MidiInput::run()
{
    unsigned char tmp;
    unsigned char cmd     = 0;
    unsigned char channel = 0;
    unsigned char data[2];
    int inCommand = 0;
    char ctlName[ 10 ]; //format is "ctl00-000"

    while( running )
    {
	read( midiFd, &tmp, 1 );
    
	if ( tmp == 248 ) // throw away timing messages they mess us up!
	{
	    //debug( DEBUG_STATUS, "." );
	    continue;
	}

	if ( tmp < 128 )
	{
	    data[0] = tmp;
	    inCommand = 1;
	}
	
	else
	{
	    cmd     = tmp & 0xF0;
	    channel = tmp & 0x0F;
	    inCommand = 0;
	}
	
	switch( cmd )
	{
	case MIDI_NOTEOFF: //0x80
	    READ2;
	    doNoteOff( channel, data[0], data[1] );
	    break;
	    
	case MIDI_NOTEON: //0x90
	    READ2;
	    if ( data[1] == 0 )
	    {
		doNoteOff( channel, data[0], data[1] );
	    }
	    else
	    {
		doNoteOn( channel, data[0], data[1] );
	    }
	    break;
	    
	case MIDI_KEY_PRESSURE: //0xA0
	    READ2;
	    debug( DEBUG_STATUS, "KEY PRESSURE ch=%d note=%d amount=%d\n", 
		   channel, cmd, data[ 0 ] );
	    break;
	    
	case MIDI_CTL_CHANGE: //0xB0
	    READ2;
	    debug( DEBUG_STATUS, "CTL_CHANGE %d %d %d\n", channel, data[ 0 ], data[ 1 ] );

	    sprintf( ctlName, "ctl%d-%d", channel, data[0] );
	    {
		Output* out;
		out = MoogObject::getOutput( ctlName );
		if ( out != NULL )
		    out->setData(data[ 1 ] / 127.0);
	    }

	    break;
	    
	case MIDI_PGM_CHANGE: //0xC0
	    READ1;
	    debug( DEBUG_STATUS, "PGM_CHANGE %d %d\n", channel, data[ 0 ] );
	    break;
	    
	case MIDI_CHN_PRESSURE: //0xD0
	    READ1;
	    debug( DEBUG_STATUS, "CHN_PRESSURE %d %d\n", channel, data[ 0 ] );
	    break;
	    
	case MIDI_PITCH_BEND: //0xE0
	    READ2;
	    doPitchBend( (( data[ 1 ] << 7 ) & 0xFF00) | data[ 0 ] );
	    break;
	    
	case MIDI_SYSTEM_PREFIX: //0xF0
	    switch( channel )
	    {
	    case 0:
		break;
	    }
	    break;
	    
	default:
	    debug( DEBUG_STATUS, "[%d]\n", cmd );
	}
    }

    pthread_exit(0);

    /* not reached */
    return( NULL );
}