Example #1
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called when a MIDI package has been received
/////////////////////////////////////////////////////////////////////////////
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
{
  // Note On received?
  if( midi_package.type == NoteOn &&
      midi_package.chn == Chn1 &&
      midi_package.velocity > 0 ) {

    // determine base key number (0=C, 1=C#, 2=D, ...)
    u8 base_key = midi_package.note % 12;

    // branch depending on note
    switch( base_key ) {
      case 0: // "C" starts the sequencer
	MIOS32_MIDI_SendDebugMessage("Start\n");
	// if in auto mode and BPM generator is clocked in slave mode:
	// change to master mode
	SEQ_BPM_CheckAutoMaster();
	// start sequencer
	SEQ_BPM_Start();
	break;

      case 2: // "D" stops the sequencer. If pressed twice, the sequencer will be reset
	MIOS32_MIDI_SendDebugMessage("Stop\n");
	if( SEQ_BPM_IsRunning() )
	  SEQ_BPM_Stop();          // stop sequencer
	else
	  SEQ_Reset(1);            // reset sequencer
	break;

      case 4: // "E" pauses the sequencer
	// if in auto mode and BPM generator is clocked in slave mode:
	// change to master mode
	SEQ_BPM_CheckAutoMaster();

	// toggle pause mode
	seq_pause ^= 1;

	MIOS32_MIDI_SendDebugMessage("Pause %s\n", seq_pause ? "on" : "off");

	// execute stop/continue depending on new mode
	if( seq_pause )
	  SEQ_BPM_Stop();         // stop sequencer
	else
	  SEQ_BPM_Cont();         // continue sequencer
	break;

      case 5: // "F" switches to next file
	MIOS32_MIDI_SendDebugMessage("Next File\n");
	SEQ_PlayFileReq(1);
	break;
    }
  }
}
Example #2
0
/////////////////////////////////////////////////////////////////////////////
// Should be called whenever a Note event has been received.
// We expect, that velocity is 0 on a Note Off event
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_NotifyNoteOn(u8 note, u8 velocity)
{
  u8 clear_stack = 0;

  if( velocity )
    // push note into note stack
    NOTESTACK_Push(&notestack, note, velocity);
  else {
    // remove note from note stack
    // function returns 2 if no note played anymore (all keys depressed)
    if( NOTESTACK_Pop(&notestack, note) == 2 )
      clear_stack = 1;
  }

  // At least one note played?
  if( !clear_stack && notestack.len > 0 ) {
    // start sequencer if it isn't already running
    if( !SEQ_BPM_IsRunning() )
      SEQ_BPM_Start();
  } else {
    // clear stack
    NOTESTACK_Clear(&notestack);

    // no key is pressed anymore: stop sequencer
    SEQ_BPM_Stop();
  }


#if 1
  // optional debug messages
  NOTESTACK_SendDebugMessage(&notestack);
#endif

  return 0; // no error
}
Example #3
0
/////////////////////////////////////////////////////////////////////////////
// Allows to request to play the next file from a lower priority task
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_PlayFileReq(u32 next)
{
  // stop generator
  SEQ_BPM_Stop();

  // request next file
  next_file_req = next ? 2 : 1;

  return 0; // no error
}
Example #4
0
/////////////////////////////////////////////////////////////////////////////
//! To control the stop button function
/////////////////////////////////////////////////////////////////////////////
s32 MBNG_SEQ_StopButton(void)
{
  if( SEQ_BPM_IsRunning() ) {
    SEQ_BPM_Stop();          // stop sequencer
  } else {
    // reset sequencer
    MBNG_SEQ_Reset();

    // disable pause mode
    MBNG_SEQ_SetPauseMode(0);
  }

  return 0; // no error
}
Example #5
0
/////////////////////////////////////////////////////////////////////////////
// Plays the first .mid file if next == 0, the next file if next != 0
/////////////////////////////////////////////////////////////////////////////
static s32 SEQ_PlayFile(u32 next)
{
  // play off events before loading new file
  SEQ_PlayOffEvents();

  char next_file[13];
  if( MID_FILE_FindNext(next ? MID_FILE_UI_NameGet() : NULL, next_file) == 1 ||
      MID_FILE_FindNext(NULL, next_file) == 1 ) { // if next file not found, try first file
#if DEBUG_VERBOSE_LEVEL >= 1
    DEBUG_MSG("[SEQ] next file found '%s'\n", next_file);
#endif
    SEQ_BPM_Stop();                  // stop BPM generator
    if( MID_FILE_open(next_file) ) { // try to open next file
#if DEBUG_VERBOSE_LEVEL >= 1
      DEBUG_MSG("[SEQ] file %s cannot be opened (wrong directory?)\n", next_file);
#endif
      return -1; // file cannot be opened
    }
    if( MID_PARSER_Read() < 0 ) { // read file, stop on failure
#if DEBUG_VERBOSE_LEVEL >= 1
      DEBUG_MSG("[SEQ] file %s is invalid!\n", next_file);
#endif
      return -2; // file is invalid
    } 
    SEQ_BPM_Start();          // start BPM generator
  } else {
    SEQ_BPM_Stop();           // stop BPM generator

#if DEBUG_VERBOSE_LEVEL >= 1
    DEBUG_MSG("[SEQ] no file found\n");
#endif
    return -1; // file not found
  }

  return 0; // no error
}
Example #6
0
/////////////////////////////////////////////////////////////////////////////
//! To control the stop button function
/////////////////////////////////////////////////////////////////////////////
s32 MBNG_SEQ_PauseButton(void)
{
  // if in auto mode and BPM generator is not clocked in slave mode:
  // change to master mode
  SEQ_BPM_CheckAutoMaster();

  // toggle pause
  seq_pause ^= 1;

  // execute stop/continue depending on new mode
  MIOS32_IRQ_Disable();
  if( seq_pause ) {
    SEQ_BPM_Stop();
  } else {
    if( !SEQ_BPM_IsRunning() )
      SEQ_BPM_Cont();
  }
  MIOS32_IRQ_Enable();

  return 0; // no error
}
Example #7
0
void MClock_User_Stop(void) {
    SEQ_BPM_Stop();
}
Example #8
0
/////////////////////////////////////////////////////////////////////////////
// fetches the pos entries of a song
// returns -1 if recursion counter reached max position
/////////////////////////////////////////////////////////////////////////////
s32 SEQ_SONG_FetchPos(u8 force_immediate_change, u8 dont_dump_mixer_map)
{
  int recursion_ctr = 0;

  u8 again;
  do {
    again = 0;

    // stop song once recursion counter reached 64 loops
    if( ++recursion_ctr >= 64 ) {
      SEQ_BPM_Stop();
      return -1; // recursion detected
    }

    // reset song position if we reached the end (loop over 128 steps)
    if( song_pos >= SEQ_SONG_NUM_STEPS )
      song_pos = 0;

    // get step entry
    seq_song_step_t *s = (seq_song_step_t *)&seq_song_steps[song_pos];

    // branch depending on action
    switch( s->action ) {
      case SEQ_SONG_ACTION_End:
#if 0
	if( song_active ) // not in phrase mode
	  SEQ_BPM_Stop();
#else
	song_finished = 1; // deactivate song incrementer
#endif
	break;

      case SEQ_SONG_ACTION_JmpPos:
	song_pos = s->action_value % SEQ_SONG_NUM_STEPS;
	again = 1;
	break;

      case SEQ_SONG_ACTION_JmpSong: {
	if( song_active ) { // not in phrase mode
	  u32 new_song_num = s->action_value % SEQ_SONG_NUM;

	  SEQ_SONG_Save(song_num);
	  SEQ_SONG_Load(new_song_num);
	  song_pos = 0;
	  again = 1;
	}
      } break;

      case SEQ_SONG_ACTION_SelMixerMap:
	SEQ_MIXER_Load(s->action_value);
	SEQ_MIDI_IN_ExtCtrlSend(SEQ_MIDI_IN_EXT_CTRL_MIXER_MAP, s->action_value, 0);
	if( !dont_dump_mixer_map )
	  SEQ_MIXER_SendAll();
	++song_pos;
	again = 1;
	break;

      case SEQ_SONG_ACTION_Tempo: {
	float bpm = (float)s->action_value;
	if( bpm < 25.0 )
	  bpm = 25.0;
	float ramp = (float)s->pattern_g1;
	SEQ_CORE_BPM_Update(bpm, ramp);
	++song_pos;
	again = 1;
      } break;

      case SEQ_SONG_ACTION_Mutes: {
	// access to seq_core_trk[] must be atomic!
	portENTER_CRITICAL();

	seq_core_trk_muted =
	  ((s->pattern_g1 & 0x0f) <<  0) |
	  ((s->pattern_g2 & 0x0f) <<  4) |
	  ((s->pattern_g3 & 0x0f) <<  8) |
	  ((s->pattern_g4 & 0x0f) << 12);

	portEXIT_CRITICAL();

	++song_pos;
	again = 1;
      } break;

      case SEQ_SONG_ACTION_GuideTrack: {
	if( s->action_value <= 16 )
	  seq_song_guide_track = s->action_value;
	++song_pos;
	again = 1;
      } break;

      default:
	if( s->action >= SEQ_SONG_ACTION_Loop1 && s->action <= SEQ_SONG_ACTION_Loop16 ) {
	  song_loop_ctr = 0;
	  song_loop_ctr_max = s->action - SEQ_SONG_ACTION_Loop1;

	  // TODO: implement prefetching until end of step!
	  
	  SEQ_SONG_FetchHlp_PatternChange(0, s->pattern_g1, s->bank_g1, force_immediate_change);
	  SEQ_SONG_FetchHlp_PatternChange(1, s->pattern_g2, s->bank_g2, force_immediate_change);
	  SEQ_SONG_FetchHlp_PatternChange(2, s->pattern_g3, s->bank_g3, force_immediate_change);
	  SEQ_SONG_FetchHlp_PatternChange(3, s->pattern_g4, s->bank_g4, force_immediate_change);
	}
    }

  } while( again );

  return 0; // no error
}
Example #9
0
/////////////////////////////////////////////////////////////////////////////
//! This task is running endless in background
/////////////////////////////////////////////////////////////////////////////
void APP_Background(void)
{
  const u16 sdcard_check_delay = 1000;
  u16 sdcard_check_ctr = 0;
  u8 lun_available = 0;
  static u8 isInMainPage = 1;

  SCS_DisplayUpdateInMainPage(0);
  MBNG_LCD_SpecialCharsReInit();

  u32 last_timestamp = MIOS32_TIMESTAMP_Get();
  while( 1 ) {
    //vTaskDelay(1 / portTICK_RATE_MS);
    // Background task: use timestamp mechanism to generate delay
    while( MIOS32_TIMESTAMP_Get() == last_timestamp );
    last_timestamp = MIOS32_TIMESTAMP_Get();

    // call SCS handler
    MUTEX_LCD_TAKE;
    MIOS32_LCD_FontInit((u8 *)GLCD_FONT_NORMAL);
    SCS_Tick();

    SCS_DisplayUpdateInMainPage((MBNG_EVENT_MidiLearnModeGet() || MBNG_EVENT_EventLearnIdGet()) ? 1 : 0);

    // LCD output in mainpage
    if( SCS_MenuStateGet() == SCS_MENU_STATE_MAINPAGE && !MBNG_EVENT_MidiLearnModeGet() && !MBNG_EVENT_EventLearnIdGet() ) {
      u8 force = isInMainPage == 0;
      if( force ) { // page change
	MBNG_LCD_SpecialCharsReInit();
	MBNG_LCD_CursorSet(SCS_LCD_DeviceGet(), SCS_LCD_OffsetXGet(), SCS_LCD_OffsetYGet() + 0);
	MBNG_LCD_PrintSpaces(SCS_NumMenuItemsGet()*SCS_MENU_ITEM_WIDTH);
	MBNG_LCD_CursorSet(SCS_LCD_DeviceGet(), SCS_LCD_OffsetXGet(), SCS_LCD_OffsetYGet() + 1);
	MBNG_LCD_PrintSpaces(SCS_NumMenuItemsGet()*SCS_MENU_ITEM_WIDTH);
      }

      MBNG_EVENT_UpdateLCD(force);

      // handles .NGR file execution
      MBNG_FILE_R_CheckRequest();

      isInMainPage = 1; // static reminder
    } else {
      if( isInMainPage && (MBNG_EVENT_MidiLearnModeGet() || MBNG_EVENT_EventLearnIdGet()) ) {
	SCS_LCD_Update(1); // force display update when learn mode is entered in mainpage
      }

      isInMainPage = 0; // static reminder
    }

    // handles .NGR file execution
    MBNG_FILE_R_CheckRequest();

    MUTEX_LCD_GIVE;

    // -> keyboard handler
    KEYBOARD_Periodic_1mS();

    // MIDI In/Out monitor
    MIDI_PORT_Period1mS();

    // call MIDI event tick
    MBNG_EVENT_Tick();

    // each second: check if SD Card (still) available
    if( msd_state == MSD_DISABLED && ++sdcard_check_ctr >= sdcard_check_delay ) {
      sdcard_check_ctr = 0;

      MUTEX_SDCARD_TAKE;
      s32 status = FILE_CheckSDCard();

      if( status == 1 ) {
	DEBUG_MSG("SD Card connected: %s\n", FILE_VolumeLabel());

	// stop sequencer
	SEQ_BPM_Stop();

	// load all file infos
	MBNG_FILE_LoadAllFiles(1); // including HW info

	// select the first bank
	MBNG_EVENT_SelectedBankSet(1);

	// immediately go to next step
	sdcard_check_ctr = sdcard_check_delay;
      } else if( status == 2 ) {
	DEBUG_MSG("SD Card disconnected\n");
	// invalidate all file infos
	MBNG_FILE_UnloadAllFiles();

	// stop sequencer
	SEQ_BPM_Stop();

	// change status
	MBNG_FILE_StatusMsgSet("No SD Card");

	MUTEX_LCD_TAKE;
	MBNG_LCD_CursorSet(0, 0, 0);
	MBNG_LCD_PrintString("*** No SD Card *** ");
	MBNG_LCD_ClearScreenOnNextMessage();
	MUTEX_LCD_GIVE;
      } else if( status == 3 ) {
	if( !FILE_SDCardAvailable() ) {
	  DEBUG_MSG("SD Card not found\n");
	  MBNG_FILE_StatusMsgSet("No SD Card");

	  MUTEX_LCD_TAKE;
	  MBNG_LCD_CursorSet(0, 0, 0);
	  MBNG_LCD_PrintString("*** No SD Card *** ");
	  MBNG_LCD_ClearScreenOnNextMessage();
	  MUTEX_LCD_GIVE;
	} else if( !FILE_VolumeAvailable() ) {
	  DEBUG_MSG("ERROR: SD Card contains invalid FAT!\n");
	  MBNG_FILE_StatusMsgSet("No FAT");

	  MUTEX_LCD_TAKE;
	  MBNG_LCD_CursorSet(0, 0, 0);
	  MBNG_LCD_PrintString("* No FAT on SD Card * ");
	  MBNG_LCD_ClearScreenOnNextMessage();
	  MUTEX_LCD_GIVE;
	} else {
	  MBNG_FILE_StatusMsgSet(NULL);

	  // create the default files if they don't exist on SD Card
	  MBNG_FILE_CreateDefaultFiles();
	}

	hw_enabled = 1; // enable hardware after first read...
      }

      MUTEX_SDCARD_GIVE;
    }

    // MSD driver
    if( msd_state != MSD_DISABLED ) {
      MUTEX_SDCARD_TAKE;

      switch( msd_state ) {
      case MSD_SHUTDOWN:
	// switch back to USB MIDI
	MIOS32_USB_Init(1);
	msd_state = MSD_DISABLED;
	break;

      case MSD_INIT:
	// LUN not mounted yet
	lun_available = 0;

	// enable MSD USB driver
	MUTEX_J16_TAKE;
	if( MSD_Init(0) >= 0 )
	  msd_state = MSD_READY;
	else
	  msd_state = MSD_SHUTDOWN;
	MUTEX_J16_GIVE;
	break;

      case MSD_READY:
	// service MSD USB driver
	MSD_Periodic_mS();

	// this mechanism shuts down the MSD driver if SD card has been unmounted by OS
	if( lun_available && !MSD_LUN_AvailableGet(0) )
	  msd_state = MSD_SHUTDOWN;
	else if( !lun_available && MSD_LUN_AvailableGet(0) )
	  lun_available = 1;
	break;
      }

      MUTEX_SDCARD_GIVE;
    }
  }
}
Example #10
0
/////////////////////////////////////////////////////////////////////////////
// This task is called periodically each mS to handle sequencer requests
/////////////////////////////////////////////////////////////////////////////
static void TASK_SEQ(void *pvParameters)
{
  portTickType xLastExecutionTime;
  u16 sdcard_check_ctr = 0;

  // Initialise the xLastExecutionTime variable on task entry
  xLastExecutionTime = xTaskGetTickCount();

  while( 1 ) {
    vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK_RATE_MS);

    // execute sequencer handler
    SEQ_Handler();

    // send timestamped MIDI events
    SEQ_MIDI_OUT_Handler();

    // each second: check if SD Card (still) available
    if( ++sdcard_check_ctr >= 1000 ) {
      sdcard_check_ctr = 0;

      // use a mutex if multiple tasks access the SD Card!
      MUTEX_SDCARD_TAKE;
      s32 status = FILE_CheckSDCard();

      if( status == 1 ) {
	MIOS32_MIDI_SendDebugMessage("SD Card connected: %s\n", FILE_VolumeLabel());
      } else if( status == 2 ) {
	MIOS32_MIDI_SendDebugMessage("SD Card disconnected\n");

	// stop sequencer
	SEQ_BPM_Stop();

	// change filename
	sprintf(MID_FILE_UI_NameGet(), "No SD Card");
      } else if( status == 3 ) {
	if( !FILE_SDCardAvailable() ) {
	  MIOS32_MIDI_SendDebugMessage("SD Card not found\n");
	  // change filename
	  sprintf(MID_FILE_UI_NameGet(), "No SD Card");
	} else if( !FILE_VolumeAvailable() ) {
	  MIOS32_MIDI_SendDebugMessage("ERROR: SD Card contains invalid FAT!\n");
	  MIOS32_BOARD_LED_Set(0x1, 0x0); // turn off LED
	  // change filename
	  sprintf(MID_FILE_UI_NameGet(), "No FAT");
	  // stop sequencer
	  SEQ_BPM_Stop();
	} else {
	  // change filename
	  sprintf(MID_FILE_UI_NameGet(), "SDCard found");
	  // if in auto mode and BPM generator is clocked in slave mode:
	  // change to master mode
	  SEQ_BPM_CheckAutoMaster();
	  // reset sequencer
	  SEQ_Reset(1);
	  // request to play the first file
	  SEQ_PlayFileReq(0);
	  // start sequencer
	  SEQ_BPM_Start();
	}
      }
      MUTEX_SDCARD_GIVE;
    }
  }
}