/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_MidiSequencePlayer.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include namespace nw { namespace snd { namespace internal { namespace driver { /* ======================================================================== public function ======================================================================== */ /*---------------------------------------------------------------------------* Name: MidiSequencePlayer Description: コンストラクタ Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ MidiSequencePlayer::MidiSequencePlayer() { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { m_NoteInfo[i].channel = NULL; } } MidiSequencePlayer::~MidiSequencePlayer() { } void MidiSequencePlayer::Start() { SequenceSoundPlayer::Start(); // 全てのトラックをOpenしないとトラックのチャンネルがUpdateされない for( int trackNo = 0; trackNo < TRACK_NUM_PER_PLAYER ; trackNo++ ) { SequenceTrack* track = GetPlayerTrack( trackNo ); if ( track == NULL ) continue; track->Open(); } } void MidiSequencePlayer::SendMessage( u8 status, u8 data1, u8 data2 ) { u8 channel = static_cast(status & 0x0f); switch ( status & 0xf0 ) { case MIDI_MSG_NOTE_OFF: NoteOff( channel, data1, data2 ); break; case MIDI_MSG_NOTE_ON: if (data2 != 0) { NoteOn( channel, data1, data2 ); } else { NoteOff( channel, data1, data2 ); } break; case MIDI_MSG_POLY_KEY_PRESSURE: break; case MIDI_MSG_CONTROL_CHANGE: if ( data1 < 120 ) { HandleControlChangeMessage( channel, data1, data2 ); } else { HandleChannelModeMessage( data1, data2 ); } break; case MIDI_MSG_PROGRAM_CHANGE: HandleProgramChangeMessage( channel, data1 ); break; case MIDI_MSG_CHANNEL_PRESSURE: break; case MIDI_MSG_PITCH_BEND: HandlePitchBendMessage( channel, data1, data2 ); break; case MIDI_MSG_SYSTEM: switch (status) { case 0xfe: // active sencing break; case 0xff: // reset Reset(); break; } break; } } void MidiSequencePlayer::SetProgramNumber( int channelIndex, int prgNo ) { SequenceTrack* track = GetPlayerTrack( channelIndex ); track->GetParserTrackParam().prgNo = prgNo; } void MidiSequencePlayer::NoteOn( u8 channelIndex, u8 key, u8 velocity ) { SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track == NULL ) return; SequenceTrack::ParserTrackParam& trackParam = track->GetParserTrackParam(); key = static_cast( ut::Clamp( key + trackParam.transpose, 0, 127 ) ); if ( trackParam.monophonicFlag ) { NoteInfo* noteInfo = FindNoteInfo( channelIndex ); if ( noteInfo != NULL ) { Channel* channel = noteInfo->channel; if ( ! channel->IsRelease() ) { channel->SetKey( key ); float initVolume = static_cast( velocity ) / 127.0f; channel->SetInitVolume( initVolume * initVolume ); noteInfo->key = key; return; } channel->Stop(); noteInfo->channel = NULL; } } Channel* channel = track->NoteOn( key, velocity, -1, false ); if ( channel == NULL ) return; NoteInfo* noteInfo = FindFreeNoteInfo(); NW_NULL_ASSERT( noteInfo ); noteInfo->channel = channel; noteInfo->channelIndex = channelIndex; noteInfo->key = key; } void MidiSequencePlayer::NoteOff( u8 channelIndex, u8 key, u8 velocity ) { (void)velocity; SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track == NULL ) return; SequenceTrack::ParserTrackParam& param = track->GetParserTrackParam(); key = static_cast( ut::Clamp( key + param.transpose, 0, 127 ) ); while( 1 ) { NoteInfo* noteInfo = FindNoteInfo( channelIndex, key ); if ( noteInfo == NULL ) break; noteInfo->channel->SetLength( 0 ); track->UpdateChannelRelease( noteInfo->channel ); noteInfo->channel = NULL; } } void MidiSequencePlayer::HandleControlChangeMessage( u8 channelIndex, u8 control, u8 value ) { SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track == NULL ) return; SequenceSoundPlayer* player = track->GetSequenceSoundPlayer(); if ( player == NULL ) return; SequenceTrack::ParserTrackParam& param = track->GetParserTrackParam(); SequenceSoundPlayer::ParserPlayerParam& playerParam = player->GetParserPlayerParam(); switch ( control ) { case MIDI_CTRLCHG_BANK_SELECT: param.bankIndex = value; break; case MIDI_CTRLCHG_MOD_DEPTH: param.lfoParam.depth = value / 128.0f; break; case MIDI_CTRLCHG_INIT_PAN: param.initPan = static_cast(value - 64); break; case MIDI_CTRLCHG_PORTA_TIME: param.portaTime = value; break; case MIDI_CTRLCHG_DATA_ENTRY: switch ( m_ParameterControlInfo[ channelIndex ].mode ) { case ParameterControlInfo::RPN: HandleRpnMessage( channelIndex, value ); break; case ParameterControlInfo::NRPN: HandleNrpnMessage( channelIndex, value ); break; } break; case MIDI_CTRLCHG_VOLUME: param.volume.SetTarget( value, 0 ); break; #ifdef NW_PLATFORM_RVL case MIDI_CTRLCHG_SPAN: param.surroundPan.SetTarget( static_cast(value), 0 ); break; #endif case MIDI_CTRLCHG_PAN: param.pan.SetTarget( static_cast(value - 64), 0 ); break; case MIDI_CTRLCHG_EXPRESSION: param.volume2 = value; break; case MIDI_CTRLCHG_MAIN_VOLUME: playerParam.volume = value; break; case MIDI_CTRLCHG_TRANSPOSE: param.transpose = static_cast(value - 64); break; case MIDI_CTRLCHG_PRIORITY: param.priority = value; break; case MIDI_CTRLCHG_SETVAR_0: case MIDI_CTRLCHG_SETVAR_1: case MIDI_CTRLCHG_SETVAR_2: case MIDI_CTRLCHG_SETVAR_3: track->SetTrackVariable( control - MIDI_CTRLCHG_SETVAR_0, value ); break; case MIDI_CTRLCHG_BEND_RANGE: param.bendRange = value; break; case MIDI_CTRLCHG_MOD_SPEED: param.lfoParam.speed = value * 0.390625f; break; case MIDI_CTRLCHG_MOD_TYPE: param.lfoTarget = value; break; case MIDI_CTRLCHG_MOD_RANGE: param.lfoParam.range = value; break; case MIDI_CTRLCHG_BIQUAD_TYPE: param.biquadType = value; break; case MIDI_CTRLCHG_BIQUAD_VALUE: param.biquadValue = static_cast( value ) / 127.0f; break; case MIDI_CTRLCHG_MOD_DELAY: param.lfoParam.delay = static_cast( value * 5 ); break; case MIDI_CTRLCHG_MOD_DELAY_10: param.lfoParam.delay = static_cast( (value * 5) * 10 ); break; case MIDI_CTRLCHG_SWEEP_PITCH: param.sweepPitch = (value - 64) / 64.0f; break; case MIDI_CTRLCHG_SWEEP_PITCH_24: param.sweepPitch = (value - 64) / 64.0f * 24; break; case MIDI_CTRLCHG_DAMPER: param.damperFlag = (value >= 64) ? true : false; break; case MIDI_CTRLCHG_PORTA: param.portaFlag = (value >= 64) ? true : false; break; case MIDI_CTRLCHG_MONOPHONIC: param.monophonicFlag = (value >= 64) ? true : false; if ( param.monophonicFlag ) { NoteOffAll(); } break; case MIDI_CTRLCHG_CUTOFF: param.lpfFreq = static_cast( value - 64 ) / 64.0f; break; case MIDI_CTRLCHG_PORTA_CONTROL: param.portaKey = static_cast(value + param.transpose); param.portaFlag = true; break; case MIDI_CTRLCHG_ATTACK: param.attack = value; break; case MIDI_CTRLCHG_DECAY: param.decay = value; break; case MIDI_CTRLCHG_SUSTAIN: param.sustain = value; break; case MIDI_CTRLCHG_RELEASE: param.release = value; break; case MIDI_CTRLCHG_ENV_HOLD: param.envHold = value; break; case MIDI_CTRLCHG_FXSEND_A: param.fxSend[ AUX_BUS_A ] = value; break; case MIDI_CTRLCHG_FXSEND_B: param.fxSend[ AUX_BUS_B ] = value; break; #ifdef NW_PLATFORM_RVL case MIDI_CTRLCHG_FXSEND_C: param.fxSend[ AUX_BUS_C ] = value; break; #endif case MIDI_CTRLCHG_MAINSEND: param.mainSend = value; break; case MIDI_CTRLCHG_NRPN_LSB: m_ParameterControlInfo[ channelIndex ].nrpnLsb = value; m_ParameterControlInfo[ channelIndex ].mode = ParameterControlInfo::NRPN; break; case MIDI_CTRLCHG_NRPN_MSB: m_ParameterControlInfo[ channelIndex ].nrpnMsb = value; m_ParameterControlInfo[ channelIndex ].mode = ParameterControlInfo::NRPN; break; case MIDI_CTRLCHG_RPN_LSB: m_ParameterControlInfo[ channelIndex ].rpnLsb = value; m_ParameterControlInfo[ channelIndex ].mode = ParameterControlInfo::RPN; break; case MIDI_CTRLCHG_RPN_MSB: m_ParameterControlInfo[ channelIndex ].rpnMsb = value; m_ParameterControlInfo[ channelIndex ].mode = ParameterControlInfo::RPN; break; case MIDI_CTRLCHG_FRONTBYPASS: param.frontBypassFlag = (value >= 64) ? true : false; break; } } void MidiSequencePlayer::HandleRpnMessage( u8 channelIndex, u8 value ) { int parameterNumber = ( static_cast( m_ParameterControlInfo[ channelIndex ].rpnMsb ) << 8 ) + m_ParameterControlInfo[ channelIndex ].rpnLsb ; SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track == NULL ) return; SequenceSoundPlayer* player = track->GetSequenceSoundPlayer(); if ( player == NULL ) return; SequenceTrack::ParserTrackParam& param = track->GetParserTrackParam(); SequenceSoundPlayer::ParserPlayerParam& playerParam = player->GetParserPlayerParam(); switch ( parameterNumber ) { case MIDI_RPN_PITCHBEND_SENSITIVITY: param.bendRange = value; break; case MIDI_RPN_NULL: break; } } void MidiSequencePlayer::HandleNrpnMessage( u8 channelIndex, u8 value ) { int parameterNumber = ( static_cast( m_ParameterControlInfo[ channelIndex ].nrpnMsb ) << 8 ) + m_ParameterControlInfo[ channelIndex ].nrpnLsb ; SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track == NULL ) return; SequenceSoundPlayer* player = track->GetSequenceSoundPlayer(); if ( player == NULL ) return; SequenceTrack::ParserTrackParam& param = track->GetParserTrackParam(); SequenceSoundPlayer::ParserPlayerParam& playerParam = player->GetParserPlayerParam(); (void)value; switch ( parameterNumber ) { case MIDI_NRPN_ENV_RESET: param.attack = SequenceTrack::INVALID_ENVELOPE; param.decay = SequenceTrack::INVALID_ENVELOPE; param.sustain = SequenceTrack::INVALID_ENVELOPE; param.release = SequenceTrack::INVALID_ENVELOPE; param.envHold = SequenceTrack::INVALID_ENVELOPE; break; case MIDI_NRPN_NULL: break; } } void MidiSequencePlayer::HandleChannelModeMessage( u8 control, u8 value ) { (void)value; switch( control ) { case MIDI_MODEMSG_ALL_SOUND_OFF: StopAllSound(); break; case MIDI_MODEMSG_RESET_ALL_CONTROLER: ResetAllController(); break; case MIDI_MODEMSG_LOCAL_CONTROL: break; case MIDI_MODEMSG_ALL_NOTE_OFF: NoteOffAll(); break; case MIDI_MODEMSG_OMNI_OFF: case MIDI_MODEMSG_OMNI_ON: case MIDI_MODEMSG_MONO_MODE: case MIDI_MODEMSG_POLY_MODE: break; } } void MidiSequencePlayer::HandleProgramChangeMessage( u8 channelIndex, u8 program ) { SetProgramNumber( channelIndex, program ); } void MidiSequencePlayer::HandlePitchBendMessage( u8 channelIndex, u8 lsb, u8 msb ) { s16 value = static_cast( ((msb << 7) | lsb) - 0x2000 ); value >>= 6; SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track == NULL ) return; SequenceTrack::ParserTrackParam& param = track->GetParserTrackParam(); param.pitchBend.SetTarget( static_cast(value), 0 ); } void MidiSequencePlayer::NoteOffAll() { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { if ( m_NoteInfo[i].channel != NULL ) { m_NoteInfo[i].channel->Release(); m_NoteInfo[i].channel = NULL; } } } void MidiSequencePlayer::StopAllSound() { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { if ( m_NoteInfo[i].channel != NULL ) { m_NoteInfo[i].channel = NULL; } } for ( int channelIndex = 0 ; channelIndex < TRACK_NUM_PER_PLAYER ; channelIndex++ ) { SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track != NULL ) { track->StopAllChannel(); } } } void MidiSequencePlayer::ResetAllController() { for ( int channelIndex = 0 ; channelIndex < TRACK_NUM_PER_PLAYER ; channelIndex++ ) { SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track != NULL ) { track->InitParam(); } } } void MidiSequencePlayer::Reset() { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { if ( m_NoteInfo[i].channel != NULL ) { m_NoteInfo[i].channel = NULL; } } for ( int channelIndex = 0 ; channelIndex < TRACK_NUM_PER_PLAYER ; channelIndex++ ) { SequenceTrack* track = GetPlayerTrack( channelIndex ); if ( track != NULL ) { track->StopAllChannel(); track->InitParam(); } } } MidiSequencePlayer::NoteInfo* MidiSequencePlayer::FindFreeNoteInfo() { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { if ( m_NoteInfo[i].channel == NULL ) { return &m_NoteInfo[i]; } } return NULL; } MidiSequencePlayer::NoteInfo* MidiSequencePlayer::FindNoteInfo( int channelIndex, int key ) { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { if ( m_NoteInfo[i].channel != NULL && m_NoteInfo[i].channelIndex == channelIndex && m_NoteInfo[i].key == key ) { return &m_NoteInfo[i]; } } return NULL; } MidiSequencePlayer::NoteInfo* MidiSequencePlayer::FindNoteInfo( int channelIndex ) { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { if ( m_NoteInfo[i].channel != NULL && m_NoteInfo[i].channelIndex == channelIndex ) { return &m_NoteInfo[i]; } } return NULL; } void MidiSequencePlayer::ChannelCallback( Channel* channel ) { for( int i = 0 ; i < NOTE_INFO_COUNT ; i++ ) { if ( m_NoteInfo[i].channel == channel ) { m_NoteInfo[i].channel = NULL; } } } } // namespace nw::snd::internal::driver } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw