Exemplo n.º 1
0
BOOL CWavProgressDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	static_cast<CProgressCtrl*>(GetDlgItem(IDC_PROGRESS_BAR))->SetRange(0, 100);
	CFamiTrackerView *pView = CFamiTrackerView::GetView();
	CSoundGen *pSoundGen = theApp.GetSoundGenerator();

	pView->Invalidate();
	pView->RedrawWindow();

	// Start rendering
	CString FileStr;
	AfxFormatString1(FileStr, IDS_WAVE_PROGRESS_FILE_FORMAT, m_sFile);
	SetDlgItemText(IDC_PROGRESS_FILE, FileStr);

	if (!pSoundGen->RenderToFile(m_sFile.GetBuffer(), m_iSongEndType, m_iSongEndParam, m_iTrack))
		EndDialog(0);

	m_dwStartTime = GetTickCount();
	SetTimer(0, 200, NULL);

	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}
Exemplo n.º 2
0
void CFrameAction::Update(CMainFrame *pMainFrm)
{
	CFamiTrackerView *pView = (CFamiTrackerView*)pMainFrm->GetActiveView();
	CFamiTrackerDoc *pDocument = pView->GetDocument();

	switch (m_iAction) {
		case ACT_CHANGE_COUNT:
			pDocument->SetFrameCount(m_iNewFrameCount);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		// TODO add change pattern 
	}
}
Exemplo n.º 3
0
void CInstrumentEditDlg::SwitchOffNote(bool ForceHalt)
{
	stChanNote NoteData { };		// // //

	CFamiTrackerView *pView = CFamiTrackerView::GetView();
	CMainFrame *pFrameWnd = static_cast<CMainFrame*>(GetParent());

	int Channel = pView->GetSelectedChannel();

	NoteData.Note			= (pView->DoRelease() && !ForceHalt) ? RELEASE : HALT;
	NoteData.Instrument		= pFrameWnd->GetSelectedInstrument();

	theApp.GetSoundGenerator()->QueueNote(Channel, NoteData, NOTE_PRIO_2);

	m_iLastKey = -1;
}
Exemplo n.º 4
0
void CCreateWaveDlg::OnBnClickedBegin()
{
	RENDER_END EndType;
	int EndParam;

	CFamiTrackerDoc *pDoc = CFamiTrackerDoc::GetDoc();

	CString FileName = pDoc->GetFileTitle();

	CWavProgressDlg ProgressDlg;
	CFileDialog SaveDialog(FALSE, _T("wav"), FileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Microsoft PCM files (*.wav)|*.wav|All files (*.*)|*.*||"));

	// Close this dialog
	EndDialog(0);

	// Ask for file location
	if (SaveDialog.DoModal() == IDCANCEL)
		return;
	
	// Save
	if (IsDlgButtonChecked(IDC_RADIO_LOOP)) {
		EndType = SONG_LOOP_LIMIT;
		EndParam = GetFrameLoopCount();
	}
	else if (IsDlgButtonChecked(IDC_RADIO_TIME)) {
		EndType = SONG_TIME_LIMIT;
		EndParam = GetTimeLimit();
	}

	CFamiTrackerView *pView = CFamiTrackerView::GetView();

	pView->UnmuteAllChannels();

	// Mute selected channels
	for (int i = 0; i < m_ctlChannelList.GetCount(); ++i) {
		if (m_ctlChannelList.GetCheck(i) == 0)
			pView->ToggleChannel(i);
	}

//	m_sFileName = SaveDialog.GetPathName();
	ProgressDlg.SetFile(SaveDialog.GetPathName().GetString());
	ProgressDlg.SetOptions(EndType, EndParam);
	ProgressDlg.DoModal();

	// Unmute all channels
	pView->UnmuteAllChannels();
}
Exemplo n.º 5
0
void CInstrumentEditDlg::SwitchOnNote(int x, int y)
{
	CFamiTrackerView *pView = CFamiTrackerView::GetView();
	CFamiTrackerDoc *pDoc = static_cast<CFamiTrackerDoc*>(static_cast<CFrameWnd*>(GetParent())->GetActiveDocument());
	CMainFrame *pFrameWnd = static_cast<CMainFrame*>(GetParent());
	int Channel = pView->GetSelectedChannel();		// // //
	int Chip = pDoc->GetExpansionChip();

	stChanNote NoteData { };

	// // // Send to respective channels whenever cursor is outside instrument chip
	if (m_iSelectedInstType == INST_2A03) {
		if (m_pPanels[0]->IsWindowVisible() && Channel > CHANID_NOISE)
			pView->SelectChannel(pDoc->GetChannelIndex(CHANID_SQUARE1));
		if (m_pPanels[1]->IsWindowVisible())
			pView->SelectChannel(pDoc->GetChannelIndex(CHANID_DPCM));
	}
	else {
		chan_id_t First = CHANNELS;
		switch (m_iSelectedInstType) {
		case INST_VRC6: First = CHANID_VRC6_PULSE1; break;
		case INST_N163: First = CHANID_N163_CH1; break;
		case INST_FDS:  First = CHANID_FDS; break;
		case INST_VRC7: First = CHANID_VRC7_CH1; break;
		case INST_S5B:  First = CHANID_S5B_CH1; break;
		}
		int Index = pDoc->GetChannelIndex(First);
		if (Index != -1 && pDoc->GetChipType(Index) != pDoc->GetChipType(Channel))
			pView->SelectChannel(Index);
	}
	Channel = pView->GetSelectedChannel();		// // //

	if (m_KeyboardRect.PtInRect({x, y})) {
		int KeyPos = (x - m_KeyboardRect.left) % 70;		// // //
		int Octave = (x - m_KeyboardRect.left) / 70;
		int Note;

		if (y > m_KeyboardRect.top + 38) {
			// Only white keys
			     if (KeyPos >= 60) Note = NOTE_B;
			else if (KeyPos >= 50) Note = NOTE_A;
			else if (KeyPos >= 40) Note = NOTE_G;
			else if (KeyPos >= 30) Note = NOTE_F;
			else if (KeyPos >= 20) Note = NOTE_E;
			else if (KeyPos >= 10) Note = NOTE_D;
			else if (KeyPos >=  0) Note = NOTE_C;
		}
		else {
			// Black and white keys
			     if (KeyPos >= 62) Note = NOTE_B;
			else if (KeyPos >= 56) Note = NOTE_As;
			else if (KeyPos >= 53) Note = NOTE_A;
			else if (KeyPos >= 46) Note = NOTE_Gs;
			else if (KeyPos >= 43) Note = NOTE_G;
			else if (KeyPos >= 37) Note = NOTE_Fs;
			else if (KeyPos >= 30) Note = NOTE_F;
			else if (KeyPos >= 23) Note = NOTE_E;
			else if (KeyPos >= 16) Note = NOTE_Ds;
			else if (KeyPos >= 13) Note = NOTE_D;
			else if (KeyPos >=  7) Note = NOTE_Cs;
			else if (KeyPos >=  0) Note = NOTE_C;
		}

		int NewNote = MIDI_NOTE(Octave, Note);		// // //
		if (NewNote != m_iLastKey) {
			NoteData.Note			= Note;
			NoteData.Octave			= Octave;
			NoteData.Vol			= MAX_VOLUME - 1;
			NoteData.Instrument		= pFrameWnd->GetSelectedInstrument();
			memset(NoteData.EffNumber, 0, 4);
			memset(NoteData.EffParam, 0, 4);

			theApp.GetSoundGenerator()->QueueNote(Channel, NoteData, NOTE_PRIO_2);
			theApp.GetSoundGenerator()->ForceReloadInstrument(Channel);		// // //
			m_iLastKey = NewNote;
		}
	}
	else {
		NoteData.Note			= pView->DoRelease() ? RELEASE : HALT;//HALT;
		NoteData.Vol			= MAX_VOLUME;
		NoteData.Instrument		= pFrameWnd->GetSelectedInstrument();;
		memset(NoteData.EffNumber, 0, 4);
		memset(NoteData.EffParam, 0, 4);

		theApp.GetSoundGenerator()->QueueNote(Channel, NoteData, NOTE_PRIO_2);

		m_iLastKey = -1;
	}
}
Exemplo n.º 6
0
void MainWindow::onIdleSlot()
{
   CFamiTrackerApp* pApp = (CFamiTrackerApp*)AfxGetApp();   
   CMainFrame* pMainFrame = (CMainFrame*)pApp->m_pMainWnd;
   CFamiTrackerDoc* pDoc = (CFamiTrackerDoc*)pMainFrame->GetActiveDocument();
   CFamiTrackerView* pView = (CFamiTrackerView*)pMainFrame->GetActiveView();
   static int lastFrame = -1;
   
   ui->sampleWindow->update();

   if ( m_bCheck )
   {
      // Move to next song if playing and the current song has reached a stop.
      if ( m_bCheck && m_bPlaying && !m_bChangeSong )
      {
         // Check if time is at time limit and if so, advance to next song.
         int timeLimit = m_pWndMFC->GetTimeLimit();
         CString playTime;
         int totalPlayTime;
         
         pMainFrame->GetDescendantWindow(AFX_IDW_STATUS_BAR)->GetDlgItemText(ID_INDICATOR_TIME,playTime);
         totalPlayTime = m_pWndMFC->ConvertTime(playTime);
         
         if ( lastFrame != pView->GetPlayFrame() )
         {
            lastFrame = pView->GetPlayFrame();
            m_iFramesPlayed++;
         }
         
         if ( m_bTimeLimited &&
              (timeLimit == totalPlayTime) )
         {
            // Force stop...
            m_bPlaying = false;
            pApp->OnCmdMsg(ID_TRACKER_TOGGLE_PLAY,0,0,0);
            m_bChangeSong = true;
            
            // Create a bit of a delay between songs.
            m_pTimer->start(500);
         }
         else if ( m_bLoopLimited &&
                   m_iFramesPlayed > pDoc->ScanActualLength(pDoc->GetSelectedTrack(),m_pWndMFC->GetFrameLoopCount()) )
         {   
            // Force stop...
            m_bPlaying = false;
            pApp->OnCmdMsg(ID_TRACKER_TOGGLE_PLAY,0,0,0);
            m_bChangeSong = true;
            
            // Create a bit of a delay between songs.
            m_pTimer->start(500);
         }
         if ( !pApp->GetSoundGenerator()->IsPlaying() )
         {
            m_bPlaying = false;
            m_bChangeSong = true;
            
            // Create a bit of a delay between songs.
            m_pTimer->start(500);
         }
      }
      // Wait until player starts playing before turning the above logic back on.
      else if ( m_bChangeSong )
      {
         on_playStop_clicked();
         if ( !ui->repeat->isChecked() )
         {
            on_next_clicked();
         }
         m_bChangeSong = false;
         ui->position->setValue((pView->GetPatternView()->GetPlayFrame()*pDoc->GetPatternLength())+pView->GetPatternView()->GetPlayRow());
         startSettleTimer();
         m_pTimer->start(0);
      }
   }
   if ( m_bDraggingPosition )
   {
      // FF/RW
      m_bCheck = false;
      pView->PlayerCommand(CMD_JUMP_TO,(ui->position->value()/pDoc->GetPatternLength())-1);
      pView->GetPatternView()->JumpToRow(ui->position->value()%pDoc->GetPatternLength());
   }
   else
   {
      m_bCheck = true;
      ui->frames->setText(QString::number(m_iFramesPlayed)+"/"+QString::number(pDoc->ScanActualLength(pDoc->GetSelectedTrack(),m_pWndMFC->GetFrameLoopCount())));
      ui->position->setValue((pView->GetPatternView()->GetPlayFrame()*pDoc->GetPatternLength())+pView->GetPatternView()->GetPlayRow());
   }
}
Exemplo n.º 7
0
void CInstrumentEditDlg::SwitchOnNote(int x, int y)
{
    CFamiTrackerView *pView = CFamiTrackerView::GetView();
    CMainFrame *pFrameWnd = static_cast<CMainFrame*>(GetParent());

    stChanNote NoteData;

    // TODO: remove hardcoded numbers

    // Send to DPCM channel if DPCM view is activated
    if (m_iSelectedInstType == INST_2A03 && m_pPanels[1]->IsWindowVisible())
        pView->SelectChannel(4);

    // Select FDS channel
    if (m_iSelectedInstType == INST_FDS)
        pView->SelectChannel(5);

    int Channel = pView->GetSelectedChannel();

    if (y > KEYBOARD_TOP && y < (KEYBOARD_TOP + 58) && x > KEYBOARD_LEFT && x < (KEYBOARD_LEFT + 560)) {

        int Octave = (x - KEYBOARD_LEFT) / 70;
        int Note;

        if (y > KEYBOARD_TOP + 38) {

            // Only white keys
            int KeyPos = (x - KEYBOARD_LEFT) % 70;

            if (KeyPos >= 0 && KeyPos < 10)				// C
                Note = 0;
            else if (KeyPos >= 10 && KeyPos < 20)		// D
                Note = 2;
            else if (KeyPos >= 20 && KeyPos < 30)		// E
                Note = 4;
            else if (KeyPos >= 30 && KeyPos < 40)		// F
                Note = 5;
            else if (KeyPos >= 40 && KeyPos < 50)		// G
                Note = 7;
            else if (KeyPos >= 50 && KeyPos < 60)		// A
                Note = 9;
            else if (KeyPos >= 60 && KeyPos < 70)		// B
                Note = 11;
        }
        else {
            // Black and white keys
            int KeyPos = (x - KEYBOARD_LEFT) % 70;

            if (KeyPos >= 0 && KeyPos < 7)			// C
                Note = 0;
            else if (KeyPos >= 7 && KeyPos < 13) 	// C#
                Note = 1;
            else if (KeyPos >= 13 && KeyPos < 16) 	// D
                Note = 2;
            else if (KeyPos >= 16 && KeyPos < 23) 	// D#
                Note = 3;
            else if (KeyPos >= 23 && KeyPos < 30) 	// E
                Note = 4;
            else if (KeyPos >= 30 && KeyPos < 37) 	// F
                Note = 5;
            else if (KeyPos >= 37 && KeyPos < 43) 	// F#
                Note = 6;
            else if (KeyPos >= 43 && KeyPos < 46) 	// G
                Note = 7;
            else if (KeyPos >= 46 && KeyPos < 53) 	// G#
                Note = 8;
            else if (KeyPos >= 53 && KeyPos < 56) 	// A
                Note = 9;
            else if (KeyPos >= 56 && KeyPos < 62) 	// A#
                Note = 10;
            else if (KeyPos >= 62 && KeyPos < 70) 	// B
                Note = 11;
        }

        if (Note + (Octave * 12) != m_iLastKey) {
            NoteData.Note			= Note + 1;
            NoteData.Octave			= Octave;
            NoteData.Vol			= 0x0F;
            NoteData.Instrument		= pFrameWnd->GetSelectedInstrument();
            memset(NoteData.EffNumber, 0, 4);
            memset(NoteData.EffParam, 0, 4);

            theApp.GetSoundGenerator()->QueueNote(Channel, NoteData, NOTE_PRIO_2);
        }

        m_iLastKey = Note + (Octave * 12);
    }
    else {
        NoteData.Note			= pView->DoRelease() ? RELEASE : HALT;//HALT;
        NoteData.Octave			= 0;
        NoteData.Vol			= 0x10;
        NoteData.Instrument		= pFrameWnd->GetSelectedInstrument();;
        memset(NoteData.EffNumber, 0, 4);
        memset(NoteData.EffParam, 0, 4);

        theApp.GetSoundGenerator()->QueueNote(Channel, NoteData, NOTE_PRIO_2);

        m_iLastKey = -1;
    }
}
Exemplo n.º 8
0
bool CFrameAction::SaveState(CMainFrame *pMainFrm)
{
	// Perform action

	CFrameEditor *pFrameEditor = pMainFrm->GetFrameEditor();
	CFamiTrackerView *pView = (CFamiTrackerView*)pMainFrm->GetActiveView();
	CFamiTrackerDoc *pDocument = pView->GetDocument();

	m_iUndoFramePos = pView->GetSelectedFrame();
	m_iUndoChannelPos = pView->GetSelectedChannel();

	switch (m_iAction) {
		case ACT_ADD:
			if (!pDocument->InsertFrame(m_iUndoFramePos + 1))
				return false;
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_REMOVE:
			SaveFrame(pDocument);
			if (!pDocument->RemoveFrame(m_iUndoFramePos))
				return false;
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_DUPLICATE:
			if (!pDocument->DuplicateFrame(m_iUndoFramePos))
				return false;
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_DUPLICATE_PATTERNS:
			if (!pDocument->DuplicatePatterns(m_iUndoFramePos + 1))
				return false;
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_CHANGE_COUNT:
			m_iUndoFrameCount = pDocument->GetFrameCount();
			pDocument->SetFrameCount(m_iNewFrameCount);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_SET_PATTERN:
			m_iOldPattern = pDocument->GetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos);
			pDocument->SetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos, m_iNewPattern);
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
		case ACT_SET_PATTERN_ALL:
			{
				int Channels = pDocument->GetAvailableChannels();
				for (int i = 0; i < Channels; ++i) {
					m_iPatterns[i] = pDocument->GetPatternAtFrame(m_iUndoFramePos, i);
					pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iNewPattern);
				}
				pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			}
			break;
		case ACT_CHANGE_PATTERN:
			{
				m_iOldPattern = pDocument->GetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos);
				int NewPattern = m_iOldPattern + m_iPatternDelta;
				if (NewPattern < 0)
					NewPattern = 0;
				if (NewPattern >= MAX_FRAMES)
					NewPattern = MAX_FRAMES - 1;
				if (NewPattern == m_iOldPattern)
					return false;
				pDocument->SetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos, NewPattern);
				pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			}
			break;
		case ACT_CHANGE_PATTERN_ALL:
			{
				int Channels = pDocument->GetAvailableChannels();
				for (int i = 0; i < Channels; ++i) {
					m_iPatterns[i] = pDocument->GetPatternAtFrame(m_iUndoFramePos, i);
					if (m_iPatterns[i] + m_iPatternDelta < 0 || m_iPatterns[i] + m_iPatternDelta >= MAX_FRAMES)
						return false;
				}
				for (int i = 0; i < Channels; ++i)
					pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iPatterns[i] + m_iPatternDelta);
				pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			}
			break;
		case ACT_MOVE_DOWN:
			if (!pDocument->MoveFrameDown(m_iUndoFramePos))
				return false;
			pView->SelectFrame(m_iUndoFramePos + 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_MOVE_UP:
			if (!pDocument->MoveFrameUp(m_iUndoFramePos))
				return false;
			pView->SelectFrame(m_iUndoFramePos - 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_PASTE:
			SaveFrame(pDocument);
			{
				int Channels = pDocument->GetAvailableChannels();
				for (int i = 0; i < Channels; ++i)
					pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iPasteData[i]);
			}
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
	}

	return true;
}
Exemplo n.º 9
0
void CFrameAction::Redo(CMainFrame *pMainFrm)
{
	// Redo action

	CFamiTrackerView *pView = (CFamiTrackerView*)pMainFrm->GetActiveView();
	CFamiTrackerDoc *pDocument = pView->GetDocument();

	switch (m_iAction) {
		case ACT_ADD:
			pDocument->InsertFrame(m_iUndoFramePos + 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_REMOVE:
			pDocument->RemoveFrame(m_iUndoFramePos);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_DUPLICATE:
			pDocument->DuplicateFrame(m_iUndoFramePos);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_DUPLICATE_PATTERNS:
			pDocument->DuplicatePatterns(m_iUndoFramePos + 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_CHANGE_COUNT:
			pDocument->SetFrameCount(m_iNewFrameCount);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_SET_PATTERN:
			pDocument->SetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos, m_iNewPattern);
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			pMainFrm->UpdateControls();
			break;
		case ACT_SET_PATTERN_ALL:
			{
				int Channels = pDocument->GetAvailableChannels();
				for (int i = 0; i < Channels; ++i) {
					pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iNewPattern);
				}
				pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			}
			break;
		case ACT_CHANGE_PATTERN:
			pDocument->SetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos, m_iOldPattern + m_iPatternDelta);
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
		case ACT_CHANGE_PATTERN_ALL:
			{
				int Channels = pDocument->GetAvailableChannels();
				for (int i = 0; i < Channels; ++i) {
					pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iPatterns[i] + m_iPatternDelta);
				}
				pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			}
			break;
		case ACT_MOVE_DOWN:
			pDocument->MoveFrameDown(m_iUndoFramePos);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_MOVE_UP:
			pDocument->MoveFrameUp(m_iUndoFramePos);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_PASTE:
			{
				int Channels = pDocument->GetAvailableChannels();
				for (int i = 0; i < Channels; ++i)
					pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iPasteData[i]);
			}
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
	}

	pView->SelectFrame(m_iRedoFramePos);
	pView->SelectChannel(m_iRedoChannelPos);
}
Exemplo n.º 10
0
void CFrameAction::Undo(CMainFrame *pMainFrm)
{
	// Undo action

	CFrameEditor *pFrameEditor = pMainFrm->GetFrameEditor();
	CFamiTrackerView *pView = (CFamiTrackerView*)pMainFrm->GetActiveView();
	CFamiTrackerDoc *pDocument = pView->GetDocument();

	m_iRedoFramePos = pView->GetSelectedFrame();
	m_iRedoChannelPos = pView->GetSelectedChannel();

	pView->SelectFrame(m_iUndoFramePos);
	pView->SelectChannel(m_iUndoChannelPos);

	switch (m_iAction) {
		case ACT_ADD:
			pDocument->RemoveFrame(m_iUndoFramePos + 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_REMOVE:
			pDocument->InsertFrame(m_iUndoFramePos);
			RestoreFrame(pDocument);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_DUPLICATE:
			pDocument->RemoveFrame(m_iUndoFramePos);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_DUPLICATE_PATTERNS:
			for (unsigned int i = 0; i < pDocument->GetAvailableChannels(); ++i) {
				pDocument->ClearPattern(m_iUndoFramePos + 1, i);
			}
			pDocument->RemoveFrame(m_iUndoFramePos + 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_CHANGE_COUNT:
			pDocument->SetFrameCount(m_iUndoFrameCount);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_SET_PATTERN:
			pDocument->SetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos, m_iOldPattern);
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			pMainFrm->UpdateControls();
			break;
		case ACT_SET_PATTERN_ALL:
			for (unsigned int i = 0; i < pDocument->GetAvailableChannels(); ++i) {
				pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iPatterns[i]);
			}
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
		case ACT_CHANGE_PATTERN:
			pDocument->SetPatternAtFrame(m_iUndoFramePos, m_iUndoChannelPos, m_iOldPattern);
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
		case ACT_CHANGE_PATTERN_ALL:
			for (unsigned int i = 0; i < pDocument->GetAvailableChannels(); ++i) {
				pDocument->SetPatternAtFrame(m_iUndoFramePos, i, m_iPatterns[i]);
			}
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
		case ACT_MOVE_DOWN:
			pDocument->MoveFrameUp(m_iUndoFramePos + 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_MOVE_UP:
			pDocument->MoveFrameDown(m_iUndoFramePos - 1);
			pDocument->UpdateAllViews(NULL, CHANGED_FRAMES);
			break;
		case ACT_PASTE:
			RestoreFrame(pDocument);
			pDocument->UpdateAllViews(NULL, CHANGED_PATTERN);
			break;
	}

	pView->SelectFrame(m_iUndoFramePos);
	pView->SelectChannel(m_iUndoChannelPos);
}