Pattern XP mod

Post Reply
User avatar
UNZ
Posts: 809
Joined: Mon Nov 21, 2011 9:42 pm
Contact:

Re: Pattern XP mod

Post by UNZ »

very nice additions!
minor annoyance: when "use toolbar" is off, clicking a button (chord for example) switches the focus away from the pattern. So you have to click on the pattern again and only then can you enter notes and move around again etc.
This doesn't happen with "use toolbar" on.
rav
Posts: 140
Joined: Fri Sep 14, 2012 3:35 pm

Re: Pattern XP mod

Post by rav »

Great update!
I wanted to suggest simple solution for new curves, but you were faster ;d
This is the idea:
Image
Anyway, possibility to invert/mirror selected notes or values would be pretty nice addition for patterns editing.

In built-in pattern editor is very cool feature. Timeline doesn't disappear, if you stop sequence. This is very helpful during editing long patterns. Is it possible, to reintroduce this functionality? What do you think?

If you select just one value, humanize option is inactive in toolbar mode, but you can use it via shortcut.
I just found that, new interpolation works very well on values from min to max, but not vice versa.
User avatar
tinga
Posts: 526
Joined: Tue Nov 22, 2011 5:25 pm

Re: Pattern XP mod

Post by tinga »

Thanks for this new update, what is the limit for the list? (just because i don't want to crash buzz again if I have the stupid idea to merge all the lists i' m doing).

3 new lists
Intervals, very short, but useful for two voices harmonization.

3 notes chords in 7 different positions for the 3 states:fundamental, first and second inversions
just major minor and dim, maybe some adds, but maybe not, the most useful list, for clean sound.

4 notes chords in different positions, clear sound, larger intervals.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

tinga wrote:Thanks for this new update, what is the limit for the list? (just because i don't want to crash buzz again if I have the stupid idea to merge all the lists i' m doing).
The limit is 200, but it's dirty work :-)
I'll rewrite that one day with no limitation (I don't have time ...)
tinga wrote:3 new lists
Installation files updated.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

UNZ wrote:very nice additions!
minor annoyance: when "use toolbar" is off, clicking a button (chord for example) switches the focus away from the pattern. So you have to click on the pattern again and only then can you enter notes and move around again etc.
This doesn't happen with "use toolbar" on.
This is the way "Buttons" act. They have focus when you click on it.
The "ToolButtons" don't have focus, so the pattern don't loose it when you click.
I only use the toolbar version. I kept the button version because someone asked for it, but I don't plan to improve it.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

rav wrote: Anyway, possibility to invert/mirror selected notes or values would be pretty nice addition for patterns editing.
I keep the idea.
rav wrote: In built-in pattern editor is very cool feature. Timeline doesn't disappear, if you stop sequence. This is very helpful during editing long patterns. Is it possible, to reintroduce this functionality? What do you think?
I'll have a look at that.
rav wrote: If you select just one value, humanize option is inactive in toolbar mode, but you can use it via shortcut.
I just found that, new interpolation works very well on values from min to max, but not vice versa.
I'll have a look at that.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

rav wrote: I just found that, new interpolation works very well on values from min to max, but not vice versa.
New version available to correct this bug.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Pattern XP mod - pitch bend problem

Post by chahur »

I had a look at the "record pitch bend commands from the midi keyboard" problem.
To try to find what happens, I restarted from the sources of the original patternXP.
Then, when I compile this sources, I already have the same problem.
So, it seems that it doesn't come from what I have added : the problem is there from the start.
But obviously, it works fine in the dll Oskari provides in Buzz install.

I know that I don't use the same version of the MFC, maybe the problem is here ...
I know also that Oskari don't use Visual C++ 2010 Express.

So if someone have a suggestion.
rav
Posts: 140
Joined: Fri Sep 14, 2012 3:35 pm

Re: Pattern XP mod

Post by rav »

Maybe it is related to this problem with compiling peer adsr machine. Oskari mentioned about pxp in this thread too:
viewtopic.php?f=3&t=1383
oskari
Site Admin
Posts: 296
Joined: Mon Nov 21, 2011 2:04 pm

Re: Pattern XP mod

Post by oskari »

It looks like the code on jeskola.net was old so it didn't have the latest features like pitch bend record. It's updated now and I think you might be able to automatically merge it with your new code. There are some other important changes like UpdateWaveReferences (template paste). Here's the whole diff:

Code: Select all

diff old/ActionStack.cpp new/ActionStack.cpp
21c21
< 		int oldsize = pdata->size();
---
> 		int oldsize = (int)pdata->size();
83a84
> 	s.scrollpos = pew->pe.GetScrollPos();
101a103
> 		pew->pe.ScrollTo(ps->scrollpos);
diff old/ActionStack.h new/ActionStack.h
13a14
> 	CPoint scrollpos;
diff old/App.cpp new/App.cpp
62a63,64
> 	//afxAmbientActCtx = FALSE;
> 
diff old/EditorWnd.cpp new/EditorWnd.cpp
318,320c318
< 		MACHINE_LOCK;
< 		pPattern->EnableColumns(dlg.enabledColumns, pCB);
< 		pPattern->SetRowsPerBeat(dlg.m_RPBValue);
---
> 		pPattern->EnableColumns(dlg.enabledColumns, pCB, 1, dlg.m_RPBValue);
diff old/MachinePattern.h new/MachinePattern.h
2a3
> #include <functional>
172c173
< 		modulators = shared_ptr<CModulators>(new CModulators());
---
> 		modulators = make_shared<CModulators>();
201c202
< 	enum State { note_on_pending, playing, note_off_pending, recording };
---
> 	enum State { note_on_pending, playing, note_off_pending, recording, pw_or_cc };
208a210,211
> 	int pw;
> 	int cc;
381a385,393
> 	int GetValueClamp(int row, int mini, int maxi) const
> 	{
> 		MapIntToValue::const_iterator i = events.find(row);
> 		if (i == events.end())
> 			return GetNoValue();
> 		else
> 			return min(max((*i).second, mini), maxi);
> 	}
> 
597a610
> 	MapIntToValue::const_iterator EventsBeginAt(int offset) const { return events.lower_bound(offset); }
630a644,645
> 	bool IsMidiPW() const { return paramIndex == MidiPitchWheel; }
> 	bool IsMidiCC() const { return paramIndex == MidiCC; }
633c648
< 	int GetDigitCount()
---
> 	int GetDigitCount() const
639c654
< 		case pt_byte: return 2;
---
> 		case pt_byte: return IsAscii() ? 1 : 2;
646c661
< 	int GetWidth()
---
> 	int GetWidth() const
651c666
< 			return GetDigitCount() + 1;
---
> 			return GetDigitCount() + (IsTiedToNext() ? 0 : 1);
654c669
< 	bool IsNormalValue(int value)
---
> 	bool IsNormalValue(int value) const
677a693,694
> 	int GetIndex() const { return paramIndex; }
> 
742,743c759,761
< 					if (GetParamType() == pt_note)
< 						value = EncodeNote(modulators->DiatonicTransposition(DecodeNote(value)));
---
> 					if (GetParamType() == pt_note && IsNormalValue(value))
> 						value = EncodeNote(min(max(modulators->DiatonicTransposition(DecodeNote(value)), 0), 9 * 12 + 11));
> 
770a789
> 						if (modulators) n.note = min(max(modulators->DiatonicTransposition(n.note), 0), 9 * 12 + 11);
773a793
> 						n.pw = n.cc = -1;
796a817,850
> 				else if (ip == MidiPitchWheel)
> 				{
> 					auto n = gdata.activeMidiNotes.find(MacIntPair(pMachine, paramTrack));
> 					if (n == gdata.activeMidiNotes.end())
> 					{
> 						gdata.activeMidiNotes[MacIntPair(pMachine, paramTrack)] = ActiveMidiNote();
> 						n = gdata.activeMidiNotes.find(MacIntPair(pMachine, paramTrack));
> 						(*n).second.state = ActiveMidiNote::pw_or_cc;
> 						(*n).second.cc = -1;
> 						(*n).second.delaytime = 0;
> 						(*n).second.cuttime = 0x7fffffff;
> 					}
> 
> 					(*n).second.rowInBeat = gdata.currentRowInBeat;
> 					(*n).second.RPB = gdata.currentRPB;
> 					(*n).second.pw = (*i).second;
> 				}
> 				else if (ip == MidiCC)
> 				{
> 					auto n = gdata.activeMidiNotes.find(MacIntPair(pMachine, paramTrack));
> 					if (n == gdata.activeMidiNotes.end())
> 					{
> 						gdata.activeMidiNotes[MacIntPair(pMachine, paramTrack)] = ActiveMidiNote();
> 						n = gdata.activeMidiNotes.find(MacIntPair(pMachine, paramTrack));
> 						(*n).second.state = ActiveMidiNote::pw_or_cc;
> 						(*n).second.pw = -1;
> 						(*n).second.delaytime = 0;
> 						(*n).second.cuttime = 0x7fffffff;
> 					}
> 
> 					(*n).second.rowInBeat = gdata.currentRowInBeat;
> 					(*n).second.RPB = gdata.currentRPB;
> 					(*n).second.cc = (*i).second;
> 				}
802c856
< 						if ((*n).second.state == ActiveMidiNote::note_on_pending)
---
> 						if ((*n).second.state == ActiveMidiNote::note_on_pending || (*n).second.pw >= 0 || (*n).second.cc >= 0)
823c877
< 					(*sptv)[tid] = shared_ptr<CSubPatternControl>(new CSubPatternControl((*i).second, paramTrack));
---
> 					(*sptv)[tid] = make_shared<CSubPatternControl>((*i).second, paramTrack);
887a942,971
> 	bool IsTiedToNext() const 
> 	{ 
> 		assert(pParam != NULL); 
> 		return (pParam->Flags & MPF_TIE_TO_NEXT) != 0; 
> 	}
> 
> 	bool IsAscii() const 
> 	{ 
> 		assert(pParam != NULL); 
> 		return (pParam->Flags & MPF_ASCII) != 0; 
> 	}
> 
> 	char const *GetName() const 
> 	{
> 		assert(pParam != NULL); 
> 		return pParam->Name;
> 	}
> 
> 	bool NameEqualsIgnoreCase(char const *str) const 
> 	{
> 		assert(pParam != NULL); 
> 		return ::_stricmp(pParam->Name, str) == 0;
> 	}
> 
> 	bool NameStartsWithIgnoreCase(char const *str) const 
> 	{
> 		assert(pParam != NULL); 
> 		return ::_strnicmp(pParam->Name, str, strlen(str)) == 0;
> 	}
> 
893a978
> 
922a1008,1020
> 	void UpdateWaveReferences(byte const *remap)
> 	{
> 		if (!IsWaveParameter()) return;
> 
> 		for (MapIntToValue::iterator i = events.begin(); i != events.end(); i++)
> 		{
> 			int wr = (*i).second;
> 			if (wr >= WAVE_MIN && wr <= WAVE_MAX && remap[wr] >= WAVE_MIN && remap[wr] <= WAVE_MAX)
> 				(*i).second = remap[wr];
> 		}
> 
> 	}
> 
982c1080
< 			columns.push_back(shared_ptr<CColumn>(new CColumn((*i).get(), copydata)));
---
> 			columns.push_back(make_shared<CColumn>((*i).get(), copydata));
1030c1128
< 			CColumn *pc = new CColumn();
---
> 			auto pc = make_shared<CColumn>();
1032c1130
< 			columns.push_back(shared_ptr<CColumn>(pc));
---
> 			columns.push_back(pc);
1180c1278
< 			shared_ptr<CColumn> pc = shared_ptr<CColumn>(new CColumn(columns[lastcoli+i].get(), false, true));
---
> 			shared_ptr<CColumn> pc = make_shared<CColumn>(columns[lastcoli+i].get(), false, true);
1184,1185c1282,1283
< //		int nmt = pcb->GetNumTracks(pmac);
< //		if (nmt < tc + 1)
---
> 		int nmt = pcb->GetNumTracks(pmac);
> 		if (nmt < tc + 1)
1218a1317,1325
> 	shared_ptr<CColumn> GetColumn(function<bool (shared_ptr<CColumn> const &)> match) const
> 	{
> 		for (auto i = columns.begin(); i != columns.end(); i++)
> 			if (match(*i))
> 				return (*i);
> 
> 		return shared_ptr<CColumn>();
> 	}
> 
1241c1348
< 		return shared_ptr<CColumn>(new CColumn(pcb, mpp, track));
---
> 		return make_shared<CColumn>(pcb, mpp, track);
1244c1351
< 	void EnableColumns(MacParamPairVector const &_ec, CMICallbacks *pcb, int mintracks = 1)
---
> 	void EnableColumns(MacParamPairVector const &_ec, CMICallbacks *pCB, int mintracks = 1, int rpb = -1)
1253c1360
< 			if (IsGlobalParameter(*i, pcb))
---
> 			if (IsGlobalParameter(*i, pCB))
1262c1369
< 			if (!c) c = CreateColumn(*i, 0, pcb);
---
> 			if (!c) c = CreateColumn(*i, 0, pCB);
1266d1372
< 
1271a1378
> 			maxtracks = max(maxtracks, GetTrackCount((*i).first));
1289c1396
< 						cv.push_back(shared_ptr<CColumn>(CreateColumn(MacIntPair(*(i + c)), t, pcb)));
---
> 						cv.push_back(shared_ptr<CColumn>(CreateColumn(MacIntPair(*(i + c)), t, pCB)));
1295a1403
> 		MACHINE_LOCK;
1296a1405,1408
> 
> 		if (rpb > 0)
> 			SetRowsPerBeat(rpb);
> 
1404a1517,1525
> 	void UpdateWaveReferences(byte const *remap)
> 	{
> 		for (ColumnVector::iterator i = columns.begin(); i != columns.end(); i++)
> 			(*i)->UpdateWaveReferences(remap);
> 
> 		for (ColumnVector::iterator i = deletedColumns.begin(); i != deletedColumns.end(); i++)
> 			(*i)->UpdateWaveReferences(remap);
> 	}
> 
1415a1537,1541
> 				auto pwcol = GetColumn(MacIntPair(pmac, MidiPitchWheel), t).get();
> 				if (pwcol != NULL && pwcol->HasValue(row)) continue;
> 				auto cccol = GetColumn(MacIntPair(pmac, MidiCC), t).get();
> 				if (cccol != NULL && cccol->HasValue(row)) continue;
> 
1533a1660,1732
> 	int AllocateMidiCCTrack(CMachine *pmac, int row, int delay, MapMacAndTrackToActiveMidiNote &notes, int tc)
> 	{
> 		for (int t = 0; t < tc; t++)
> 		{
> 			MapMacAndTrackToActiveMidiNote::iterator i;
> 			
> 			for (i = notes.begin(); i != notes.end(); i++)
> 				if ((*i).first.second == t) break;
> 
> 			if (i == notes.end())
> 			{
> 				auto notecol = GetColumn(MacIntPair(pmac, MidiNote), t).get();
> 				auto pwcol = GetColumn(MacIntPair(pmac, MidiPitchWheel), t).get();
> 				auto cccol = GetColumn(MacIntPair(pmac, MidiCC), t).get();
> 				auto delaycol = GetColumn(MacIntPair(pmac, MidiNoteDelay), t).get();
> 				auto cutcol = GetColumn(MacIntPair(pmac, MidiNoteCut), t).get();
> 
> 				bool gotstuff = notecol != NULL && notecol->HasValue(row);
> 				gotstuff |= pwcol != NULL && pwcol->HasValue(row);
> 				gotstuff |= cccol != NULL && cccol->HasValue(row);
> 				gotstuff |= cutcol != NULL && cutcol->HasValue(row);
> 
> 				if (!gotstuff) return t;
> 			}
> 		}
> 
> 		return tc > 0 ? 0 : -1;
> 	}
> 
> 	void RecordMidiCCs(int row, CRecQueue::Event const &e, CGlobalData &gdata)
> 	{
> 		int tc = GetTrackCount(e.pmac);
> 		if (tc < 1) return;
> 
> 		if (e.param == 255)
> 		{
> 			if (!HasMidiPWColumn()) return;
> 		}
> 		else if (e.param >= 0 && e.param <= 127)
> 		{
> 			if (!HasMidiCCColumn()) return;
> 		}
> 		else
> 		{
> 			return;
> 		}
> 
> 
> 		auto range = GetRowSubtickRange(row % gdata.currentRPB, gdata.currentRPB, gdata.subticksPerTick);
> 		int delay = min(max((gdata.currentSubtick - range.first) * 96 / (range.second - range.first), 0), 95);
> 
> 		int rectrack = AllocateMidiCCTrack(e.pmac, row, delay, gdata.recordingMidiNotes, tc);
> 		if (rectrack < 0) return;
> 
> 		if (e.param == 255)
> 		{
> 			auto pwcol = GetColumn(MacIntPair(e.pmac, MidiPitchWheel), rectrack).get();
> 			if (pwcol == NULL) return;
> 			pwcol->SetValue(row, e.value);
> 		}
> 		else
> 		{
> 			auto cccol = GetColumn(MacIntPair(e.pmac, MidiCC), rectrack).get();
> 			if (cccol == NULL) return;
> 			cccol->SetValue(row, (e.param << 8) | e.value);
> 		}
> 
> 		auto delaycol = GetColumn(MacIntPair(e.pmac, MidiNoteDelay), rectrack).get();
> 		if (delaycol != NULL && delay != 0) delaycol->SetValue(row, delay);
> 
> 
> 	}
> 
1546c1745,1751
< 			if (e.group < 0 && e.value > 0)	RecordMidiNoteOns(row, e, gdata);
---
> 			if (e.group == -1 && e.value > 0)	RecordMidiNoteOns(row, e, gdata);
> 		}
> 
> 		for (int ei = 0; ei < (int)ev.size(); ei++)
> 		{
> 			CRecQueue::Event const &e = ev[ei];
> 			if (e.group == -1 && e.value == 0) RecordMidiNoteOffs(row, e, gdata);
1552c1757
< 			if (e.group < 0 && e.value == 0) RecordMidiNoteOffs(row, e, gdata);
---
> 			if (e.group == -2) RecordMidiCCs(row, e, gdata);
1588a1794,1816
> 	bool HasMidiPWColumn() const
> 	{
> 		for (auto i = columns.begin(); i != columns.end(); i++)
> 			if ((*i)->IsMidiPW())
> 				return true;
> 
> 		return false;
> 	}
> 
> 	bool HasMidiCCColumn() const
> 	{
> 		for (auto i = columns.begin(); i != columns.end(); i++)
> 			if ((*i)->IsMidiCC())
> 				return true;
> 
> 		return false;
> 	}
> 
> 	int ScaleToMidiTime(int row, int delay, int range) const
> 	{
> 		return (range * row + delay) * 960 * BUZZ_TICKS_PER_BEAT / (range * rowsPerBeat);
> 	}
> 
1591d1818
< 		if (!HasMidiNoteColumn()) return false;
1604a1832,1840
> 			if (notecol[i] == NULL)
> 			{
> 				notecol[i] = GetColumn([=] (shared_ptr<CColumn> const &c)
> 				{ 
> 					return c->GetParamType() == pt_note && c->IsTrackParam() && c->GetTrack() == i && c->NameEqualsIgnoreCase("note"); 
> 				}).get();
> 				if (notecol[i] == NULL) return false;
> 			}
> 
1605a1842,1849
> 			if (velcol[i] == NULL)
> 			{
> 				velcol[i] = GetColumn([=] (shared_ptr<CColumn> const &c)
> 				{ 
> 					return c->GetParamType() == pt_byte && c->IsTrackParam() && c->GetTrack() == i && (c->NameEqualsIgnoreCase("note velocity") || c->NameEqualsIgnoreCase("velocity")); 
> 				}).get();
> 			}
> 
1606a1851,1858
> 			if (delaycol[i] == NULL)
> 			{
> 				delaycol[i] = GetColumn([=] (shared_ptr<CColumn> const &c)
> 				{ 
> 					return c->GetParamType() == pt_byte && c->IsTrackParam() && c->GetTrack() == i && c->NameEqualsIgnoreCase("note delay"); 
> 				}).get();
> 			}
> 
1607a1860,1866
> 			if (cutcol[i] == NULL)
> 			{
> 				cutcol[i] = GetColumn([=] (shared_ptr<CColumn> const &c)
> 				{ 
> 					return c->GetParamType() == pt_byte && c->IsTrackParam() && c->GetTrack() == i && c->NameEqualsIgnoreCase("note cut"); 
> 				}).get();
> 			}
1615a1875,1877
> 				int const delayrange = (delaycol[t] != NULL) ? (delaycol[t]->GetMaxValue() + 1) : 96;
> 				int const cutrange = (cutcol[t] != NULL) ? (cutcol[t]->GetMaxValue() + 1) : 96;
> 
1619c1881
< 				int cut = 96;
---
> 				int cut = cutrange;
1622c1884
< 				if (velcol[t] != NULL && velcol[t]->HasValue(row)) velocity = velcol[t]->GetValue(row);
---
> 				if (velcol[t] != NULL && velcol[t]->HasValue(row)) velocity =  velcol[t]->GetValueClamp(row, 1, 127);
1634c1896
< 							(96 * row + delay) * 10 * BUZZ_TICKS_PER_BEAT / rowsPerBeat,
---
> 							ScaleToMidiTime(row, delay, delayrange),
1641c1903
< 						(96 * row + delay) * 10 * BUZZ_TICKS_PER_BEAT / rowsPerBeat,
---
> 						ScaleToMidiTime(row, delay, delayrange),
1646c1908
< 					if (cut < 96)
---
> 					if (cut < cutrange)
1650c1912
< 							(96 * row + cut) * 10 * BUZZ_TICKS_PER_BEAT / rowsPerBeat,
---
> 							ScaleToMidiTime(row, cut, cutrange),
1658c1920
< 						(96 * row + min(delay, cut)) * 10 * BUZZ_TICKS_PER_BEAT / rowsPerBeat,
---
> 						ScaleToMidiTime(row, min(delay, cut), delayrange),
1952c2214
< 				shared_ptr<CPlayingPattern> p = shared_ptr<CPlayingPattern>(new CPlayingPattern(gdata.patternList[spi], NULL, -1, tofs, (*i).second->modulators)); 
---
> 				auto p = make_shared<CPlayingPattern>(gdata.patternList[spi], nullptr, -1, tofs, (*i).second->modulators); 
diff old/PatEd.cpp new/PatEd.cpp
42a43
> 	ON_WM_CHAR()
217,218d217
< 	MapIntToValue::const_iterator ei = pc->EventsBegin();
< 
219a219
> 	MapIntToValue::const_iterator ei = pc->EventsBeginAt(firstrow);
222,223d221
< 	while(ei != pc->EventsEnd() && (*ei).first < firstrow) ei++;
< 
246c244
< static void FieldToText(char *txt, CMPType type, bool hasval, void *fdata)
---
> static void FieldToText(char *txt, CMPType type, bool ascii, bool hasval, void *fdata)
282c280
< 			if (!hasval)
---
> 			if (ascii)
284,285c282,287
< 				txt[0] = '.';
< 				txt[1] = '.';
---
> 				if (!hasval)
> 					txt[0] = '.';
> 				else
> 					txt[0] = b;
> 
> 				txt[1] = 0;
289,290c291,301
< 				txt[0] = NibbleToHexText[b >> 4];
< 				txt[1] = NibbleToHexText[b & 15];
---
> 				if (!hasval)
> 				{
> 					txt[0] = '.';
> 					txt[1] = '.';
> 				}
> 				else
> 				{
> 					txt[0] = NibbleToHexText[b >> 4];
> 					txt[1] = NibbleToHexText[b & 15];
> 				}
> 				txt[2] = 0;
292d302
< 			txt[2] = 0;
336a347,389
> static CString FieldToLongText(CMPType type, bool hasval, int v)
> {
> 	CString s;
> 
> 	switch(type)
> 	{
> 	case pt_note:
> 		{
> 			if (!hasval)
> 			{
> 			}
> 			else if (v == NOTE_OFF)
> 			{
> 				s = "note off";
> 			}
> 			else
> 			{
> 				int octave = v >> 4;
> 				int note = (v & 15) -1;
> 
> 				s = NoteToText[note*2+0];
> 				s += NoteToText[note*2+1];
> 				s += (char)(octave + '0');
> 			}
> 		}
> 		break;
> 	default:
> 		if (v != -1)
> 		{
> 			if (v > 255)
> 				s.Format("%04X (%d)", v, v);
> 			else
> 				s.Format("%02X (%d)", v, v);
> 		}
> 
> 		break;
> 
> 
> 	}
> 
> 	return s;
> }
> 
340a394,402
> 	int bar = 4;
> 	
> 	if (ppat->numBeats % 13 == 0) bar = 13;
> 	else if (ppat->numBeats % 11 == 0) bar = 11;
> 	else if (ppat->numBeats % 9 == 0) bar = 9;
> 	else if (ppat->numBeats % 7 == 0) bar = 7;
> 	else if (ppat->numBeats % 5 == 0) bar = 5;
> 	else if (ppat->numBeats % 3 == 0) bar = 3;
> 
345c407
< 	else if ((row % (4 * ppat->rowsPerBeat)) == 0)
---
> 	else if ((row % (bar * ppat->rowsPerBeat)) == 0)
377c439
< 	FieldToText(txt, pc->GetParamType(), hasvalue, (void *)&data);
---
> 	FieldToText(txt, pc->GetParamType(), pc->IsAscii(), hasvalue, (void *)&data);
379c441
< 	int len = strlen(txt);
---
> 	int len = (int)strlen(txt);
479c541
< 		if (x < colx - pew->fontSize.cx)
---
> 		if (x < colx - (ppat->columns[col]->IsTiedToNext() ? 0 : pew->fontSize.cx))
561c623
< 	r.right = r.left + GetColumnWidth(column) - pew->fontSize.cx;
---
> 	r.right = r.left + GetColumnWidth(column); // - pew->fontSize.cx;
882a945,959
> void CPatEd::EditAscii(char val)
> {
> 	CMachinePattern *ppat = pew->pPattern;
> 	CColumn *pc = ppat->columns[cursor.column].get();
> 
> 	ppat->actions.BeginAction(pew, "Edit ASCII");
> 	{
> 		MACHINE_LOCK;
> 		pc->SetValue(cursor.row, val);
> 	}
> 
> 	InvalidateField(cursor.row, cursor.column);
> 	MoveCursorDelta(0, cursorStep);
> }
> 
1088,1095c1165,1175
< 			if (nChar >= '0' && nChar <= '9')
< 				EditByte(nChar - '0');
< 			else if (nChar == 'A') EditByte(0xA);
< 			else if (nChar == 'B') EditByte(0xB);
< 			else if (nChar == 'C') EditByte(0xC);
< 			else if (nChar == 'D') EditByte(0xD);
< 			else if (nChar == 'E') EditByte(0xE);
< 			else if (nChar == 'F') EditByte(0xF);
---
> 			if (!pc->IsAscii())
> 			{
> 				if (nChar >= '0' && nChar <= '9')
> 					EditByte(nChar - '0');
> 				else if (nChar == 'A') EditByte(0xA);
> 				else if (nChar == 'B') EditByte(0xB);
> 				else if (nChar == 'C') EditByte(0xC);
> 				else if (nChar == 'D') EditByte(0xD);
> 				else if (nChar == 'E') EditByte(0xE);
> 				else if (nChar == 'F') EditByte(0xF);
> 			}
1121a1202,1239
> void CPatEd::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
> {
> 	CMachinePattern *ppat = pew->pPattern;
> 	if (ppat == NULL || ppat->columns.size() == 0)
> 		return;
> 
> 	CColumn *pc = ppat->columns[cursor.column].get();
> 
> 	if (pc->GetParamType() == pt_byte && pc->IsAscii())
> 	{
> 		if (nChar != '.')
> 		{
> 			char ch = (char)nChar;
> 			bool valid = pCB->IsValidAsciiChar(pc->GetMachine(), pc->GetIndex(), ch);
> 			
> 			if (!valid && nChar >= 'a' && nChar <= 'z')
> 			{
> 				ch += 'A' - 'a';
> 				valid = pCB->IsValidAsciiChar(pc->GetMachine(), pc->GetIndex(), ch);
> 			}
> 			else if (!valid && nChar >= 'A' && nChar <= 'Z')
> 			{
> 				ch += 'a' - 'A';
> 				valid = pCB->IsValidAsciiChar(pc->GetMachine(), pc->GetIndex(), ch);
> 			}
> 
> 			if (ch < pc->GetMinValue() || ch > pc->GetMaxValue())
> 				valid = false;
> 
> 			if (valid)
> 				EditAscii(ch);
> 		}
> 	}
> 
> 	CWnd::OnChar(nChar, nRepCnt, nFlags);
> }
> 
> 
1279,1280d1396
< 	char txt[6];
< 	FieldToText(txt, pc->GetParamType(), pc->HasValue(cursor.row), (void *)&value);
1284c1400
< 		char const *desc = pc->DescribeValue(value, pCB);
---
> 		s = FieldToLongText(pc->GetParamType(), pc->HasValue(cursor.row), value);
1286c1402,1403
< 		s = txt;
---
> 		char const *desc = pc->DescribeValue(value, pCB);
> 		
1288c1405
< 			s += (CString)" (" + desc + ")";
---
> 			s += (CString)" " + desc;
1372a1490,1491
> 	CColumn *pc = ppat->columns[cursor.column].get();
> 
1379a1499,1500
> 	CCursorPos oldpos = cursor;
> 
1388a1510,1540
> 	if (cursor == oldpos)
> 	{
> 		switch(selMode)
> 		{
> 		case column: selMode = track; break;
> 		case track: if (pc->IsTrackParam()) selMode = group; else selMode = all; break;
> 		case group: selMode = all; break;
> 		case all: selMode = column; break;
> 		}
> 
> 		switch(selMode)
> 		{
> 		case column:
> 			selStart.x = selEnd.x = cursor.column;
> 			break;
> 		case track:
> 			selStart.x = ppat->GetFirstColumnOfTrackByColumn(cursor.column);
> 			selEnd.x = selStart.x + ppat->GetGroupColumnCount(cursor.column) - 1;
> 			break;
> 		case group:
> 			selStart.x = ppat->GetFirstColumnOfTrackByColumn(cursor.column) - pc->GetTrack() * ppat->GetGroupColumnCount(cursor.column);
> 			selEnd.x = selStart.x + ppat->GetGroupColumnCount(cursor.column) * ppat->GetTrackCount(pc->GetMachine()) - 1;
> 			break;
> 		case all:
> 			selStart.x = 0;
> 			selEnd.x = (int)ppat->columns.size() - 1;
> 			break;
> 		}
> 
> 	}
> 
1763,1764c1915,1916
< 	int vel = lParam;
< 	int n = wParam - pew->pCB->GetBaseOctave() * 12;
---
> 	int vel = (int)lParam;
> 	int n = (int)wParam - pew->pCB->GetBaseOctave() * 12;
diff old/PatEd.h new/PatEd.h
69a70
> 	void EditAscii(char n);
131a133
> 	afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
diff old/PatternXP.cpp new/PatternXP.cpp
92a93
> 	virtual void UpdateWaveReferences(CPattern *p, byte const *remap);
448a450,453
> void miex::UpdateWaveReferences(CPattern *p, byte const *remap)
> {
> 	pmi->patterns[p]->UpdateWaveReferences(remap);
> }
508a514,519
> 		if (pmi->pCB->GetStateFlags() & SF_RECORDING)
> 		{
> 			pmi->recQueue.Push(CRecQueue::Event(pmac, -2, channel, ctrl, value));
> 			pmi->patEd->pe.InvalidateInTimer();
> 		}
> 
696a708,719
> 		if ((*i).second.pw >= 0 && cst >= dtime)
> 		{
> 			pCB->SendMidiControlChange((*i).first.first, 255, 0, (*i).second.pw);
> 			(*i).second.pw = -1;
> 		}
> 
> 		if ((*i).second.cc >= 0 && cst >= dtime)
> 		{
> 			pCB->SendMidiControlChange((*i).first.first, ((*i).second.cc >> 8) & 0x7f, 0, (*i).second.cc & 0x7f);
> 			(*i).second.cc = -1;
> 		}
> 		
701a725,729
> 		else if ((*i).second.state == ActiveMidiNote::pw_or_cc && (*i).second.pw < 0 && (*i).second.cc < 0)
> 		{
> 			globalData.activeMidiNotes.erase(i);
> 		}
> 
diff old/ScrollWnd.cpp new/ScrollWnd.cpp
44,45c44,48
< 	canvasSize = s;
< 	ScrollTo(CPoint(0, 0));
---
> 	if (canvasSize != s)
> 	{
> 		canvasSize = s;
> 		ScrollTo(GetScrollPos());
> 	}
diff old/ScrollWnd.h new/ScrollWnd.h
50a51
> 	void ScrollTo(CPoint pos);
58d58
< 	void ScrollTo(CPoint pos);
diff old/stdafx.h new/stdafx.h
14a15,24
> #define NOMINMAX
> 
> #ifndef max
> #define max(a,b)            (((a) > (b)) ? (a) : (b))
> #endif
> 
> #ifndef min
> #define min(a,b)            (((a) < (b)) ? (a) : (b))
> #endif
> 
53a64,65
> 
> //#define MI_DEBUG_LOCKS
68a81
> 
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

oskari wrote:It looks like the code on jeskola.net was old so it didn't have the latest features like pitch bend record. It's updated now and I think you might be able to automatically merge it with your new code. There are some other important changes like UpdateWaveReferences (template paste).
Thanks.
That's what I was thinking.
I use Beyond Compare to merge the code, that's not a problem.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

New version
- Upgraded to last official PatternXP sources (add pitch bend record ...)
- New chords files added. Thanks to Tinga as usual :-)
- Import pattern can be undone.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

Added :
- Reverse selection (shortcut Ctrl+D)
- Humanize Toolbutton enabled when selection is empty
mridlen
Posts: 432
Joined: Sun Apr 15, 2012 8:55 am
Contact:

Re: Pattern XP mod

Post by mridlen »

YAY!!!! :dance: :dance: :dance:

Thanks guys! :)
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

Added
- Mirror selection (ctrl+shift+D).
flat
Posts: 34
Joined: Thu Nov 24, 2011 4:55 pm

Re: Pattern XP mod

Post by flat »

Chahur, thanks for this, you're doing a great job.
In Pattern XP editor I'd like to be able to trigger the machine help display by double clicking (or by choosing it via left mouse button menu).
Main reason would be to more directly/intuitively get info of effects command parameters values while editing patterns.
User avatar
UNZ
Posts: 809
Joined: Mon Nov 21, 2011 9:42 pm
Contact:

Re: Pattern XP mod

Post by UNZ »

chahur wrote:
UNZ wrote:very nice additions!
minor annoyance: when "use toolbar" is off, clicking a button (chord for example) switches the focus away from the pattern. So you have to click on the pattern again and only then can you enter notes and move around again etc.
This doesn't happen with "use toolbar" on.
This is the way "Buttons" act. They have focus when you click on it.
The "ToolButtons" don't have focus, so the pattern don't loose it when you click.
I only use the toolbar version. I kept the button version because someone asked for it, but I don't plan to improve it.

they don't have to work like this, its configurable. look at the "columns.." button. there, even dialog comes up and when you close it focus switches back to the pattern editor. it shouldn't be a big thing to switch back focus or disable focus stealing imho. please ?

the "midi edit" checkbox has the same issue btw.
User avatar
chahur
Posts: 215
Joined: Sun Nov 27, 2011 5:19 pm

Re: Pattern XP mod

Post by chahur »

Added :
- Remove Chords limit
- Add "Parameters" dialog"
- Keep "Draw play position" persistent (parameter)
- Put focus back to editor when clicking on a button
User avatar
UNZ
Posts: 809
Joined: Mon Nov 21, 2011 9:42 pm
Contact:

Re: Pattern XP mod

Post by UNZ »

chahur wrote:Added :
- Remove Chords limit
- Add "Parameters" dialog"
- Keep "Draw play position" persistent (parameter)
- Put focus back to editor when clicking on a button
THANK YOU :)
esp81
Posts: 139
Joined: Mon Jun 17, 2013 2:44 am

Re: Pattern XP mod

Post by esp81 »

Loving the new features, thanks!! Mirror selection is changing all notes, not just the selected ones, is that intentional?
Post Reply