diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2013-09-17 02:14:21 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2013-09-17 02:14:21 -0700 |
commit | 844d31616bfd90cf743489897bf2ceb3b72c27e3 (patch) | |
tree | 0ba5b0ac6ad484a3e8c8c9055474234f564cd1c3 | |
parent | 72f567f6560ad2fda9bb82ebe9abf8ad4911e67e (diff) | |
download | sekaiju-844d31616bfd90cf743489897bf2ceb3b72c27e3.tar.gz sekaiju-844d31616bfd90cf743489897bf2ceb3b72c27e3.tar.bz2 sekaiju-844d31616bfd90cf743489897bf2ceb3b72c27e3.zip |
This commit solves a remaining problem of events accidentally looping back
during recording when midi through is disabled in the binding array.
The problem is caused by the fact that the real-time events are inserted into
the tracks just at the start of the next clock period. When the next clock
period comes, those events are played back! (This also causes a delay:
since the looped notes will not play until the next clock advance!)
To solve this problem we do two things:
1. Rearrange the processing so that playback, metronome generation
et cetera are handled first in every processing period, and the real-time
input is handled afterward.
2. Now that real-time inputs are handled after playback, we can simply insert
them into the CURRENT time period. Since playback is already done
for the current time period before, they will not be played.
Referring new events into the current time period is done by subtracting
one from the clock value. Sekaiju's logic for handling time periods
is that each time period is an interval that excludes the current
time: [old_time, new_time). So when an new event is inserted at new_time,
it becomes part of the next period. By inserting an event at new_time - 1,
we make it part of the current period.
Hey, I wrote some comments in Japanese. :)
-rw-r--r-- | src/SekaijuApp.cpp | 350 |
1 files changed, 177 insertions, 173 deletions
diff --git a/src/SekaijuApp.cpp b/src/SekaijuApp.cpp index 8af01a5..0b64aa2 100644 --- a/src/SekaijuApp.cpp +++ b/src/SekaijuApp.cpp @@ -1537,179 +1537,6 @@ BOOL CSekaijuApp::PlayRecordProc (LPVOID pInfo) { long lTimeMode = MIDIData_GetTimeMode (pMIDIData);
long lTimeResolution = MIDIData_GetTimeResolution (pMIDIData);
- // データの入力処理(記録用)
- // 各MIDI入力デバイスについて
- for (i = 0; i < MAXMIDIINDEVICENUM; i++) {
- // MIDI入力デバイスが有効ならば
- if (m_pMIDIIn[i] != NULL) {
- int nMidiThru = pSekaijuApp->m_nMIDIThruBinding[i] - 1;
- long lMIDIInSyncMode = pSekaijuApp->m_lMIDIInSyncMode[i];
- // MIDIメッセージの取得できる限り
- while (1) {
- // MIDIメッセージの取得
- memset (byMsg, 0, sizeof (byMsg));
- lLen = MIDIIn_GetMIDIMessage (m_pMIDIIn[i], byMsg, sizeof (byMsg));
- if (lLen <= 0) {
- break;
- }
- // MIDIInStatusへの記録
- MIDIStatus_PutMIDIMessage (m_pMIDIInStatus[i], byMsg, lLen);
-
- // ループ
- if (nMidiThru >= 0 && nMidiThru < MAXMIDIOUTDEVICENUM) {
- MIDIOut* pMIDIOut = m_pMIDIOut[nMidiThru];
- if (pMIDIOut)
- MIDIOut_PutMIDIMessage (pMIDIOut, byMsg, lLen);
- // MIDIチャンネルメッセージの場合
- if (0x80 <= byMsg[0] && byMsg[0] <= 0xEF) {
- MIDIStatus* pMIDIOutStatus = m_pMIDIOutStatus[nMidiThru];
- if (pMIDIOutStatus)
- MIDIStatus_PutMIDIMessage (pMIDIOutStatus, byMsg, lLen);
- }
- }
-
- // アクティブセンシングの場合
- if (byMsg[0] == 0xFE) {
- ;
- }
- // MIDIタイムコードクォーターフレームの場合
- else if (byMsg[0] == 0xF1 || byMsg[0] == 0xF0) {
- if (lMIDIInSyncMode >= 2) {
- if (pMIDIClock) {
- MIDIClock_PutMIDIMessage (pMIDIClock, byMsg, lLen);
- }
- }
- }
- // MIDIタイミングクロックの場合
- else if (byMsg[0] == 0xF8) {
- if (lMIDIInSyncMode == 1) {
- if (pMIDIClock) {
- MIDIClock_PutMIDIMessage (pMIDIClock, byMsg, lLen);
- }
- }
- }
- // ソングポジションセレクタの場合
- else if (byMsg[0] == 0xF2) {
- if (lMIDIInSyncMode == 1) {
- long lVal = ((byMsg[2] & 0x7F) << 7) | (byMsg[1] & 0x7F);
- long lTickCount = lVal * lTimeResolution / 4;
- SetPlayPosition (pSekaijuDoc, lTickCount);
- }
- }
- // スタートの場合
- else if (byMsg[0] == 0xFA && pSekaijuDoc) {
- if (pMIDIClock && !m_bPlaying && !m_bRecording) {
- pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_TOBEGIN, 0);
- pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
- }
- else if (pMIDIClock && m_bPlaying && !m_bRecording) { // 20090704追加
- pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_TOBEGIN, 0);
- pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
- }
- }
- // コンティニューの場合
- else if (byMsg[0] == 0xFB && pSekaijuDoc) {
- if (pSekaijuDoc->m_pMIDIClock && !m_bPlaying && !m_bRecording) {
- pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
- }
- }
- // ストップの場合
- else if (byMsg[0] == 0xFC && pSekaijuDoc) {
- if (pSekaijuDoc->m_pMIDIClock && (m_bPlaying || m_bRecording)) {
- pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
- }
- }
- // MIDIチャンネルメッセージの場合
- else if (0x80 <= byMsg[0] && byMsg[0] <= 0xEF && pSekaijuDoc) {
- // シンクロスタート処理
- if (m_bRecording && m_lCurSpeedIndex == 0) {
- m_lCurSpeedIndex = m_lOldSpeedIndex;
- MIDIClock_Stop (pMIDIClock);
- pSekaijuDoc->ApplyAppCurSpeedIndex ();
- MIDIClock_Start (pMIDIClock);
- }
- // リアルタイム入力処理
- MIDITrack* pMIDITrack = NULL;
- forEachTrack (pSekaijuDoc->m_pMIDIData, pMIDITrack) {
- long lInputOn = MIDITrack_GetInputOn (pMIDITrack);
- long lInputPort = MIDITrack_GetInputPort (pMIDITrack);
- long lInputChannel = MIDITrack_GetInputChannel (pMIDITrack);
- long lOutputOn = MIDITrack_GetOutputOn (pMIDITrack);
- long lOutputPort = MIDITrack_GetOutputPort (pMIDITrack);
- long lOutputChannel = MIDITrack_GetOutputChannel (pMIDITrack);
- if (lInputOn && lInputPort == i && lInputChannel == (byMsg[0] & 0x0F)) {
- // 出力チャンネルの変換
- BYTE byMsg2[sizeof(byMsg)];
- memcpy (byMsg2, byMsg, sizeof (byMsg));
- if (0 <= lOutputChannel && lOutputChannel < 16) {
- byMsg2[0] &= 0xF0;
- byMsg2[0] |= (BYTE)lOutputChannel;
- }
- // このMIDIメッセージをMIDIデータに記録
- if (m_bRecording) {
- MIDIEvent* pMIDIEvent = MIDIEvent_Create
- (pSekaijuDoc->m_lNewTime, (byMsg[0] & 0xF0), byMsg2, lLen);
- if (pMIDIEvent) {
- //pMIDIEvent->m_lUserFlag |= MIDIEVENT_REALTIMEGENERATE;
- MIDITrack_InsertEvent (pMIDITrack, pMIDIEvent);
- // ノートオフの場合のノートオンとの結合処理
- if (MIDIEvent_IsNoteOff (pMIDIEvent)) {
- long lTempRecordedEventCount = m_theTempRecordedEventArray.GetSize ();
- long j;
- for (j = lTempRecordedEventCount - 1; j >= 0; j--) {
- MIDIEvent* pTempEvent =
- (MIDIEvent*)(m_theTempRecordedEventArray.GetAt (j));
- if (MIDIEvent_IsNoteOn (pTempEvent) &&
- pTempEvent->m_pNextCombinedEvent == NULL) {
- if (MIDIEvent_GetChannel (pTempEvent) ==
- MIDIEvent_GetChannel (pMIDIEvent)) {
- if (MIDIEvent_GetKey (pTempEvent) ==
- MIDIEvent_GetKey (pMIDIEvent)) {
- pTempEvent->m_pNextCombinedEvent = pMIDIEvent;
- pMIDIEvent->m_pPrevCombinedEvent = pTempEvent;
- }
- }
- }
- }
- //MIDIEvent_Combine (pMIDIEvent);
- }
- m_theTempRecordedEventArray.Add (pMIDIEvent);
- }
- }
- }
- }
- }
- // システムエクスクルーシブメッセージの場合
- else if (byMsg[0] == 0xF0 || byMsg[0] == 0xF7) {
- // シンクロスタート処理
- if (m_bRecording && m_lCurSpeedIndex == 0) {
- m_lCurSpeedIndex = m_lOldSpeedIndex;
- MIDIClock_Stop (pMIDIClock);
- pSekaijuDoc->ApplyAppCurSpeedIndex ();
- MIDIClock_Start (pMIDIClock);
- }
- // リアルタイム入力処理
- MIDITrack* pMIDITrack = NULL;
- forEachTrack (pSekaijuDoc->m_pMIDIData, pMIDITrack) {
- long lInputOn = MIDITrack_GetInputOn (pMIDITrack);
- long lInputPort = MIDITrack_GetInputPort (pMIDITrack);
- long lInputChannel = MIDITrack_GetInputChannel (pMIDITrack);
- long lOutputOn = MIDITrack_GetOutputOn (pMIDITrack);
- long lOutputPort = MIDITrack_GetOutputPort (pMIDITrack);
- long lOutputChannel = MIDITrack_GetOutputChannel (pMIDITrack);
- if (lInputOn && lInputPort == i && lInputChannel == -1) {
- // このMIDIメッセージをMIDIデータに記録
- if (m_bRecording) {
- MIDITrack_InsertSysExEvent
- (pMIDITrack, pSekaijuDoc->m_lNewTime, byMsg, lLen);
- }
- }
- }
- }
- }
- }
- }
-
// MIDIタイミングクロックとSMPTE/MTCの送出処理(20090624追加)
if (m_bPlaying) {
long lOutputPort;
@@ -1999,6 +1826,183 @@ BOOL CSekaijuApp::PlayRecordProc (LPVOID pInfo) { }
}
+ // データの入力処理(記録用)
+ // 各MIDI入力デバイスについて
+ for (i = 0; i < MAXMIDIINDEVICENUM; i++) {
+ // MIDI入力デバイスが有効ならば
+ if (m_pMIDIIn[i] != NULL) {
+ int nMidiThru = pSekaijuApp->m_nMIDIThruBinding[i] - 1;
+ long lMIDIInSyncMode = pSekaijuApp->m_lMIDIInSyncMode[i];
+ // MIDIメッセージの取得できる限り
+ while (1) {
+ // MIDIメッセージの取得
+ memset (byMsg, 0, sizeof (byMsg));
+ lLen = MIDIIn_GetMIDIMessage (m_pMIDIIn[i], byMsg, sizeof (byMsg));
+ if (lLen <= 0) {
+ break;
+ }
+ // MIDIInStatusへの記録
+ MIDIStatus_PutMIDIMessage (m_pMIDIInStatus[i], byMsg, lLen);
+
+ // ループバック
+ if (nMidiThru >= 0 && nMidiThru < MAXMIDIOUTDEVICENUM) {
+ MIDIOut* pMIDIOut = m_pMIDIOut[nMidiThru];
+ if (pMIDIOut)
+ MIDIOut_PutMIDIMessage (pMIDIOut, byMsg, lLen);
+ // MIDIチャンネルメッセージの場合
+ if (0x80 <= byMsg[0] && byMsg[0] <= 0xEF) {
+ MIDIStatus* pMIDIOutStatus = m_pMIDIOutStatus[nMidiThru];
+ if (pMIDIOutStatus)
+ MIDIStatus_PutMIDIMessage (pMIDIOutStatus, byMsg, lLen);
+ }
+ }
+
+ // アクティブセンシングの場合
+ if (byMsg[0] == 0xFE) {
+ ;
+ }
+ // MIDIタイムコードクォーターフレームの場合
+ else if (byMsg[0] == 0xF1 || byMsg[0] == 0xF0) {
+ if (lMIDIInSyncMode >= 2) {
+ if (pMIDIClock) {
+ MIDIClock_PutMIDIMessage (pMIDIClock, byMsg, lLen);
+ }
+ }
+ }
+ // MIDIタイミングクロックの場合
+ else if (byMsg[0] == 0xF8) {
+ if (lMIDIInSyncMode == 1) {
+ if (pMIDIClock) {
+ MIDIClock_PutMIDIMessage (pMIDIClock, byMsg, lLen);
+ }
+ }
+ }
+ // ソングポジションセレクタの場合
+ else if (byMsg[0] == 0xF2) {
+ if (lMIDIInSyncMode == 1) {
+ long lVal = ((byMsg[2] & 0x7F) << 7) | (byMsg[1] & 0x7F);
+ long lTickCount = lVal * lTimeResolution / 4;
+ SetPlayPosition (pSekaijuDoc, lTickCount);
+ }
+ }
+ // スタートの場合
+ else if (byMsg[0] == 0xFA && pSekaijuDoc) {
+ if (pMIDIClock && !m_bPlaying && !m_bRecording) {
+ pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_TOBEGIN, 0);
+ pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
+ }
+ else if (pMIDIClock && m_bPlaying && !m_bRecording) { // 20090704追加
+ pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_TOBEGIN, 0);
+ pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
+ }
+ }
+ // コンティニューの場合
+ else if (byMsg[0] == 0xFB && pSekaijuDoc) {
+ if (pSekaijuDoc->m_pMIDIClock && !m_bPlaying && !m_bRecording) {
+ pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
+ }
+ }
+ // ストップの場合
+ else if (byMsg[0] == 0xFC && pSekaijuDoc) {
+ if (pSekaijuDoc->m_pMIDIClock && (m_bPlaying || m_bRecording)) {
+ pMainFrame->PostMessage (WM_COMMAND, ID_CONTROL_PLAY, 0);
+ }
+ }
+ // MIDIチャンネルメッセージの場合
+ else if (0x80 <= byMsg[0] && byMsg[0] <= 0xEF && pSekaijuDoc) {
+ // シンクロスタート処理
+ if (m_bRecording && m_lCurSpeedIndex == 0) {
+ m_lCurSpeedIndex = m_lOldSpeedIndex;
+ MIDIClock_Stop (pMIDIClock);
+ pSekaijuDoc->ApplyAppCurSpeedIndex ();
+ MIDIClock_Start (pMIDIClock);
+ }
+ // リアルタイム入力処理
+ MIDITrack* pMIDITrack = NULL;
+ forEachTrack (pSekaijuDoc->m_pMIDIData, pMIDITrack) {
+ long lInputOn = MIDITrack_GetInputOn (pMIDITrack);
+ long lInputPort = MIDITrack_GetInputPort (pMIDITrack);
+ long lInputChannel = MIDITrack_GetInputChannel (pMIDITrack);
+ long lOutputOn = MIDITrack_GetOutputOn (pMIDITrack);
+ long lOutputPort = MIDITrack_GetOutputPort (pMIDITrack);
+ long lOutputChannel = MIDITrack_GetOutputChannel (pMIDITrack);
+ if (lInputOn && lInputPort == i && lInputChannel == (byMsg[0] & 0x0F)) {
+ // 出力チャンネルの変換
+ BYTE byMsg2[sizeof(byMsg)];
+ memcpy (byMsg2, byMsg, sizeof (byMsg));
+ if (0 <= lOutputChannel && lOutputChannel < 16) {
+ byMsg2[0] &= 0xF0;
+ byMsg2[0] |= (BYTE)lOutputChannel;
+ }
+ // このMIDIメッセージをMIDIデータに記録
+ if (m_bRecording) {
+ // 何でこの以下の「m_lNewTime - 1」?
+ // それは新しいエベントがループバックしないようにです。
+ MIDIEvent* pMIDIEvent = MIDIEvent_Create
+ (pSekaijuDoc->m_lNewTime - 1, (byMsg[0] & 0xF0), byMsg2, lLen);
+ if (pMIDIEvent) {
+ //pMIDIEvent->m_lUserFlag |= MIDIEVENT_REALTIMEGENERATE;
+ MIDITrack_InsertEvent (pMIDITrack, pMIDIEvent);
+ // ノートオフの場合のノートオンとの結合処理
+ if (MIDIEvent_IsNoteOff (pMIDIEvent)) {
+ long lTempRecordedEventCount = m_theTempRecordedEventArray.GetSize ();
+ long j;
+ for (j = lTempRecordedEventCount - 1; j >= 0; j--) {
+ MIDIEvent* pTempEvent =
+ (MIDIEvent*)(m_theTempRecordedEventArray.GetAt (j));
+ if (MIDIEvent_IsNoteOn (pTempEvent) &&
+ pTempEvent->m_pNextCombinedEvent == NULL) {
+ if (MIDIEvent_GetChannel (pTempEvent) ==
+ MIDIEvent_GetChannel (pMIDIEvent)) {
+ if (MIDIEvent_GetKey (pTempEvent) ==
+ MIDIEvent_GetKey (pMIDIEvent)) {
+ pTempEvent->m_pNextCombinedEvent = pMIDIEvent;
+ pMIDIEvent->m_pPrevCombinedEvent = pTempEvent;
+ }
+ }
+ }
+ }
+ //MIDIEvent_Combine (pMIDIEvent);
+ }
+ m_theTempRecordedEventArray.Add (pMIDIEvent);
+ }
+ }
+ }
+ }
+ }
+ // システムエクスクルーシブメッセージの場合
+ else if (byMsg[0] == 0xF0 || byMsg[0] == 0xF7) {
+ // シンクロスタート処理
+ if (m_bRecording && m_lCurSpeedIndex == 0) {
+ m_lCurSpeedIndex = m_lOldSpeedIndex;
+ MIDIClock_Stop (pMIDIClock);
+ pSekaijuDoc->ApplyAppCurSpeedIndex ();
+ MIDIClock_Start (pMIDIClock);
+ }
+ // リアルタイム入力処理
+ MIDITrack* pMIDITrack = NULL;
+ forEachTrack (pSekaijuDoc->m_pMIDIData, pMIDITrack) {
+ long lInputOn = MIDITrack_GetInputOn (pMIDITrack);
+ long lInputPort = MIDITrack_GetInputPort (pMIDITrack);
+ long lInputChannel = MIDITrack_GetInputChannel (pMIDITrack);
+ long lOutputOn = MIDITrack_GetOutputOn (pMIDITrack);
+ long lOutputPort = MIDITrack_GetOutputPort (pMIDITrack);
+ long lOutputChannel = MIDITrack_GetOutputChannel (pMIDITrack);
+ if (lInputOn && lInputPort == i && lInputChannel == -1) {
+ // このMIDIメッセージをMIDIデータに記録
+ if (m_bRecording) {
+ // 以上の「m_lNewTime - 1」コメント見て
+ MIDITrack_InsertSysExEvent
+ (pMIDITrack, pSekaijuDoc->m_lNewTime - 1, byMsg, lLen);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
// クリティカルセクション解放
pSekaijuApp->m_theCriticalSection.Unlock ();
pSekaijuDoc->m_theCriticalSection.Unlock ();
|