12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954 |
- /*
- * view_ins.cpp
- * ------------
- * Purpose: Instrument tab, lower panel.
- * Notes : (currently none)
- * Authors: Olivier Lapicque
- * OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #include "stdafx.h"
- #include "Mptrack.h"
- #include "Mainfrm.h"
- #include "InputHandler.h"
- #include "ImageLists.h"
- #include "Childfrm.h"
- #include "Moddoc.h"
- #include "Globals.h"
- #include "Ctrl_ins.h"
- #include "View_ins.h"
- #include "Dlsbank.h"
- #include "ChannelManagerDlg.h"
- #include "ScaleEnvPointsDlg.h"
- #include "../soundlib/MIDIEvents.h"
- #include "../soundlib/mod_specifications.h"
- #include "../common/mptStringBuffer.h"
- #include "FileDialog.h"
- OPENMPT_NAMESPACE_BEGIN
- namespace
- {
- const int ENV_POINT_SIZE = 4;
- const float ENV_MIN_ZOOM = 2.0f;
- const float ENV_MAX_ZOOM = 256.0f;
- }
- // Non-client toolbar
- #define ENV_LEFTBAR_CY Util::ScalePixels(29, m_hWnd)
- #define ENV_LEFTBAR_CXSEP Util::ScalePixels(14, m_hWnd)
- #define ENV_LEFTBAR_CXSPC Util::ScalePixels(3, m_hWnd)
- #define ENV_LEFTBAR_CXBTN Util::ScalePixels(24, m_hWnd)
- #define ENV_LEFTBAR_CYBTN Util::ScalePixels(22, m_hWnd)
- static constexpr UINT cLeftBarButtons[ENV_LEFTBAR_BUTTONS] =
- {
- ID_ENVSEL_VOLUME,
- ID_ENVSEL_PANNING,
- ID_ENVSEL_PITCH,
- ID_SEPARATOR,
- ID_ENVELOPE_VOLUME,
- ID_ENVELOPE_PANNING,
- ID_ENVELOPE_PITCH,
- ID_ENVELOPE_FILTER,
- ID_SEPARATOR,
- ID_ENVELOPE_SETLOOP,
- ID_ENVELOPE_SUSTAIN,
- ID_ENVELOPE_CARRY,
- ID_SEPARATOR,
- ID_INSTRUMENT_SAMPLEMAP,
- ID_SEPARATOR,
- ID_ENVELOPE_VIEWGRID,
- ID_SEPARATOR,
- ID_ENVELOPE_ZOOM_IN,
- ID_ENVELOPE_ZOOM_OUT,
- ID_SEPARATOR,
- ID_ENVELOPE_LOAD,
- ID_ENVELOPE_SAVE,
- };
- IMPLEMENT_SERIAL(CViewInstrument, CModScrollView, 0)
- BEGIN_MESSAGE_MAP(CViewInstrument, CModScrollView)
- //{{AFX_MSG_MAP(CViewInstrument)
- #if !defined(MPT_BUILD_RETRO)
- ON_MESSAGE(WM_DPICHANGED, &CViewInstrument::OnDPIChanged)
- #endif
- ON_WM_ERASEBKGND()
- ON_WM_SETFOCUS()
- ON_WM_SIZE()
- ON_WM_NCCALCSIZE()
- ON_WM_NCPAINT()
- ON_WM_NCHITTEST()
- ON_WM_MOUSEMOVE()
- ON_WM_NCMOUSEMOVE()
- ON_WM_LBUTTONDOWN()
- ON_WM_LBUTTONUP()
- ON_WM_LBUTTONDBLCLK()
- ON_WM_RBUTTONDOWN()
- ON_WM_MBUTTONDOWN()
- ON_WM_XBUTTONUP()
- ON_WM_NCLBUTTONDOWN()
- ON_WM_NCLBUTTONUP()
- ON_WM_NCLBUTTONDBLCLK()
- ON_WM_DROPFILES()
- ON_COMMAND(ID_PREVINSTRUMENT, &CViewInstrument::OnPrevInstrument)
- ON_COMMAND(ID_NEXTINSTRUMENT, &CViewInstrument::OnNextInstrument)
- ON_COMMAND(ID_ENVELOPE_SETLOOP, &CViewInstrument::OnEnvLoopChanged)
- ON_COMMAND(ID_ENVELOPE_SUSTAIN, &CViewInstrument::OnEnvSustainChanged)
- ON_COMMAND(ID_ENVELOPE_CARRY, &CViewInstrument::OnEnvCarryChanged)
- ON_COMMAND(ID_ENVELOPE_INSERTPOINT, &CViewInstrument::OnEnvInsertPoint)
- ON_COMMAND(ID_ENVELOPE_REMOVEPOINT, &CViewInstrument::OnEnvRemovePoint)
- ON_COMMAND(ID_ENVELOPE_VOLUME, &CViewInstrument::OnEnvVolChanged)
- ON_COMMAND(ID_ENVELOPE_PANNING, &CViewInstrument::OnEnvPanChanged)
- ON_COMMAND(ID_ENVELOPE_PITCH, &CViewInstrument::OnEnvPitchChanged)
- ON_COMMAND(ID_ENVELOPE_FILTER, &CViewInstrument::OnEnvFilterChanged)
- ON_COMMAND(ID_ENVELOPE_VIEWGRID, &CViewInstrument::OnEnvToggleGrid)
- ON_COMMAND(ID_ENVELOPE_ZOOM_IN, &CViewInstrument::OnEnvZoomIn)
- ON_COMMAND(ID_ENVELOPE_ZOOM_OUT, &CViewInstrument::OnEnvZoomOut)
- ON_COMMAND(ID_ENVELOPE_LOAD, &CViewInstrument::OnEnvLoad)
- ON_COMMAND(ID_ENVELOPE_SAVE, &CViewInstrument::OnEnvSave)
- ON_COMMAND(ID_ENVSEL_VOLUME, &CViewInstrument::OnSelectVolumeEnv)
- ON_COMMAND(ID_ENVSEL_PANNING, &CViewInstrument::OnSelectPanningEnv)
- ON_COMMAND(ID_ENVSEL_PITCH, &CViewInstrument::OnSelectPitchEnv)
- ON_COMMAND(ID_EDIT_COPY, &CViewInstrument::OnEditCopy)
- ON_COMMAND(ID_EDIT_PASTE, &CViewInstrument::OnEditPaste)
- ON_COMMAND(ID_EDIT_UNDO, &CViewInstrument::OnEditUndo)
- ON_COMMAND(ID_EDIT_REDO, &CViewInstrument::OnEditRedo)
- ON_COMMAND(ID_INSTRUMENT_SAMPLEMAP, &CViewInstrument::OnEditSampleMap)
- ON_COMMAND(ID_ENVELOPE_TOGGLERELEASENODE, &CViewInstrument::OnEnvToggleReleasNode)
- ON_COMMAND(ID_ENVELOPE_SCALEPOINTS, &CViewInstrument::OnEnvelopeScalePoints)
- ON_MESSAGE(WM_MOD_MIDIMSG, &CViewInstrument::OnMidiMsg)
- ON_MESSAGE(WM_MOD_KEYCOMMAND, &CViewInstrument::OnCustomKeyMsg)
- ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CViewInstrument::OnUpdateUndo)
- ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, &CViewInstrument::OnUpdateRedo)
- //}}AFX_MSG_MAP
- ON_WM_MOUSEWHEEL()
- END_MESSAGE_MAP()
- ///////////////////////////////////////////////////////////////
- // CViewInstrument operations
- CViewInstrument::CViewInstrument()
- {
- EnableActiveAccessibility();
- m_rcClient.bottom = 2;
- m_dwNotifyPos.fill(uint32(Notification::PosInvalid));
- MemsetZero(m_NcButtonState);
- m_bmpEnvBar.Create(&CMainFrame::GetMainFrame()->m_EnvelopeIcons);
- m_baPlayingNote.reset();
- }
- void CViewInstrument::OnInitialUpdate()
- {
- CModScrollView::OnInitialUpdate();
- ModifyStyleEx(0, WS_EX_ACCEPTFILES);
- m_zoom = (ENV_POINT_SIZE * m_nDPIx) / 96.0f;
- m_envPointSize = Util::ScalePixels(ENV_POINT_SIZE, m_hWnd);
- UpdateScrollSize();
- UpdateNcButtonState();
- EnableToolTips();
- }
- void CViewInstrument::UpdateScrollSize()
- {
- CModDoc *pModDoc = GetDocument();
- GetClientRect(&m_rcClient);
- if(m_rcClient.bottom < 2)
- m_rcClient.bottom = 2;
- if(pModDoc)
- {
- SIZE sizeTotal, sizePage, sizeLine;
- uint32 maxTick = EnvGetTick(EnvGetLastPoint());
- sizeTotal.cx = mpt::saturate_round<int>((maxTick + 2) * m_zoom);
- sizeTotal.cy = 1;
- sizeLine.cx = mpt::saturate_round<int>(m_zoom);
- sizeLine.cy = 2;
- sizePage.cx = sizeLine.cx * 4;
- sizePage.cy = sizeLine.cy;
- SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
- }
- }
- LRESULT CViewInstrument::OnDPIChanged(WPARAM wParam, LPARAM lParam)
- {
- LRESULT res = CModScrollView::OnDPIChanged(wParam, lParam);
- m_envPointSize = Util::ScalePixels(4, m_hWnd);
- return res;
- }
- void CViewInstrument::PrepareUndo(const char *description)
- {
- GetDocument()->GetInstrumentUndo().PrepareUndo(m_nInstrument, description, m_nEnv);
- }
- // Set instrument (and moddoc) as modified.
- // updateAll: Update all views including this one. Otherwise, only update update other views.
- void CViewInstrument::SetModified(InstrumentHint hint, bool updateAll)
- {
- CModDoc *pModDoc = GetDocument();
- pModDoc->SetModified();
- pModDoc->UpdateAllViews(nullptr, hint.SetData(m_nInstrument), updateAll ? nullptr : this);
- CMainFrame::GetMainFrame()->NotifyAccessibilityUpdate(*this);
- }
- BOOL CViewInstrument::SetCurrentInstrument(INSTRUMENTINDEX nIns, EnvelopeType nEnv)
- {
- CModDoc *pModDoc = GetDocument();
- Notification::Type type;
- if((!pModDoc) || (nIns < 1) || (nIns >= MAX_INSTRUMENTS))
- return FALSE;
- m_nEnv = nEnv;
- m_nInstrument = nIns;
- switch(m_nEnv)
- {
- case ENV_PANNING: type = Notification::PanEnv; break;
- case ENV_PITCH: type = Notification::PitchEnv; break;
- default: m_nEnv = ENV_VOLUME; type = Notification::VolEnv; break;
- }
- pModDoc->SetNotifications(type, m_nInstrument);
- pModDoc->SetFollowWnd(m_hWnd);
- UpdateScrollSize();
- UpdateNcButtonState();
- InvalidateRect(NULL, FALSE);
- return TRUE;
- }
- void CViewInstrument::OnSetFocus(CWnd *pOldWnd)
- {
- CScrollView::OnSetFocus(pOldWnd);
- SetCurrentInstrument(m_nInstrument, m_nEnv);
- }
- LRESULT CViewInstrument::OnModViewMsg(WPARAM wParam, LPARAM lParam)
- {
- switch(wParam)
- {
- case VIEWMSG_SETCURRENTINSTRUMENT:
- SetCurrentInstrument(lParam & 0xFFFF, m_nEnv);
- break;
- case VIEWMSG_LOADSTATE:
- if(lParam)
- {
- INSTRUMENTVIEWSTATE *pState = (INSTRUMENTVIEWSTATE *)lParam;
- if(pState->initialized)
- {
- m_zoom = pState->zoom;
- SetCurrentInstrument(m_nInstrument, pState->nEnv);
- m_bGrid = pState->bGrid;
- }
- }
- break;
- case VIEWMSG_SAVESTATE:
- if(lParam)
- {
- INSTRUMENTVIEWSTATE *pState = (INSTRUMENTVIEWSTATE *)lParam;
- pState->initialized = true;
- pState->zoom = m_zoom;
- pState->nEnv = m_nEnv;
- pState->bGrid = m_bGrid;
- }
- break;
- default:
- return CModScrollView::OnModViewMsg(wParam, lParam);
- }
- return 0;
- }
- uint32 CViewInstrument::EnvGetTick(int nPoint) const
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return 0;
- if((nPoint >= 0) && (nPoint < (int)envelope->size()))
- return envelope->at(nPoint).tick;
- else
- return 0;
- }
- uint32 CViewInstrument::EnvGetValue(int nPoint) const
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return 0;
- if(nPoint >= 0 && nPoint < (int)envelope->size())
- return envelope->at(nPoint).value;
- else
- return 0;
- }
- bool CViewInstrument::EnvSetValue(int nPoint, int32 nTick, int32 nValue, bool moveTail)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr || nPoint < 0)
- return false;
- if(nPoint == 0)
- {
- nTick = 0;
- moveTail = false;
- }
- int tickDiff = 0;
- bool ok = false;
- if(nPoint < (int)envelope->size())
- {
- if(nTick != int32_min)
- {
- nTick = std::max(0, nTick);
- tickDiff = envelope->at(nPoint).tick;
- int mintick = (nPoint > 0) ? envelope->at(nPoint - 1).tick : 0;
- int maxtick;
- if(nPoint + 1 >= (int)envelope->size() || moveTail)
- maxtick = std::numeric_limits<decltype(maxtick)>::max();
- else
- maxtick = envelope->at(nPoint + 1).tick;
- // Can't have multiple points on same tick
- if(nPoint > 0 && mintick < maxtick - 1)
- {
- mintick++;
- if(nPoint + 1 < (int)envelope->size())
- maxtick--;
- }
- if(nTick < mintick)
- nTick = mintick;
- if(nTick > maxtick)
- nTick = maxtick;
- if(nTick != envelope->at(nPoint).tick)
- {
- envelope->at(nPoint).tick = static_cast<EnvelopeNode::tick_t>(nTick);
- ok = true;
- }
- }
- const int maxVal = (GetDocument()->GetModType() != MOD_TYPE_XM || m_nEnv != ENV_PANNING) ? 64 : 63;
- if(nValue != int32_min)
- {
- Limit(nValue, 0, maxVal);
- if(nValue != envelope->at(nPoint).value)
- {
- envelope->at(nPoint).value = static_cast<EnvelopeNode::value_t>(nValue);
- ok = true;
- }
- }
- }
- if(ok && moveTail)
- {
- // Move all points after modified point as well.
- tickDiff = envelope->at(nPoint).tick - tickDiff;
- for(auto it = envelope->begin() + nPoint + 1; it != envelope->end(); it++)
- {
- it->tick = static_cast<EnvelopeNode::tick_t>(std::max(0, (int)it->tick + tickDiff));
- }
- }
- return ok;
- }
- uint32 CViewInstrument::EnvGetNumPoints() const
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return 0;
- return envelope->size();
- }
- uint32 CViewInstrument::EnvGetLastPoint() const
- {
- uint32 nPoints = EnvGetNumPoints();
- if(nPoints > 0)
- return nPoints - 1;
- return 0;
- }
- // Return if an envelope flag is set.
- bool CViewInstrument::EnvGetFlag(const EnvelopeFlags dwFlag) const
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv != nullptr)
- return pEnv->dwFlags[dwFlag];
- return false;
- }
- uint32 CViewInstrument::EnvGetLoopStart() const
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return 0;
- return envelope->nLoopStart;
- }
- uint32 CViewInstrument::EnvGetLoopEnd() const
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return 0;
- return envelope->nLoopEnd;
- }
- uint32 CViewInstrument::EnvGetSustainStart() const
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return 0;
- return envelope->nSustainStart;
- }
- uint32 CViewInstrument::EnvGetSustainEnd() const
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return 0;
- return envelope->nSustainEnd;
- }
- bool CViewInstrument::EnvGetVolEnv() const
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns)
- return pIns->VolEnv.dwFlags[ENV_ENABLED] != 0;
- return false;
- }
- bool CViewInstrument::EnvGetPanEnv() const
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns)
- return pIns->PanEnv.dwFlags[ENV_ENABLED] != 0;
- return false;
- }
- bool CViewInstrument::EnvGetPitchEnv() const
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns)
- return ((pIns->PitchEnv.dwFlags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED);
- return false;
- }
- bool CViewInstrument::EnvGetFilterEnv() const
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns)
- return ((pIns->PitchEnv.dwFlags & (ENV_ENABLED | ENV_FILTER)) == (ENV_ENABLED | ENV_FILTER));
- return false;
- }
- bool CViewInstrument::EnvSetLoopStart(int nPoint)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return false;
- if(nPoint < 0 || nPoint > (int)EnvGetLastPoint())
- return false;
- if(nPoint != envelope->nLoopStart)
- {
- envelope->nLoopStart = static_cast<decltype(envelope->nLoopStart)>(nPoint);
- if(envelope->nLoopEnd < nPoint)
- envelope->nLoopEnd = static_cast<decltype(envelope->nLoopEnd)>(nPoint);
- return true;
- } else
- {
- return false;
- }
- }
- bool CViewInstrument::EnvSetLoopEnd(int nPoint)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return false;
- if(nPoint < 0 || nPoint > (int)EnvGetLastPoint())
- return false;
- if(nPoint != envelope->nLoopEnd)
- {
- envelope->nLoopEnd = static_cast<decltype(envelope->nLoopEnd)>(nPoint);
- if(envelope->nLoopStart > nPoint)
- envelope->nLoopStart = static_cast<decltype(envelope->nLoopStart)>(nPoint);
- return true;
- } else
- {
- return false;
- }
- }
- bool CViewInstrument::EnvSetSustainStart(int nPoint)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return false;
- if(nPoint < 0 || nPoint > (int)EnvGetLastPoint())
- return false;
- // We won't do any security checks here as GetEnvelopePtr() does that for us.
- CSoundFile &sndFile = GetDocument()->GetSoundFile();
- if(nPoint != envelope->nSustainStart)
- {
- envelope->nSustainStart = static_cast<decltype(envelope->nSustainStart)>(nPoint);
- if((envelope->nSustainEnd < nPoint) || (sndFile.GetType() & MOD_TYPE_XM))
- envelope->nSustainEnd = static_cast<decltype(envelope->nSustainEnd)>(nPoint);
- return true;
- } else
- {
- return false;
- }
- }
- bool CViewInstrument::EnvSetSustainEnd(int nPoint)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return false;
- if(nPoint < 0 || nPoint > (int)EnvGetLastPoint())
- return false;
- // We won't do any security checks here as GetEnvelopePtr() does that for us.
- CSoundFile &sndFile = GetDocument()->GetSoundFile();
- if(nPoint != envelope->nSustainEnd)
- {
- envelope->nSustainEnd = static_cast<decltype(envelope->nSustainEnd)>(nPoint);
- if((envelope->nSustainStart > nPoint) || (sndFile.GetType() & MOD_TYPE_XM))
- envelope->nSustainStart = static_cast<decltype(envelope->nSustainStart)>(nPoint);
- return true;
- } else
- {
- return false;
- }
- }
- bool CViewInstrument::EnvToggleReleaseNode(int nPoint)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return false;
- if(nPoint < 0 || nPoint >= (int)EnvGetNumPoints())
- return false;
- // Don't allow release nodes in IT/XM. GetDocument()/... nullptr check is done in GetEnvelopePtr, so no need to check twice.
- if(!GetDocument()->GetSoundFile().GetModSpecifications().hasReleaseNode)
- {
- if(envelope->nReleaseNode != ENV_RELEASE_NODE_UNSET)
- {
- envelope->nReleaseNode = ENV_RELEASE_NODE_UNSET;
- return true;
- }
- return false;
- }
- if(envelope->nReleaseNode == nPoint)
- {
- envelope->nReleaseNode = ENV_RELEASE_NODE_UNSET;
- } else
- {
- envelope->nReleaseNode = static_cast<decltype(envelope->nReleaseNode)>(nPoint);
- }
- return true;
- }
- // Enable or disable a flag of the current envelope
- bool CViewInstrument::EnvSetFlag(EnvelopeFlags flag, bool enable)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr || envelope->empty())
- return false;
- bool modified = envelope->dwFlags[flag] != enable;
- PrepareUndo("Toggle Envelope Flag");
- envelope->dwFlags.set(flag, enable);
- return modified;
- }
- bool CViewInstrument::EnvToggleEnv(EnvelopeType envelope, CSoundFile &sndFile, ModInstrument &ins, bool enable, EnvelopeNode::value_t defaultValue, EnvelopeFlags extraFlags)
- {
- InstrumentEnvelope &env = ins.GetEnvelope(envelope);
- const FlagSet<EnvelopeFlags> flags = (ENV_ENABLED | extraFlags);
- env.dwFlags.set(flags, enable);
- if(enable && env.empty())
- {
- env.reserve(2);
- env.push_back(EnvelopeNode(0, defaultValue));
- env.push_back(EnvelopeNode(10, defaultValue));
- InvalidateRect(NULL, FALSE);
- }
- CriticalSection cs;
- // Update mixing flags...
- for(auto &chn : sndFile.m_PlayState.Chn)
- {
- if(chn.pModInstrument == &ins)
- {
- chn.GetEnvelope(envelope).flags.set(flags, enable);
- }
- }
- return true;
- }
- bool CViewInstrument::EnvSetVolEnv(bool enable)
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns == nullptr)
- return false;
- return EnvToggleEnv(ENV_VOLUME, GetDocument()->GetSoundFile(), *pIns, enable, 64);
- }
- bool CViewInstrument::EnvSetPanEnv(bool enable)
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns == nullptr)
- return false;
- return EnvToggleEnv(ENV_PANNING, GetDocument()->GetSoundFile(), *pIns, enable, 32);
- }
- bool CViewInstrument::EnvSetPitchEnv(bool enable)
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns == nullptr)
- return false;
- pIns->PitchEnv.dwFlags.reset(ENV_FILTER);
- return EnvToggleEnv(ENV_PITCH, GetDocument()->GetSoundFile(), *pIns, enable, 32);
- }
- bool CViewInstrument::EnvSetFilterEnv(bool enable)
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns == nullptr)
- return false;
- return EnvToggleEnv(ENV_PITCH, GetDocument()->GetSoundFile(), *pIns, enable, 64, ENV_FILTER);
- }
- uint32 CViewInstrument::DragItemToEnvPoint() const
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !m_nDragItem)
- return 0;
- switch(m_nDragItem)
- {
- case ENV_DRAGLOOPSTART: return pEnv->nLoopStart;
- case ENV_DRAGLOOPEND: return pEnv->nLoopEnd;
- case ENV_DRAGSUSTAINSTART: return pEnv->nSustainStart;
- case ENV_DRAGSUSTAINEND: return pEnv->nSustainEnd;
- default: return m_nDragItem - 1;
- }
- }
- int CViewInstrument::TickToScreen(int tick) const
- {
- return static_cast<int>((tick * m_zoom) - m_nScrollPosX + m_envPointSize);
- }
- int CViewInstrument::PointToScreen(int nPoint) const
- {
- return TickToScreen(EnvGetTick(nPoint));
- }
- int CViewInstrument::ScreenToTick(int x) const
- {
- int offset = m_nScrollPosX + x;
- if(offset < m_envPointSize)
- return 0;
- return mpt::saturate_round<int>((offset - m_envPointSize) / m_zoom);
- }
- int CViewInstrument::ScreenToValue(int y) const
- {
- if(m_rcClient.bottom < 2)
- return ENVELOPE_MIN;
- int n = ENVELOPE_MAX - Util::muldivr(y, ENVELOPE_MAX, m_rcClient.bottom - 1);
- if(n < ENVELOPE_MIN)
- return ENVELOPE_MIN;
- if(n > ENVELOPE_MAX)
- return ENVELOPE_MAX;
- return n;
- }
- int CViewInstrument::ScreenToPoint(int x0, int y0) const
- {
- int nPoint = -1;
- int64 ydist = int64_max, xdist = int64_max;
- int numPoints = EnvGetNumPoints();
- for(int i = 0; i < numPoints; i++)
- {
- int dx = x0 - PointToScreen(i);
- int64 dx2 = Util::mul32to64(dx, dx);
- if(dx2 <= xdist)
- {
- int dy = y0 - ValueToScreen(EnvGetValue(i));
- int64 dy2 = Util::mul32to64(dy, dy);
- if(dx2 < xdist || (dx2 == xdist && dy2 < ydist))
- {
- nPoint = i;
- xdist = dx2;
- ydist = dy2;
- }
- }
- }
- return nPoint;
- }
- bool CViewInstrument::GetNcButtonRect(UINT button, CRect &rect) const
- {
- rect.left = 4;
- rect.top = 3;
- rect.bottom = rect.top + ENV_LEFTBAR_CYBTN;
- if(button >= ENV_LEFTBAR_BUTTONS)
- return false;
- for(UINT i = 0; i < button; i++)
- {
- if(cLeftBarButtons[i] == ID_SEPARATOR)
- rect.left += ENV_LEFTBAR_CXSEP;
- else
- rect.left += ENV_LEFTBAR_CXBTN + ENV_LEFTBAR_CXSPC;
- }
- if(cLeftBarButtons[button] == ID_SEPARATOR)
- {
- rect.left += ENV_LEFTBAR_CXSEP / 2 - 2;
- rect.right = rect.left + 2;
- return false;
- } else
- {
- rect.right = rect.left + ENV_LEFTBAR_CXBTN;
- }
- return true;
- }
- UINT CViewInstrument::GetNcButtonAtPoint(CPoint point, CRect *outRect) const
- {
- CRect rect, rcWnd;
- UINT button = uint32_max;
- GetWindowRect(&rcWnd);
- for(UINT i = 0; i < ENV_LEFTBAR_BUTTONS; i++)
- {
- if(!(m_NcButtonState[i] & NCBTNS_DISABLED) && GetNcButtonRect(i, rect))
- {
- rect.OffsetRect(rcWnd.left, rcWnd.top);
- if(rect.PtInRect(point))
- {
- button = i;
- break;
- }
- }
- }
- if(outRect)
- *outRect = rect;
- return button;
- }
- void CViewInstrument::UpdateNcButtonState()
- {
- CModDoc *pModDoc = GetDocument();
- if(!pModDoc)
- return;
- CSoundFile &sndFile = pModDoc->GetSoundFile();
- CDC *pDC = NULL;
- for (UINT i=0; i<ENV_LEFTBAR_BUTTONS; i++) if (cLeftBarButtons[i] != ID_SEPARATOR)
- {
- DWORD dwStyle = 0;
- switch(cLeftBarButtons[i])
- {
- case ID_ENVSEL_VOLUME: if (m_nEnv == ENV_VOLUME) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVSEL_PANNING: if (m_nEnv == ENV_PANNING) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVSEL_PITCH: if (!(sndFile.GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT))) dwStyle |= NCBTNS_DISABLED;
- else if (m_nEnv == ENV_PITCH) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_SETLOOP: if (EnvGetLoop()) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_SUSTAIN: if (EnvGetSustain()) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_CARRY: if (!(sndFile.GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT))) dwStyle |= NCBTNS_DISABLED;
- else if (EnvGetCarry()) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_VOLUME: if (EnvGetVolEnv()) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_PANNING: if (EnvGetPanEnv()) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_PITCH: if (!(sndFile.GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT))) dwStyle |= NCBTNS_DISABLED; else
- if (EnvGetPitchEnv()) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_FILTER: if (!(sndFile.GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT))) dwStyle |= NCBTNS_DISABLED; else
- if (EnvGetFilterEnv()) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_VIEWGRID: if (m_bGrid) dwStyle |= NCBTNS_CHECKED; break;
- case ID_ENVELOPE_ZOOM_IN: if (m_zoom >= ENV_MAX_ZOOM) dwStyle |= NCBTNS_DISABLED; break;
- case ID_ENVELOPE_ZOOM_OUT: if (m_zoom <= ENV_MIN_ZOOM) dwStyle |= NCBTNS_DISABLED; break;
- case ID_ENVELOPE_LOAD:
- case ID_ENVELOPE_SAVE: if (GetInstrumentPtr() == nullptr) dwStyle |= NCBTNS_DISABLED; break;
- }
- if (m_nBtnMouseOver == i)
- {
- dwStyle |= NCBTNS_MOUSEOVER;
- if (m_dwStatus & INSSTATUS_NCLBTNDOWN) dwStyle |= NCBTNS_PUSHED;
- }
- if (dwStyle != m_NcButtonState[i])
- {
- m_NcButtonState[i] = dwStyle;
- if (!pDC) pDC = GetWindowDC();
- DrawNcButton(pDC, i);
- }
- }
- if (pDC) ReleaseDC(pDC);
- }
- ////////////////////////////////////////////////////////////////////
- // CViewInstrument drawing
- void CViewInstrument::UpdateView(UpdateHint hint, CObject *pObj)
- {
- if(pObj == this)
- {
- return;
- }
- const InstrumentHint instrHint = hint.ToType<InstrumentHint>();
- FlagSet<HintType> hintType = instrHint.GetType();
- const INSTRUMENTINDEX updateIns = instrHint.GetInstrument();
- if(hintType[HINT_MPTOPTIONS | HINT_MODTYPE]
- || (hintType[HINT_ENVELOPE] && (m_nInstrument == updateIns || updateIns == 0)))
- {
- UpdateScrollSize();
- UpdateNcButtonState();
- InvalidateRect(NULL, FALSE);
- }
- }
- void CViewInstrument::DrawGrid(CDC *pDC, uint32 speed)
- {
- bool windowResized = false;
- if(m_dcGrid.m_hDC)
- {
- m_dcGrid.SelectObject(m_pbmpOldGrid);
- m_dcGrid.DeleteDC();
- m_bmpGrid.DeleteObject();
- windowResized = true;
- }
- if(windowResized || m_bGridForceRedraw || (m_nScrollPosX != m_GridScrollPos) || (speed != (UINT)m_GridSpeed) && speed > 0)
- {
- m_GridSpeed = speed;
- m_GridScrollPos = m_nScrollPosX;
- m_bGridForceRedraw = false;
- // create a memory based dc for drawing the grid
- m_dcGrid.CreateCompatibleDC(pDC);
- m_bmpGrid.CreateCompatibleBitmap(pDC, m_rcClient.Width(), m_rcClient.Height());
- m_pbmpOldGrid = *m_dcGrid.SelectObject(&m_bmpGrid);
- // Do draw
- const int width = m_rcClient.Width();
- int rowsPerBeat = 1, rowsPerMeasure = 1;
- const CModDoc *modDoc = GetDocument();
- if(modDoc != nullptr)
- {
- rowsPerBeat = modDoc->GetSoundFile().m_nDefaultRowsPerBeat;
- rowsPerMeasure = modDoc->GetSoundFile().m_nDefaultRowsPerMeasure;
- }
- // Paint it black!
- m_dcGrid.FillSolidRect(&m_rcClient, TrackerSettings::Instance().rgbCustomColors[MODCOLOR_BACKENV]);
- const uint32 startTick = (ScreenToTick(0) / speed) * speed;
- const uint32 endTick = (ScreenToTick(width) / speed) * speed;
- auto oldPen = m_dcGrid.SelectStockObject(DC_PEN);
- for(uint32 tick = startTick, row = startTick / speed; tick <= endTick; tick += speed, row++)
- {
- if(rowsPerMeasure > 0 && row % rowsPerMeasure == 0)
- m_dcGrid.SetDCPenColor(RGB(0x80, 0x80, 0x80));
- else if(rowsPerBeat > 0 && row % rowsPerBeat == 0)
- m_dcGrid.SetDCPenColor(RGB(0x55, 0x55, 0x55));
- else
- m_dcGrid.SetDCPenColor(RGB(0x33, 0x33, 0x33));
- int x = TickToScreen(tick);
- m_dcGrid.MoveTo(x, 0);
- m_dcGrid.LineTo(x, m_rcClient.bottom);
- }
- if(oldPen)
- m_dcGrid.SelectObject(oldPen);
- }
- pDC->BitBlt(m_rcClient.left, m_rcClient.top, m_rcClient.Width(), m_rcClient.Height(), &m_dcGrid, 0, 0, SRCCOPY);
- }
- void CViewInstrument::OnDraw(CDC *pDC)
- {
- CModDoc *pModDoc = GetDocument();
- if((!pModDoc) || (!pDC))
- return;
- // to avoid flicker, establish a memory dc, draw to it
- // and then BitBlt it to the destination "pDC"
- //check for window resize
- if(m_dcMemMain.GetSafeHdc() && m_rcOldClient != m_rcClient)
- {
- m_dcMemMain.SelectObject(oldBitmap);
- m_dcMemMain.DeleteDC();
- m_bmpMemMain.DeleteObject();
- }
- if(!m_dcMemMain.m_hDC)
- {
- m_dcMemMain.CreateCompatibleDC(pDC);
- if(!m_dcMemMain.m_hDC)
- return;
- }
- if(!m_bmpMemMain.m_hObject)
- {
- m_bmpMemMain.CreateCompatibleBitmap(pDC, m_rcClient.Width(), m_rcClient.Height());
- }
- m_rcOldClient = m_rcClient;
- oldBitmap = *m_dcMemMain.SelectObject(&m_bmpMemMain);
- auto stockBrush = CBrush::FromHandle(GetStockBrush(DC_BRUSH));
- if(m_bGrid)
- {
- DrawGrid(&m_dcMemMain, pModDoc->GetSoundFile().m_PlayState.m_nMusicSpeed);
- } else
- {
- // Paint it black!
- m_dcMemMain.FillSolidRect(&m_rcClient, TrackerSettings::Instance().rgbCustomColors[MODCOLOR_BACKENV]);
- }
- auto oldPen = m_dcMemMain.SelectObject(CMainFrame::penDarkGray);
- // Middle line (half volume or pitch / panning center)
- const int ymed = (m_rcClient.bottom - 1) / 2;
- m_dcMemMain.MoveTo(0, ymed);
- m_dcMemMain.LineTo(m_rcClient.right, ymed);
- // Drawing Loop Start/End
- if(EnvGetLoop())
- {
- m_dcMemMain.SelectObject(m_nDragItem == ENV_DRAGLOOPSTART ? CMainFrame::penGray99 : CMainFrame::penDarkGray);
- int x1 = PointToScreen(EnvGetLoopStart()) - m_envPointSize / 2;
- m_dcMemMain.MoveTo(x1, 0);
- m_dcMemMain.LineTo(x1, m_rcClient.bottom);
- m_dcMemMain.SelectObject(m_nDragItem == ENV_DRAGLOOPEND ? CMainFrame::penGray99 : CMainFrame::penDarkGray);
- int x2 = PointToScreen(EnvGetLoopEnd()) + m_envPointSize / 2;
- m_dcMemMain.MoveTo(x2, 0);
- m_dcMemMain.LineTo(x2, m_rcClient.bottom);
- }
- // Drawing Sustain Start/End
- if(EnvGetSustain())
- {
- m_dcMemMain.SelectObject(CMainFrame::penHalfDarkGray);
- int nspace = m_rcClient.bottom / 4;
- int n1 = EnvGetSustainStart();
- int x1 = PointToScreen(n1) - m_envPointSize / 2;
- int y1 = ValueToScreen(EnvGetValue(n1));
- m_dcMemMain.MoveTo(x1, y1 - nspace);
- m_dcMemMain.LineTo(x1, y1 + nspace);
- int n2 = EnvGetSustainEnd();
- int x2 = PointToScreen(n2) + m_envPointSize / 2;
- int y2 = ValueToScreen(EnvGetValue(n2));
- m_dcMemMain.MoveTo(x2, y2 - nspace);
- m_dcMemMain.LineTo(x2, y2 + nspace);
- }
- uint32 maxpoint = EnvGetNumPoints();
- // Drawing Envelope
- if(maxpoint)
- {
- maxpoint--;
- m_dcMemMain.SelectObject(GetStockObject(DC_PEN));
- m_dcMemMain.SetDCPenColor(TrackerSettings::Instance().rgbCustomColors[MODCOLOR_ENVELOPES]);
- uint32 releaseNode = EnvGetReleaseNode();
- RECT rect;
- for(uint32 i = 0; i <= maxpoint; i++)
- {
- int x = PointToScreen(i);
- int y = ValueToScreen(EnvGetValue(i));
- rect.left = x - m_envPointSize + 1;
- rect.top = y - m_envPointSize + 1;
- rect.right = x + m_envPointSize;
- rect.bottom = y + m_envPointSize;
- if(i)
- m_dcMemMain.LineTo(x, y);
- else
- m_dcMemMain.MoveTo(x, y);
- if(i == releaseNode)
- {
- m_dcMemMain.SetDCBrushColor(RGB(0xFF, 0x00, 0x00));
- m_dcMemMain.FrameRect(&rect, stockBrush);
- m_dcMemMain.SetDCPenColor(TrackerSettings::Instance().rgbCustomColors[MODCOLOR_ENVELOPE_RELEASE]);
- } else if(i == m_nDragItem - 1)
- {
- // currently selected env point
- m_dcMemMain.SetDCBrushColor(RGB(0xFF, 0xFF, 0x00));
- m_dcMemMain.FrameRect(&rect, stockBrush);
- } else
- {
- m_dcMemMain.SetDCBrushColor(RGB(0xFF, 0xFF, 0xFF));
- m_dcMemMain.FrameRect(&rect, stockBrush);
- }
- }
- }
- DrawPositionMarks();
- if(oldPen)
- m_dcMemMain.SelectObject(oldPen);
- pDC->BitBlt(m_rcClient.left, m_rcClient.top, m_rcClient.Width(), m_rcClient.Height(), &m_dcMemMain, 0, 0, SRCCOPY);
- }
- uint8 CViewInstrument::EnvGetReleaseNode()
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr)
- return ENV_RELEASE_NODE_UNSET;
- return envelope->nReleaseNode;
- }
- bool CViewInstrument::EnvRemovePoint(uint32 nPoint)
- {
- CModDoc *pModDoc = GetDocument();
- if((pModDoc) && (nPoint <= EnvGetLastPoint()))
- {
- ModInstrument *pIns = pModDoc->GetSoundFile().Instruments[m_nInstrument];
- if(pIns)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope == nullptr || envelope->empty())
- return false;
- PrepareUndo("Remove Envelope Point");
- envelope->erase(envelope->begin() + nPoint);
- if (nPoint >= envelope->size()) nPoint = envelope->size() - 1;
- if (envelope->nLoopStart > nPoint) envelope->nLoopStart--;
- if (envelope->nLoopEnd > nPoint) envelope->nLoopEnd--;
- if (envelope->nSustainStart > nPoint) envelope->nSustainStart--;
- if (envelope->nSustainEnd > nPoint) envelope->nSustainEnd--;
- if (envelope->nReleaseNode>nPoint && envelope->nReleaseNode != ENV_RELEASE_NODE_UNSET) envelope->nReleaseNode--;
- envelope->at(0).tick = 0;
- if(envelope->size() <= 1)
- {
- // if only one node is left, just disable the envelope completely
- *envelope = InstrumentEnvelope();
- }
- SetModified(InstrumentHint().Envelope(), true);
- return true;
- }
- }
- return false;
- }
- // Insert point. Returns 0 if error occurred, else point ID + 1.
- uint32 CViewInstrument::EnvInsertPoint(int nTick, int nValue)
- {
- CModDoc *pModDoc = GetDocument();
- if(pModDoc && nTick >= 0)
- {
- InstrumentEnvelope *envelope = GetEnvelopePtr();
- if(envelope != nullptr && envelope->size() < pModDoc->GetSoundFile().GetModSpecifications().envelopePointsMax)
- {
- nValue = Clamp(nValue, ENVELOPE_MIN, ENVELOPE_MAX);
- if(std::binary_search(envelope->cbegin(), envelope->cend(), EnvelopeNode(static_cast<EnvelopeNode::tick_t>(nTick), 0),
- [] (const EnvelopeNode &l, const EnvelopeNode &r) { return l.tick < r.tick; }))
- {
- // Don't want to insert a node at the same position as another node.
- return 0;
- }
- uint8 defaultValue;
- switch(m_nEnv)
- {
- case ENV_VOLUME:
- defaultValue = ENVELOPE_MAX;
- break;
- case ENV_PANNING:
- defaultValue = ENVELOPE_MID;
- break;
- case ENV_PITCH:
- defaultValue = envelope->dwFlags[ENV_FILTER] ? ENVELOPE_MAX : ENVELOPE_MID;
- break;
- default:
- return 0;
- }
- PrepareUndo("Insert Envelope Point");
- if(envelope->empty())
- {
- envelope->reserve(2);
- envelope->push_back(EnvelopeNode(0, defaultValue));
- envelope->dwFlags.set(ENV_ENABLED);
- if(nTick == 0)
- {
- // Can't insert two points on the same tick!
- nTick = 16;
- }
- }
- uint32 i = 0;
- for(i = 0; i < envelope->size(); i++) if(nTick <= envelope->at(i).tick) break;
- envelope->insert(envelope->begin() + i, EnvelopeNode(mpt::saturate_cast<EnvelopeNode::tick_t>(nTick), static_cast<EnvelopeNode::value_t>(nValue)));
- if(envelope->nLoopStart >= i) envelope->nLoopStart++;
- if(envelope->nLoopEnd >= i) envelope->nLoopEnd++;
- if(envelope->nSustainStart >= i) envelope->nSustainStart++;
- if(envelope->nSustainEnd >= i) envelope->nSustainEnd++;
- if(envelope->nReleaseNode >= i && envelope->nReleaseNode != ENV_RELEASE_NODE_UNSET) envelope->nReleaseNode++;
- SetModified(InstrumentHint().Envelope(), true);
- return i + 1;
- }
- }
- return 0;
- }
- void CViewInstrument::DrawPositionMarks()
- {
- CRect rect;
- for(auto pos : m_dwNotifyPos) if (pos != Notification::PosInvalid)
- {
- rect.top = -2;
- rect.left = TickToScreen(pos);
- rect.right = rect.left + 1;
- rect.bottom = m_rcClient.bottom + 1;
- InvertRect(m_dcMemMain.m_hDC, &rect);
- }
- }
- LRESULT CViewInstrument::OnPlayerNotify(Notification *pnotify)
- {
- Notification::Type type;
- CModDoc *pModDoc = GetDocument();
- if((!pnotify) || (!pModDoc))
- return 0;
- switch(m_nEnv)
- {
- case ENV_PANNING: type = Notification::PanEnv; break;
- case ENV_PITCH: type = Notification::PitchEnv; break;
- default: type = Notification::VolEnv; break;
- }
- if(pnotify->type[Notification::Stop])
- {
- bool invalidate = false;
- for(auto &pos : m_dwNotifyPos)
- {
- if(pos != (uint32)Notification::PosInvalid)
- {
- pos = (uint32)Notification::PosInvalid;
- invalidate = true;
- }
- }
- if(invalidate)
- {
- InvalidateEnvelope();
- }
- m_baPlayingNote.reset();
- } else if(pnotify->type[type] && pnotify->item == m_nInstrument)
- {
- bool update = false;
- for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
- {
- uint32 newpos = (uint32)pnotify->pos[i];
- if(m_dwNotifyPos[i] != newpos)
- {
- update = true;
- break;
- }
- }
- if(update)
- {
- HDC hdc = ::GetDC(m_hWnd);
- DrawPositionMarks();
- for(CHANNELINDEX j = 0; j < MAX_CHANNELS; j++)
- {
- uint32 newpos = (uint32)pnotify->pos[j];
- m_dwNotifyPos[j] = newpos;
- }
- DrawPositionMarks();
- BitBlt(hdc, m_rcClient.left, m_rcClient.top, m_rcClient.Width(), m_rcClient.Height(), m_dcMemMain.GetSafeHdc(), 0, 0, SRCCOPY);
- ::ReleaseDC(m_hWnd, hdc);
- }
- }
- return 0;
- }
- void CViewInstrument::DrawNcButton(CDC *pDC, UINT nBtn)
- {
- CRect rect;
- COLORREF crHi = GetSysColor(COLOR_3DHILIGHT);
- COLORREF crDk = GetSysColor(COLOR_3DSHADOW);
- COLORREF crFc = GetSysColor(COLOR_3DFACE);
- COLORREF c1, c2;
- if(GetNcButtonRect(nBtn, rect))
- {
- DWORD dwStyle = m_NcButtonState[nBtn];
- COLORREF c3, c4;
- int xofs = 0, yofs = 0, nImage = 0;
- c1 = c2 = c3 = c4 = crFc;
- if(!(TrackerSettings::Instance().m_dwPatternSetup & PATTERN_FLATBUTTONS))
- {
- c1 = c3 = crHi;
- c2 = crDk;
- c4 = RGB(0, 0, 0);
- }
- if(dwStyle & (NCBTNS_PUSHED | NCBTNS_CHECKED))
- {
- c1 = crDk;
- c2 = crHi;
- if(!(TrackerSettings::Instance().m_dwPatternSetup & PATTERN_FLATBUTTONS))
- {
- c4 = crHi;
- c3 = (dwStyle & NCBTNS_PUSHED) ? RGB(0, 0, 0) : crDk;
- }
- xofs = yofs = 1;
- } else if((dwStyle & NCBTNS_MOUSEOVER) && (TrackerSettings::Instance().m_dwPatternSetup & PATTERN_FLATBUTTONS))
- {
- c1 = crHi;
- c2 = crDk;
- }
- switch(cLeftBarButtons[nBtn])
- {
- case ID_ENVSEL_VOLUME: nImage = IIMAGE_VOLENV; break;
- case ID_ENVSEL_PANNING: nImage = IIMAGE_PANENV; break;
- case ID_ENVSEL_PITCH: nImage = (dwStyle & NCBTNS_DISABLED) ? IIMAGE_NOPITCHENV : IIMAGE_PITCHENV; break;
- case ID_ENVELOPE_SETLOOP: nImage = IIMAGE_LOOP; break;
- case ID_ENVELOPE_SUSTAIN: nImage = IIMAGE_SUSTAIN; break;
- case ID_ENVELOPE_CARRY: nImage = (dwStyle & NCBTNS_DISABLED) ? IIMAGE_NOCARRY : IIMAGE_CARRY; break;
- case ID_ENVELOPE_VOLUME: nImage = IIMAGE_VOLSWITCH; break;
- case ID_ENVELOPE_PANNING: nImage = IIMAGE_PANSWITCH; break;
- case ID_ENVELOPE_PITCH: nImage = (dwStyle & NCBTNS_DISABLED) ? IIMAGE_NOPITCHSWITCH : IIMAGE_PITCHSWITCH; break;
- case ID_ENVELOPE_FILTER: nImage = (dwStyle & NCBTNS_DISABLED) ? IIMAGE_NOFILTERSWITCH : IIMAGE_FILTERSWITCH; break;
- case ID_INSTRUMENT_SAMPLEMAP: nImage = IIMAGE_SAMPLEMAP; break;
- case ID_ENVELOPE_VIEWGRID: nImage = IIMAGE_GRID; break;
- case ID_ENVELOPE_ZOOM_IN: nImage = (dwStyle & NCBTNS_DISABLED) ? IIMAGE_NOZOOMIN : IIMAGE_ZOOMIN; break;
- case ID_ENVELOPE_ZOOM_OUT: nImage = (dwStyle & NCBTNS_DISABLED) ? IIMAGE_NOZOOMOUT : IIMAGE_ZOOMOUT; break;
- case ID_ENVELOPE_LOAD: nImage = IIMAGE_LOAD; break;
- case ID_ENVELOPE_SAVE: nImage = IIMAGE_SAVE; break;
- }
- pDC->Draw3dRect(rect.left - 1, rect.top - 1, ENV_LEFTBAR_CXBTN + 2, ENV_LEFTBAR_CYBTN + 2, c3, c4);
- pDC->Draw3dRect(rect.left, rect.top, ENV_LEFTBAR_CXBTN, ENV_LEFTBAR_CYBTN, c1, c2);
- rect.DeflateRect(1, 1);
- pDC->FillSolidRect(&rect, crFc);
- rect.left += xofs;
- rect.top += yofs;
- if(dwStyle & NCBTNS_CHECKED)
- m_bmpEnvBar.Draw(pDC, IIMAGE_CHECKED, rect.TopLeft(), ILD_NORMAL);
- m_bmpEnvBar.Draw(pDC, nImage, rect.TopLeft(), ILD_NORMAL);
- } else
- {
- c1 = c2 = crFc;
- if(TrackerSettings::Instance().m_dwPatternSetup & PATTERN_FLATBUTTONS)
- {
- c1 = crDk;
- c2 = crHi;
- }
- pDC->Draw3dRect(rect.left, rect.top, 2, ENV_LEFTBAR_CYBTN, c1, c2);
- }
- }
- void CViewInstrument::OnNcPaint()
- {
- RECT rect;
- CModScrollView::OnNcPaint();
- GetWindowRect(&rect);
- // Assumes there is no other non-client items
- rect.bottom = ENV_LEFTBAR_CY;
- rect.right -= rect.left;
- rect.left = 0;
- rect.top = 0;
- if((rect.left < rect.right) && (rect.top < rect.bottom))
- {
- CDC *pDC = GetWindowDC();
- {
- // Shadow
- auto shadowRect = rect;
- shadowRect.top = shadowRect.bottom - 1;
- pDC->FillSolidRect(&shadowRect, GetSysColor(COLOR_BTNSHADOW));
- }
- rect.bottom--;
- if(rect.top < rect.bottom)
- pDC->FillSolidRect(&rect, GetSysColor(COLOR_BTNFACE));
- if(rect.top + 2 < rect.bottom)
- {
- for(UINT i = 0; i < ENV_LEFTBAR_BUTTONS; i++)
- {
- DrawNcButton(pDC, i);
- }
- }
- ReleaseDC(pDC);
- }
- }
- ////////////////////////////////////////////////////////////////////
- // CViewInstrument messages
- void CViewInstrument::OnSize(UINT nType, int cx, int cy)
- {
- CModScrollView::OnSize(nType, cx, cy);
- if(((nType == SIZE_RESTORED) || (nType == SIZE_MAXIMIZED)) && (cx > 0) && (cy > 0))
- {
- UpdateScrollSize();
- }
- }
- void CViewInstrument::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS *lpncsp)
- {
- CModScrollView::OnNcCalcSize(bCalcValidRects, lpncsp);
- if(lpncsp)
- {
- lpncsp->rgrc[0].top += ENV_LEFTBAR_CY;
- if(lpncsp->rgrc[0].bottom < lpncsp->rgrc[0].top)
- lpncsp->rgrc[0].top = lpncsp->rgrc[0].bottom;
- }
- }
- void CViewInstrument::OnNcMouseMove(UINT nHitTest, CPoint point)
- {
- const auto button = GetNcButtonAtPoint(point);
- if(button != m_nBtnMouseOver)
- {
- CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
- if(pMainFrm)
- {
- CString strText;
- if(button < ENV_LEFTBAR_BUTTONS && cLeftBarButtons[button] != ID_SEPARATOR)
- {
- strText = LoadResourceString(cLeftBarButtons[button]);
- }
- pMainFrm->SetHelpText(strText);
- }
- m_nBtnMouseOver = button;
- UpdateNcButtonState();
- }
- CModScrollView::OnNcMouseMove(nHitTest, point);
- }
- void CViewInstrument::OnNcLButtonDown(UINT uFlags, CPoint point)
- {
- if(m_nBtnMouseOver < ENV_LEFTBAR_BUTTONS)
- {
- m_dwStatus |= INSSTATUS_NCLBTNDOWN;
- if(cLeftBarButtons[m_nBtnMouseOver] != ID_SEPARATOR)
- {
- PostMessage(WM_COMMAND, cLeftBarButtons[m_nBtnMouseOver]);
- UpdateNcButtonState();
- }
- }
- CModScrollView::OnNcLButtonDown(uFlags, point);
- }
- void CViewInstrument::OnNcLButtonUp(UINT uFlags, CPoint point)
- {
- if(m_dwStatus & INSSTATUS_NCLBTNDOWN)
- {
- m_dwStatus &= ~INSSTATUS_NCLBTNDOWN;
- UpdateNcButtonState();
- }
- CModScrollView::OnNcLButtonUp(uFlags, point);
- }
- void CViewInstrument::OnNcLButtonDblClk(UINT uFlags, CPoint point)
- {
- OnNcLButtonDown(uFlags, point);
- }
- LRESULT CViewInstrument::OnNcHitTest(CPoint point)
- {
- CRect rect;
- GetWindowRect(&rect);
- rect.bottom = rect.top + ENV_LEFTBAR_CY;
- if(rect.PtInRect(point))
- {
- return HTBORDER;
- }
- return CModScrollView::OnNcHitTest(point);
- }
- void CViewInstrument::OnMouseMove(UINT, CPoint pt)
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns == nullptr)
- return;
- bool splitCursor = false;
- if((m_nBtnMouseOver < ENV_LEFTBAR_BUTTONS) || (m_dwStatus & INSSTATUS_NCLBTNDOWN))
- {
- m_dwStatus &= ~INSSTATUS_NCLBTNDOWN;
- m_nBtnMouseOver = 0xFFFF;
- UpdateNcButtonState();
- CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
- if(pMainFrm)
- pMainFrm->SetHelpText(_T(""));
- }
- int nTick = ScreenToTick(pt.x);
- int nVal = Clamp(ScreenToValue(pt.y), ENVELOPE_MIN, ENVELOPE_MAX);
- if(nTick < 0)
- nTick = 0;
- UpdateIndicator(nTick, nVal);
- if((m_dwStatus & INSSTATUS_DRAGGING) && (m_nDragItem))
- {
- if(!m_mouseMoveModified)
- {
- PrepareUndo("Move Envelope Point");
- m_mouseMoveModified = true;
- }
- bool changed = false;
- if(pt.x >= m_rcClient.right - 2)
- nTick++;
- if(IsDragItemEnvPoint())
- {
- // Ctrl pressed -> move tail of envelope
- changed = EnvSetValue(m_nDragItem - 1, nTick, nVal, CMainFrame::GetInputHandler()->CtrlPressed());
- } else
- {
- int nPoint = ScreenToPoint(pt.x, pt.y);
- if (nPoint >= 0) switch(m_nDragItem)
- {
- case ENV_DRAGLOOPSTART:
- changed = EnvSetLoopStart(nPoint);
- splitCursor = true;
- break;
- case ENV_DRAGLOOPEND:
- changed = EnvSetLoopEnd(nPoint);
- splitCursor = true;
- break;
- case ENV_DRAGSUSTAINSTART:
- changed = EnvSetSustainStart(nPoint);
- splitCursor = true;
- break;
- case ENV_DRAGSUSTAINEND:
- changed = EnvSetSustainEnd(nPoint);
- splitCursor = true;
- break;
- }
- }
- if(changed)
- {
- if(pt.x <= 0)
- {
- UpdateScrollSize();
- OnScrollBy(CSize(pt.x - (int)m_zoom, 0), TRUE);
- }
- if(pt.x >= m_rcClient.right - 1)
- {
- UpdateScrollSize();
- OnScrollBy(CSize((int)m_zoom + pt.x - m_rcClient.right, 0), TRUE);
- }
- SetModified(InstrumentHint().Envelope(), true);
- UpdateWindow(); //rewbs: TODO - optimisation here so we don't redraw whole view.
- }
- } else
- {
- CRect rect;
- if(EnvGetSustain())
- {
- int nspace = m_rcClient.bottom / 4;
- rect.top = ValueToScreen(EnvGetValue(EnvGetSustainStart())) - nspace;
- rect.bottom = rect.top + nspace * 2;
- rect.right = PointToScreen(EnvGetSustainStart()) + 1;
- rect.left = rect.right - m_envPointSize * 2;
- if(rect.PtInRect(pt))
- {
- splitCursor = true; // ENV_DRAGSUSTAINSTART;
- } else
- {
- rect.top = ValueToScreen(EnvGetValue(EnvGetSustainEnd())) - nspace;
- rect.bottom = rect.top + nspace * 2;
- rect.left = PointToScreen(EnvGetSustainEnd()) - 1;
- rect.right = rect.left + m_envPointSize * 2;
- if(rect.PtInRect(pt))
- splitCursor = true; // ENV_DRAGSUSTAINEND;
- }
- }
- if(EnvGetLoop())
- {
- rect.top = m_rcClient.top;
- rect.bottom = m_rcClient.bottom;
- rect.right = PointToScreen(EnvGetLoopStart()) + 1;
- rect.left = rect.right - m_envPointSize * 2;
- if(rect.PtInRect(pt))
- {
- splitCursor = true; // ENV_DRAGLOOPSTART;
- } else
- {
- rect.left = PointToScreen(EnvGetLoopEnd()) - 1;
- rect.right = rect.left + m_envPointSize * 2;
- if(rect.PtInRect(pt))
- splitCursor = true; // ENV_DRAGLOOPEND;
- }
- }
- }
- // Update the mouse cursor
- if(splitCursor)
- {
- if(!(m_dwStatus & INSSTATUS_SPLITCURSOR))
- {
- m_dwStatus |= INSSTATUS_SPLITCURSOR;
- if(!(m_dwStatus & INSSTATUS_DRAGGING))
- SetCapture();
- SetCursor(CMainFrame::curVSplit);
- }
- } else
- {
- if(m_dwStatus & INSSTATUS_SPLITCURSOR)
- {
- m_dwStatus &= ~INSSTATUS_SPLITCURSOR;
- SetCursor(CMainFrame::curArrow);
- if(!(m_dwStatus & INSSTATUS_DRAGGING))
- ReleaseCapture();
- }
- }
- }
- void CViewInstrument::UpdateIndicator()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !m_nDragItem)
- return;
- uint32 point = DragItemToEnvPoint();
- if(point < pEnv->size())
- {
- UpdateIndicator(pEnv->at(point).tick, pEnv->at(point).value);
- }
- }
- void CViewInstrument::UpdateIndicator(int tick, int val)
- {
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns == nullptr)
- return;
- CString s;
- s.Format(TrackerSettings::Instance().cursorPositionInHex ? _T("Tick %X, [%s]") : _T("Tick %d, [%s]"), tick, EnvValueToString(tick, val).GetString());
- CModScrollView::UpdateIndicator(s);
- CMainFrame::GetMainFrame()->NotifyAccessibilityUpdate(*this);
- }
- CString CViewInstrument::EnvValueToString(int tick, int val) const
- {
- const InstrumentEnvelope *env = GetEnvelopePtr();
- const bool hasReleaseNode = env->nReleaseNode != ENV_RELEASE_NODE_UNSET;
- EnvelopeNode releaseNode;
- if(hasReleaseNode)
- {
- releaseNode = env->at(env->nReleaseNode);
- }
- CString s;
- if(!hasReleaseNode || tick <= releaseNode.tick + 1)
- {
- // ticks before release node (or no release node)
- const int displayVal = (m_nEnv != ENV_VOLUME && !(m_nEnv == ENV_PITCH && env->dwFlags[ENV_FILTER])) ? val - 32 : val;
- if(m_nEnv != ENV_PANNING)
- s.Format(_T("%d"), displayVal);
- else // panning envelope: display right/center/left chars
- s.Format(_T("%d %c"), std::abs(displayVal), displayVal > 0 ? _T('R') : (displayVal < 0 ? _T('L') : _T('C')));
- } else
- {
- // ticks after release node
- int displayVal = (val - releaseNode.value) * 2;
- displayVal = (m_nEnv != ENV_VOLUME) ? displayVal - 32 : displayVal;
- s.Format(_T("Rel%c%d"), displayVal > 0 ? _T('+') : _T('-'), std::abs(displayVal));
- }
- return s;
- }
- void CViewInstrument::OnLButtonDown(UINT, CPoint pt)
- {
- m_mouseMoveModified = false;
- if(!(m_dwStatus & INSSTATUS_DRAGGING))
- {
- CRect rect;
- // Look if dragging a point
- uint32 maxpoint = EnvGetLastPoint();
- uint32 oldDragItem = m_nDragItem;
- m_nDragItem = 0;
- const int hitboxSize = static_cast<int>((6 * m_nDPIx) / 96.0f);
- for(uint32 i = 0; i <= maxpoint; i++)
- {
- int x = PointToScreen(i);
- int y = ValueToScreen(EnvGetValue(i));
- rect.SetRect(x - hitboxSize, y - hitboxSize, x + hitboxSize + 1, y + hitboxSize + 1);
- if(rect.PtInRect(pt))
- {
- m_nDragItem = i + 1;
- break;
- }
- }
- if((!m_nDragItem) && (EnvGetSustain()))
- {
- int nspace = m_rcClient.bottom / 4;
- rect.top = ValueToScreen(EnvGetValue(EnvGetSustainStart())) - nspace;
- rect.bottom = rect.top + nspace * 2;
- rect.right = PointToScreen(EnvGetSustainStart()) + 1;
- rect.left = rect.right - m_envPointSize * 2;
- if(rect.PtInRect(pt))
- {
- m_nDragItem = ENV_DRAGSUSTAINSTART;
- } else
- {
- rect.top = ValueToScreen(EnvGetValue(EnvGetSustainEnd())) - nspace;
- rect.bottom = rect.top + nspace * 2;
- rect.left = PointToScreen(EnvGetSustainEnd()) - 1;
- rect.right = rect.left + m_envPointSize * 2;
- if(rect.PtInRect(pt))
- m_nDragItem = ENV_DRAGSUSTAINEND;
- }
- }
- if((!m_nDragItem) && (EnvGetLoop()))
- {
- rect.top = m_rcClient.top;
- rect.bottom = m_rcClient.bottom;
- rect.right = PointToScreen(EnvGetLoopStart()) + 1;
- rect.left = rect.right - m_envPointSize * 2;
- if(rect.PtInRect(pt))
- {
- m_nDragItem = ENV_DRAGLOOPSTART;
- } else
- {
- rect.left = PointToScreen(EnvGetLoopEnd()) - 1;
- rect.right = rect.left + m_envPointSize * 2;
- if(rect.PtInRect(pt))
- m_nDragItem = ENV_DRAGLOOPEND;
- }
- }
- if(m_nDragItem)
- {
- SetCapture();
- m_dwStatus |= INSSTATUS_DRAGGING;
- // refresh active node colour
- InvalidateRect(NULL, FALSE);
- } else
- {
- // Shift-Click: Insert envelope point here
- if(CMainFrame::GetInputHandler()->ShiftPressed())
- {
- if(InsertAtPoint(pt) == 0 && oldDragItem != 0)
- {
- InvalidateRect(NULL, FALSE);
- }
- } else if(oldDragItem)
- {
- InvalidateRect(NULL, FALSE);
- }
- }
- }
- }
- void CViewInstrument::OnLButtonUp(UINT, CPoint)
- {
- m_mouseMoveModified = false;
- if(m_dwStatus & INSSTATUS_SPLITCURSOR)
- {
- m_dwStatus &= ~INSSTATUS_SPLITCURSOR;
- SetCursor(CMainFrame::curArrow);
- }
- if(m_dwStatus & INSSTATUS_DRAGGING)
- {
- m_dwStatus &= ~INSSTATUS_DRAGGING;
- ReleaseCapture();
- }
- }
- void CViewInstrument::OnRButtonDown(UINT flags, CPoint pt)
- {
- const CModDoc *pModDoc = GetDocument();
- if(!pModDoc)
- return;
- const CSoundFile &sndFile = GetDocument()->GetSoundFile();
- if(m_dwStatus & INSSTATUS_DRAGGING)
- return;
- // Ctrl + Right-Click = Delete point
- if(flags & MK_CONTROL)
- {
- OnMButtonDown(flags, pt);
- return;
- }
- CMenu Menu;
- if((pModDoc) && (Menu.LoadMenu(IDR_ENVELOPES)))
- {
- CMenu *pSubMenu = Menu.GetSubMenu(0);
- if(pSubMenu != nullptr)
- {
- m_nDragItem = ScreenToPoint(pt.x, pt.y) + 1;
- const uint32 maxPoint = (sndFile.GetType() == MOD_TYPE_XM) ? 11 : 24;
- const uint32 lastpoint = EnvGetLastPoint();
- const bool forceRelease = !sndFile.GetModSpecifications().hasReleaseNode && (EnvGetReleaseNode() != ENV_RELEASE_NODE_UNSET);
- pSubMenu->EnableMenuItem(ID_ENVELOPE_INSERTPOINT, (lastpoint < maxPoint) ? MF_ENABLED : MF_GRAYED);
- pSubMenu->EnableMenuItem(ID_ENVELOPE_REMOVEPOINT, ((m_nDragItem) && (lastpoint > 0)) ? MF_ENABLED : MF_GRAYED);
- pSubMenu->EnableMenuItem(ID_ENVELOPE_CARRY, (sndFile.GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) ? MF_ENABLED : MF_GRAYED);
- pSubMenu->EnableMenuItem(ID_ENVELOPE_TOGGLERELEASENODE, ((sndFile.GetModSpecifications().hasReleaseNode && m_nEnv == ENV_VOLUME) || forceRelease) ? MF_ENABLED : MF_GRAYED);
- pSubMenu->CheckMenuItem(ID_ENVELOPE_SETLOOP, (EnvGetLoop()) ? MF_CHECKED : MF_UNCHECKED);
- pSubMenu->CheckMenuItem(ID_ENVELOPE_SUSTAIN, (EnvGetSustain()) ? MF_CHECKED : MF_UNCHECKED);
- pSubMenu->CheckMenuItem(ID_ENVELOPE_CARRY, (EnvGetCarry()) ? MF_CHECKED : MF_UNCHECKED);
- pSubMenu->CheckMenuItem(ID_ENVELOPE_TOGGLERELEASENODE, (EnvGetReleaseNode() == m_nDragItem - 1) ? MF_CHECKED : MF_UNCHECKED);
- m_ptMenu = pt;
- ClientToScreen(&pt);
- pSubMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);
- }
- }
- }
- void CViewInstrument::OnMButtonDown(UINT, CPoint pt)
- {
- // Middle mouse button: Remove envelope point
- int point = ScreenToPoint(pt.x, pt.y);
- if(point >= 0)
- {
- EnvRemovePoint(point);
- m_nDragItem = point + 1;
- }
- }
- void CViewInstrument::OnPrevInstrument()
- {
- SendCtrlMessage(CTRLMSG_INS_PREVINSTRUMENT);
- }
- void CViewInstrument::OnNextInstrument()
- {
- SendCtrlMessage(CTRLMSG_INS_NEXTINSTRUMENT);
- }
- void CViewInstrument::OnEditSampleMap()
- {
- SendCtrlMessage(CTRLMSG_INS_SAMPLEMAP);
- }
- void CViewInstrument::OnSelectVolumeEnv()
- {
- if(m_nEnv != ENV_VOLUME)
- SetCurrentInstrument(m_nInstrument, ENV_VOLUME);
- }
- void CViewInstrument::OnSelectPanningEnv()
- {
- if(m_nEnv != ENV_PANNING)
- SetCurrentInstrument(m_nInstrument, ENV_PANNING);
- }
- void CViewInstrument::OnSelectPitchEnv()
- {
- if(m_nEnv != ENV_PITCH)
- SetCurrentInstrument(m_nInstrument, ENV_PITCH);
- }
- void CViewInstrument::OnEnvLoopChanged()
- {
- CModDoc *pModDoc = GetDocument();
- PrepareUndo("Toggle Envelope Loop");
- if((pModDoc) && (EnvSetLoop(!EnvGetLoop())))
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(EnvGetLoop() && pEnv != nullptr && pEnv->nLoopEnd == 0)
- {
- // Enabled loop => set loop points if no loop has been specified yet.
- pEnv->nLoopStart = 0;
- pEnv->nLoopEnd = mpt::saturate_cast<decltype(pEnv->nLoopEnd)>(pEnv->size() - 1);
- }
- SetModified(InstrumentHint().Envelope(), true);
- }
- }
- void CViewInstrument::OnEnvSustainChanged()
- {
- CModDoc *pModDoc = GetDocument();
- PrepareUndo("Toggle Envelope Sustain");
- if((pModDoc) && (EnvSetSustain(!EnvGetSustain())))
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(EnvGetSustain() && pEnv != nullptr && pEnv->nSustainStart == pEnv->nSustainEnd && IsDragItemEnvPoint())
- {
- // Enabled sustain loop => set sustain loop points if no sustain loop has been specified yet.
- pEnv->nSustainStart = pEnv->nSustainEnd = mpt::saturate_cast<decltype(pEnv->nSustainEnd)>(m_nDragItem - 1);
- }
- SetModified(InstrumentHint().Envelope(), true);
- }
- }
- void CViewInstrument::OnEnvCarryChanged()
- {
- CModDoc *pModDoc = GetDocument();
- PrepareUndo("Toggle Envelope Carry");
- if((pModDoc) && (EnvSetCarry(!EnvGetCarry())))
- {
- SetModified(InstrumentHint().Envelope(), false);
- UpdateNcButtonState();
- }
- }
- void CViewInstrument::OnEnvToggleReleasNode()
- {
- if(IsDragItemEnvPoint())
- {
- PrepareUndo("Toggle Envelope Release Node");
- if(EnvToggleReleaseNode(m_nDragItem - 1))
- {
- SetModified(InstrumentHint().Envelope(), true);
- }
- }
- }
- void CViewInstrument::OnEnvVolChanged()
- {
- GetDocument()->GetInstrumentUndo().PrepareUndo(m_nInstrument, "Toggle Volume Envelope", ENV_VOLUME);
- if(EnvSetVolEnv(!EnvGetVolEnv()))
- {
- SetModified(InstrumentHint().Envelope(), false);
- UpdateNcButtonState();
- }
- }
- void CViewInstrument::OnEnvPanChanged()
- {
- GetDocument()->GetInstrumentUndo().PrepareUndo(m_nInstrument, "Toggle Panning Envelope", ENV_PANNING);
- if(EnvSetPanEnv(!EnvGetPanEnv()))
- {
- SetModified(InstrumentHint().Envelope(), false);
- UpdateNcButtonState();
- }
- }
- void CViewInstrument::OnEnvPitchChanged()
- {
- GetDocument()->GetInstrumentUndo().PrepareUndo(m_nInstrument, "Toggle Pitch Envelope", ENV_PITCH);
- if(EnvSetPitchEnv(!EnvGetPitchEnv()))
- {
- SetModified(InstrumentHint().Envelope(), false);
- UpdateNcButtonState();
- }
- }
- void CViewInstrument::OnEnvFilterChanged()
- {
- GetDocument()->GetInstrumentUndo().PrepareUndo(m_nInstrument, "Toggle Filter Envelope", ENV_PITCH);
- if(EnvSetFilterEnv(!EnvGetFilterEnv()))
- {
- SetModified(InstrumentHint().Envelope(), false);
- UpdateNcButtonState();
- }
- }
- void CViewInstrument::OnEnvToggleGrid()
- {
- m_bGrid = !m_bGrid;
- if(m_bGrid)
- m_bGridForceRedraw = true;
- CModDoc *pModDoc = GetDocument();
- if(pModDoc)
- pModDoc->UpdateAllViews(nullptr, InstrumentHint(m_nInstrument).Envelope());
- }
- void CViewInstrument::OnEnvRemovePoint()
- {
- if(m_nDragItem > 0)
- {
- EnvRemovePoint(m_nDragItem - 1);
- }
- }
- void CViewInstrument::OnEnvInsertPoint()
- {
- const int tick = ScreenToTick(m_ptMenu.x), value = ScreenToValue(m_ptMenu.y);
- if(!EnvInsertPoint(tick, value))
- {
- // Couldn't insert point, maybe because there's already a point at this tick
- // => Try next tick
- EnvInsertPoint(tick + 1, value);
- }
- }
- bool CViewInstrument::InsertAtPoint(CPoint pt)
- {
- auto item = EnvInsertPoint(ScreenToTick(pt.x), ScreenToValue(pt.y)); // returns point ID + 1 if successful, else 0.
- if(item > 0)
- {
- // Drag point if successful
- SetCapture();
- m_dwStatus |= INSSTATUS_DRAGGING;
- m_nDragItem = item;
- }
- return item > 0;
- }
- void CViewInstrument::OnEditCopy()
- {
- CModDoc *pModDoc = GetDocument();
- if(pModDoc)
- pModDoc->CopyEnvelope(m_nInstrument, m_nEnv);
- }
- void CViewInstrument::OnEditPaste()
- {
- CModDoc *pModDoc = GetDocument();
- PrepareUndo("Paste Envelope");
- if(pModDoc->PasteEnvelope(m_nInstrument, m_nEnv))
- {
- SetModified(InstrumentHint().Envelope(), true);
- } else
- {
- pModDoc->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- }
- }
- void CViewInstrument::PlayNote(ModCommand::NOTE note)
- {
- CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
- CModDoc *pModDoc = GetDocument();
- if(pModDoc == nullptr || pMainFrm == nullptr)
- {
- return;
- }
- if(note > 0 && note < 128)
- {
- if(m_nInstrument && !m_baPlayingNote[note])
- {
- CSoundFile &sndFile = pModDoc->GetSoundFile();
- ModInstrument *pIns = sndFile.Instruments[m_nInstrument];
- if((!pIns) || (!pIns->Keyboard[note - NOTE_MIN] && !pIns->nMixPlug))
- return;
- {
- if(pMainFrm->GetModPlaying() != pModDoc)
- {
- sndFile.m_SongFlags.set(SONG_PAUSED);
- sndFile.ResetChannels();
- if(!pMainFrm->PlayMod(pModDoc))
- return;
- }
- pModDoc->PlayNote(PlayNoteParam(note).Instrument(m_nInstrument).CheckNNA(m_baPlayingNote), &m_noteChannel);
- }
- CString noteName;
- if(ModCommand::IsNote(note))
- {
- noteName = mpt::ToCString(sndFile.GetNoteName(note, m_nInstrument));
- }
- pMainFrm->SetInfoText(noteName);
- }
- } else
- {
- pModDoc->PlayNote(PlayNoteParam(note).Instrument(m_nInstrument));
- }
- }
- // Drop files from Windows
- void CViewInstrument::OnDropFiles(HDROP hDropInfo)
- {
- const UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
- CMainFrame::GetMainFrame()->SetForegroundWindow();
- for(UINT f = 0; f < nFiles; f++)
- {
- UINT size = ::DragQueryFile(hDropInfo, f, nullptr, 0) + 1;
- std::vector<TCHAR> fileName(size, _T('\0'));
- if(::DragQueryFile(hDropInfo, f, fileName.data(), size))
- {
- const mpt::PathString file = mpt::PathString::FromNative(fileName.data());
- PrepareUndo("Replace Envelope");
- if(GetDocument()->LoadEnvelope(m_nInstrument, m_nEnv, file))
- {
- SetModified(InstrumentHint(m_nInstrument).Envelope(), true);
- } else
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- if(SendCtrlMessage(CTRLMSG_INS_OPENFILE, (LPARAM)&file) && f < nFiles - 1)
- {
- // Insert more instrument slots
- if(!SendCtrlMessage(CTRLMSG_INS_NEWINSTRUMENT))
- break;
- }
- }
- }
- }
- ::DragFinish(hDropInfo);
- }
- BOOL CViewInstrument::OnDragonDrop(BOOL doDrop, const DRAGONDROP *dropInfo)
- {
- CModDoc *modDoc = GetDocument();
- bool canDrop = false;
- if((!dropInfo) || (!modDoc))
- return FALSE;
- CSoundFile &sndFile = modDoc->GetSoundFile();
- switch(dropInfo->dropType)
- {
- case DRAGONDROP_INSTRUMENT:
- if(dropInfo->sndFile == &sndFile)
- {
- canDrop = ((dropInfo->dropItem)
- && (dropInfo->dropItem <= sndFile.m_nInstruments)
- && (dropInfo->sndFile == &sndFile));
- } else
- {
- canDrop = ((dropInfo->dropItem)
- && ((dropInfo->dropParam) || (dropInfo->sndFile)));
- }
- break;
- case DRAGONDROP_DLS:
- canDrop = ((dropInfo->dropItem < CTrackApp::gpDLSBanks.size())
- && (CTrackApp::gpDLSBanks[dropInfo->dropItem]));
- break;
- case DRAGONDROP_SOUNDFILE:
- case DRAGONDROP_MIDIINSTR:
- canDrop = !dropInfo->GetPath().empty();
- break;
- }
-
- const bool insertNew = CMainFrame::GetInputHandler()->ShiftPressed() && sndFile.GetNumInstruments() > 0;
- if(insertNew && !sndFile.CanAddMoreInstruments())
- canDrop = false;
- if(!canDrop || !doDrop)
- return canDrop;
- if(!sndFile.GetNumInstruments() && sndFile.GetModSpecifications().instrumentsMax > 0)
- SendCtrlMessage(CTRLMSG_INS_NEWINSTRUMENT);
- if(!m_nInstrument || m_nInstrument > sndFile.GetNumInstruments())
- return FALSE;
- // Do the drop
- bool modified = false;
- BeginWaitCursor();
- switch(dropInfo->dropType)
- {
- case DRAGONDROP_INSTRUMENT:
- if(dropInfo->sndFile == &sndFile)
- {
- SendCtrlMessage(CTRLMSG_SETCURRENTINSTRUMENT, dropInfo->dropItem);
- } else
- {
- if(insertNew && !SendCtrlMessage(CTRLMSG_INS_NEWINSTRUMENT))
- canDrop = false;
- else
- SendCtrlMessage(CTRLMSG_INS_SONGDROP, reinterpret_cast<LPARAM>(dropInfo));
- }
- break;
- case DRAGONDROP_MIDIINSTR:
- if(CDLSBank::IsDLSBank(dropInfo->GetPath()))
- {
- CDLSBank dlsbank;
- if(dlsbank.Open(dropInfo->GetPath()))
- {
- const DLSINSTRUMENT *pDlsIns;
- UINT nIns = 0, nRgn = 0xFF;
- // Drums
- if(dropInfo->dropItem & 0x80)
- {
- UINT key = dropInfo->dropItem & 0x7F;
- pDlsIns = dlsbank.FindInstrument(true, 0xFFFF, 0xFF, key, &nIns);
- if(pDlsIns)
- nRgn = dlsbank.GetRegionFromKey(nIns, key);
- } else
- // Melodic
- {
- pDlsIns = dlsbank.FindInstrument(false, 0xFFFF, dropInfo->dropItem, 60, &nIns);
- if(pDlsIns)
- nRgn = dlsbank.GetRegionFromKey(nIns, 60);
- }
- canDrop = false;
- if(pDlsIns)
- {
- if(!insertNew || SendCtrlMessage(CTRLMSG_INS_NEWINSTRUMENT))
- {
- CriticalSection cs;
- modDoc->GetInstrumentUndo().PrepareUndo(m_nInstrument, "Replace Instrument");
- canDrop = modified = dlsbank.ExtractInstrument(sndFile, m_nInstrument, nIns, nRgn);
- }
- }
- break;
- }
- }
- // Instrument file -> fall through
- [[fallthrough]];
- case DRAGONDROP_SOUNDFILE:
- if(!insertNew || SendCtrlMessage(CTRLMSG_INS_NEWINSTRUMENT))
- SendCtrlMessage(CTRLMSG_INS_OPENFILE, dropInfo->dropParam);
- break;
- case DRAGONDROP_DLS:
- {
- UINT nIns = dropInfo->dropParam & 0xFFFF;
- uint32 drumRgn = uint32_max;
- // Drums: (0x80000000) | (Region << 16) | (Instrument)
- if(dropInfo->dropParam & 0x80000000)
- drumRgn = (dropInfo->dropParam & 0x7FFF0000) >> 16;
- if(!insertNew || SendCtrlMessage(CTRLMSG_INS_NEWINSTRUMENT))
- {
- CriticalSection cs;
- modDoc->GetInstrumentUndo().PrepareUndo(m_nInstrument, "Replace Instrument");
- canDrop = modified = CTrackApp::gpDLSBanks[dropInfo->dropItem]->ExtractInstrument(sndFile, m_nInstrument, nIns, drumRgn);
- }
- }
- break;
- }
- if(modified)
- {
- SetModified(InstrumentHint().Info().Envelope().Names(), true);
- GetDocument()->UpdateAllViews(nullptr, SampleHint().Info().Names().Data(), this);
- }
- CMDIChildWnd *pMDIFrame = (CMDIChildWnd *)GetParentFrame();
- if(pMDIFrame)
- {
- pMDIFrame->MDIActivate();
- pMDIFrame->SetActiveView(this);
- SetFocus();
- }
- EndWaitCursor();
- return canDrop;
- }
- LRESULT CViewInstrument::OnMidiMsg(WPARAM midiDataParam, LPARAM)
- {
- const uint32 midiData = static_cast<uint32>(midiDataParam);
- CModDoc *modDoc = GetDocument();
- if(modDoc != nullptr)
- {
- modDoc->ProcessMIDI(midiData, m_nInstrument, modDoc->GetSoundFile().GetInstrumentPlugin(m_nInstrument), kCtxViewInstruments);
- MIDIEvents::EventType event = MIDIEvents::GetTypeFromEvent(midiData);
- uint8 midiByte1 = MIDIEvents::GetDataByte1FromEvent(midiData);
- if(event == MIDIEvents::evNoteOn)
- {
- CMainFrame::GetMainFrame()->SetInfoText(mpt::ToCString(modDoc->GetSoundFile().GetNoteName(midiByte1 + NOTE_MIN, m_nInstrument)));
- }
- return 1;
- }
- return 0;
- }
- BOOL CViewInstrument::PreTranslateMessage(MSG *pMsg)
- {
- if(pMsg)
- {
- //We handle keypresses before Windows has a chance to handle them (for alt etc..)
- if((pMsg->message == WM_SYSKEYUP) || (pMsg->message == WM_KEYUP) ||
- (pMsg->message == WM_SYSKEYDOWN) || (pMsg->message == WM_KEYDOWN))
- {
- CInputHandler *ih = CMainFrame::GetInputHandler();
- //Translate message manually
- UINT nChar = static_cast<UINT>(pMsg->wParam);
- UINT nRepCnt = LOWORD(pMsg->lParam);
- UINT nFlags = HIWORD(pMsg->lParam);
- KeyEventType kT = ih->GetKeyEventType(nFlags);
- InputTargetContext ctx = (InputTargetContext)(kCtxViewInstruments);
- if(ih->KeyEvent(ctx, nChar, nRepCnt, nFlags, kT) != kcNull)
- return true; // Mapped to a command, no need to pass message on.
- // Handle Application (menu) key
- if(pMsg->message == WM_KEYDOWN && nChar == VK_APPS)
- {
- CPoint pt(0, 0);
- if(m_nDragItem > 0)
- {
- uint32 point = DragItemToEnvPoint();
- pt.SetPoint(PointToScreen(point), ValueToScreen(EnvGetValue(point)));
- }
- OnRButtonDown(0, pt);
- }
- }
- }
- return CModScrollView::PreTranslateMessage(pMsg);
- }
- LRESULT CViewInstrument::OnCustomKeyMsg(WPARAM wParam, LPARAM)
- {
- CModDoc *pModDoc = GetDocument();
- if(!pModDoc)
- return kcNull;
- CSoundFile &sndFile = pModDoc->GetSoundFile();
- switch(wParam)
- {
- case kcPrevInstrument: OnPrevInstrument(); return wParam;
- case kcNextInstrument: OnNextInstrument(); return wParam;
- case kcEditCopy: OnEditCopy(); return wParam;
- case kcEditPaste: OnEditPaste(); return wParam;
- case kcEditUndo: OnEditUndo(); return wParam;
- case kcEditRedo: OnEditRedo(); return wParam;
- case kcNoteOff: PlayNote(NOTE_KEYOFF); return wParam;
- case kcNoteCut: PlayNote(NOTE_NOTECUT); return wParam;
- case kcInstrumentLoad: SendCtrlMessage(IDC_INSTRUMENT_OPEN); return wParam;
- case kcInstrumentSave: SendCtrlMessage(IDC_INSTRUMENT_SAVEAS); return wParam;
- case kcInstrumentNew: SendCtrlMessage(IDC_INSTRUMENT_NEW); return wParam;
- // envelope editor
- case kcInstrumentEnvelopeLoad: OnEnvLoad(); return wParam;
- case kcInstrumentEnvelopeSave: OnEnvSave(); return wParam;
- case kcInstrumentEnvelopeZoomIn: OnEnvZoomIn(); return wParam;
- case kcInstrumentEnvelopeZoomOut: OnEnvZoomOut(); return wParam;
- case kcInstrumentEnvelopeScale: OnEnvelopeScalePoints(); return wParam;
- case kcInstrumentEnvelopeSwitchToVolume: OnSelectVolumeEnv(); return wParam;
- case kcInstrumentEnvelopeSwitchToPanning: OnSelectPanningEnv(); return wParam;
- case kcInstrumentEnvelopeSwitchToPitch: OnSelectPitchEnv(); return wParam;
- case kcInstrumentEnvelopeToggleVolume: OnEnvVolChanged(); return wParam;
- case kcInstrumentEnvelopeTogglePanning: OnEnvPanChanged(); return wParam;
- case kcInstrumentEnvelopeTogglePitch: OnEnvPitchChanged(); return wParam;
- case kcInstrumentEnvelopeToggleFilter: OnEnvFilterChanged(); return wParam;
- case kcInstrumentEnvelopeToggleLoop: OnEnvLoopChanged(); return wParam;
- case kcInstrumentEnvelopeSelectLoopStart: EnvKbdSelectPoint(ENV_DRAGLOOPSTART); return wParam;
- case kcInstrumentEnvelopeSelectLoopEnd: EnvKbdSelectPoint(ENV_DRAGLOOPEND); return wParam;
- case kcInstrumentEnvelopeToggleSustain: OnEnvSustainChanged(); return wParam;
- case kcInstrumentEnvelopeSelectSustainStart: EnvKbdSelectPoint(ENV_DRAGSUSTAINSTART); return wParam;
- case kcInstrumentEnvelopeSelectSustainEnd: EnvKbdSelectPoint(ENV_DRAGSUSTAINEND); return wParam;
- case kcInstrumentEnvelopeToggleCarry: OnEnvCarryChanged(); return wParam;
- case kcInstrumentEnvelopePointPrev: EnvKbdSelectPoint(ENV_DRAGPREVIOUS); return wParam;
- case kcInstrumentEnvelopePointNext: EnvKbdSelectPoint(ENV_DRAGNEXT); return wParam;
- case kcInstrumentEnvelopePointMoveLeft: EnvKbdMovePointLeft(1); return wParam;
- case kcInstrumentEnvelopePointMoveRight: EnvKbdMovePointRight(1); return wParam;
- case kcInstrumentEnvelopePointMoveLeftCoarse: EnvKbdMovePointLeft(sndFile.m_PlayState.m_nCurrentRowsPerBeat * sndFile.m_PlayState.m_nMusicSpeed); return wParam;
- case kcInstrumentEnvelopePointMoveRightCoarse: EnvKbdMovePointRight(sndFile.m_PlayState.m_nCurrentRowsPerBeat * sndFile.m_PlayState.m_nMusicSpeed); return wParam;
- case kcInstrumentEnvelopePointMoveUp: EnvKbdMovePointVertical(1); return wParam;
- case kcInstrumentEnvelopePointMoveDown: EnvKbdMovePointVertical(-1); return wParam;
- case kcInstrumentEnvelopePointMoveUp8: EnvKbdMovePointVertical(8); return wParam;
- case kcInstrumentEnvelopePointMoveDown8: EnvKbdMovePointVertical(-8); return wParam;
- case kcInstrumentEnvelopePointInsert: EnvKbdInsertPoint(); return wParam;
- case kcInstrumentEnvelopePointRemove: EnvKbdRemovePoint(); return wParam;
- case kcInstrumentEnvelopeSetLoopStart: EnvKbdSetLoopStart(); return wParam;
- case kcInstrumentEnvelopeSetLoopEnd: EnvKbdSetLoopEnd(); return wParam;
- case kcInstrumentEnvelopeSetSustainLoopStart: EnvKbdSetSustainStart(); return wParam;
- case kcInstrumentEnvelopeSetSustainLoopEnd: EnvKbdSetSustainEnd(); return wParam;
- case kcInstrumentEnvelopeToggleReleaseNode: EnvKbdToggleReleaseNode(); return wParam;
- }
- if(wParam >= kcInstrumentStartNotes && wParam <= kcInstrumentEndNotes)
- {
- PlayNote(pModDoc->GetNoteWithBaseOctave(static_cast<int>(wParam - kcInstrumentStartNotes), m_nInstrument));
- return wParam;
- }
- if(wParam >= kcInstrumentStartNoteStops && wParam <= kcInstrumentEndNoteStops)
- {
- ModCommand::NOTE note = pModDoc->GetNoteWithBaseOctave(static_cast<int>(wParam - kcInstrumentStartNoteStops), m_nInstrument);
- if(ModCommand::IsNote(note))
- {
- m_baPlayingNote[note] = false;
- pModDoc->NoteOff(note, false, m_nInstrument, m_noteChannel[note - NOTE_MIN]);
- }
- return wParam;
- }
- return kcNull;
- }
- void CViewInstrument::OnEnvelopeScalePoints()
- {
- CModDoc *pModDoc = GetDocument();
- if(pModDoc == nullptr)
- return;
- const CSoundFile &sndFile = pModDoc->GetSoundFile();
- if(m_nInstrument >= 1
- && m_nInstrument <= sndFile.GetNumInstruments()
- && sndFile.Instruments[m_nInstrument])
- {
- // "Center" y value of the envelope. For panning and pitch, this is 32, for volume and filter it is 0 (minimum).
- int nOffset = ((m_nEnv != ENV_VOLUME) && !GetEnvelopePtr()->dwFlags[ENV_FILTER]) ? 32 : 0;
- CScaleEnvPointsDlg dlg(this, *GetEnvelopePtr(), nOffset);
- if(dlg.DoModal() == IDOK)
- {
- PrepareUndo("Scale Envelope");
- dlg.Apply();
- SetModified(InstrumentHint().Envelope(), true);
- }
- }
- }
- void CViewInstrument::EnvSetZoom(float newZoom)
- {
- m_zoom = Clamp(newZoom, ENV_MIN_ZOOM, ENV_MAX_ZOOM);
- InvalidateRect(NULL, FALSE);
- UpdateScrollSize();
- UpdateNcButtonState();
- }
- ////////////////////////////////////////
- // Envelope Editor - Keyboard actions
- void CViewInstrument::EnvKbdSelectPoint(DragPoints point)
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr)
- return;
- switch(point)
- {
- case ENV_DRAGLOOPSTART:
- case ENV_DRAGLOOPEND:
- if(!pEnv->dwFlags[ENV_LOOP])
- return;
- m_nDragItem = point;
- break;
- case ENV_DRAGSUSTAINSTART:
- case ENV_DRAGSUSTAINEND:
- if(!pEnv->dwFlags[ENV_SUSTAIN])
- return;
- m_nDragItem = point;
- break;
- case ENV_DRAGPREVIOUS:
- if(m_nDragItem <= 1 || m_nDragItem > pEnv->size())
- m_nDragItem = pEnv->size();
- else
- m_nDragItem--;
- break;
- case ENV_DRAGNEXT:
- if(m_nDragItem >= pEnv->size())
- m_nDragItem = 1;
- else
- m_nDragItem++;
- break;
- }
- UpdateIndicator();
- InvalidateRect(NULL, FALSE);
- }
- void CViewInstrument::EnvKbdMovePointLeft(int stepsize)
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr)
- return;
- const MODTYPE modType = GetDocument()->GetModType();
- // Move loop points?
- PrepareUndo("Move Envelope Point");
- if(m_nDragItem == ENV_DRAGSUSTAINSTART)
- {
- if(pEnv->nSustainStart <= 0)
- return;
- pEnv->nSustainStart--;
- if(modType == MOD_TYPE_XM)
- pEnv->nSustainEnd = pEnv->nSustainStart;
- } else if(m_nDragItem == ENV_DRAGSUSTAINEND)
- {
- if(pEnv->nSustainEnd <= 0)
- return;
- if(pEnv->nSustainEnd <= pEnv->nSustainStart)
- pEnv->nSustainStart--;
- pEnv->nSustainEnd--;
- } else if(m_nDragItem == ENV_DRAGLOOPSTART)
- {
- if(pEnv->nLoopStart <= 0)
- return;
- pEnv->nLoopStart--;
- } else if(m_nDragItem == ENV_DRAGLOOPEND)
- {
- if(pEnv->nLoopEnd <= 0)
- return;
- if(pEnv->nLoopEnd <= pEnv->nLoopStart)
- pEnv->nLoopStart--;
- pEnv->nLoopEnd--;
- } else
- {
- // Move envelope node
- if(!IsDragItemEnvPoint() || m_nDragItem <= 1)
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- return;
- }
- if(!EnvSetValue(m_nDragItem - 1, pEnv->at(m_nDragItem - 1).tick - stepsize))
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- return;
- }
- }
- UpdateIndicator();
- SetModified(InstrumentHint().Envelope(), true);
- }
- void CViewInstrument::EnvKbdMovePointRight(int stepsize)
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr)
- return;
- const MODTYPE modType = GetDocument()->GetModType();
- // Move loop points?
- PrepareUndo("Move Envelope Point");
- if(m_nDragItem == ENV_DRAGSUSTAINSTART)
- {
- if(pEnv->nSustainStart >= pEnv->size() - 1)
- return;
- if(pEnv->nSustainStart >= pEnv->nSustainEnd)
- pEnv->nSustainEnd++;
- pEnv->nSustainStart++;
- } else if(m_nDragItem == ENV_DRAGSUSTAINEND)
- {
- if(pEnv->nSustainEnd >= pEnv->size() - 1)
- return;
- pEnv->nSustainEnd++;
- if(modType == MOD_TYPE_XM)
- pEnv->nSustainStart = pEnv->nSustainEnd;
- } else if(m_nDragItem == ENV_DRAGLOOPSTART)
- {
- if(pEnv->nLoopStart >= pEnv->size() - 1)
- return;
- if(pEnv->nLoopStart >= pEnv->nLoopEnd)
- pEnv->nLoopEnd++;
- pEnv->nLoopStart++;
- } else if(m_nDragItem == ENV_DRAGLOOPEND)
- {
- if(pEnv->nLoopEnd >= pEnv->size() - 1)
- return;
- pEnv->nLoopEnd++;
- } else
- {
- // Move envelope node
- if(!IsDragItemEnvPoint() || m_nDragItem <= 1)
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- return;
- }
- if(!EnvSetValue(m_nDragItem - 1, pEnv->at(m_nDragItem - 1).tick + stepsize))
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- return;
- }
- }
- UpdateIndicator();
- SetModified(InstrumentHint().Envelope(), true);
- }
- void CViewInstrument::EnvKbdMovePointVertical(int stepsize)
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !IsDragItemEnvPoint())
- return;
- int val = pEnv->at(m_nDragItem - 1).value + stepsize;
- PrepareUndo("Move Envelope Point");
- if(EnvSetValue(m_nDragItem - 1, int32_min, val, false))
- {
- UpdateIndicator();
- SetModified(InstrumentHint().Envelope(), true);
- } else
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- }
- }
- void CViewInstrument::EnvKbdInsertPoint()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr)
- return;
- if(!IsDragItemEnvPoint())
- m_nDragItem = pEnv->size();
- EnvelopeNode::tick_t newTick = 10;
- EnvelopeNode::value_t newVal = m_nEnv == ENV_VOLUME ? ENVELOPE_MAX : ENVELOPE_MID;
- if(m_nDragItem < pEnv->size() && (pEnv->at(m_nDragItem).tick - pEnv->at(m_nDragItem - 1).tick > 1))
- {
- // If some other point than the last is selected: interpolate between this and next point (if there's room between them)
- newTick = (pEnv->at(m_nDragItem - 1).tick + pEnv->at(m_nDragItem).tick) / 2;
- newVal = (pEnv->at(m_nDragItem - 1).value + pEnv->at(m_nDragItem).value) / 2;
- } else if(!pEnv->empty())
- {
- // Last point is selected: add point after last point
- newTick = pEnv->back().tick + 4;
- newVal = pEnv->back().value;
- }
- auto newPoint = EnvInsertPoint(newTick, newVal);
- if(newPoint > 0)
- m_nDragItem = newPoint;
- UpdateIndicator();
- }
- void CViewInstrument::EnvKbdRemovePoint()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !IsDragItemEnvPoint() || pEnv->empty())
- return;
- if(m_nDragItem > pEnv->size())
- m_nDragItem = pEnv->size();
- EnvRemovePoint(m_nDragItem - 1);
- UpdateIndicator();
- }
- void CViewInstrument::EnvKbdSetLoopStart()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !IsDragItemEnvPoint())
- return;
- PrepareUndo("Set Envelope Loop Start");
- if(!EnvGetLoop())
- EnvSetLoopStart(0);
- EnvSetLoopStart(m_nDragItem - 1);
- SetModified(InstrumentHint(m_nInstrument).Envelope(), true);
- }
- void CViewInstrument::EnvKbdSetLoopEnd()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !IsDragItemEnvPoint())
- return;
- PrepareUndo("Set Envelope Loop End");
- if(!EnvGetLoop())
- {
- EnvSetLoop(true);
- EnvSetLoopStart(0);
- }
- EnvSetLoopEnd(m_nDragItem - 1);
- SetModified(InstrumentHint(m_nInstrument).Envelope(), true);
- }
- void CViewInstrument::EnvKbdSetSustainStart()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !IsDragItemEnvPoint())
- return;
- PrepareUndo("Set Envelope Sustain Start");
- if(!EnvGetSustain())
- EnvSetSustain(true);
- EnvSetSustainStart(m_nDragItem - 1);
- SetModified(InstrumentHint(m_nInstrument).Envelope(), true);
- }
- void CViewInstrument::EnvKbdSetSustainEnd()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !IsDragItemEnvPoint())
- return;
- PrepareUndo("Set Envelope Sustain End");
- if(!EnvGetSustain())
- {
- EnvSetSustain(true);
- EnvSetSustainStart(0);
- }
- EnvSetSustainEnd(m_nDragItem - 1);
- SetModified(InstrumentHint(m_nInstrument).Envelope(), true);
- }
- void CViewInstrument::EnvKbdToggleReleaseNode()
- {
- InstrumentEnvelope *pEnv = GetEnvelopePtr();
- if(pEnv == nullptr || !IsDragItemEnvPoint())
- return;
- PrepareUndo("Toggle Release Node");
- if(EnvToggleReleaseNode(m_nDragItem - 1))
- {
- UpdateIndicator();
- SetModified(InstrumentHint().Envelope(), true);
- } else
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- }
- }
- // Get a pointer to the currently active instrument.
- ModInstrument *CViewInstrument::GetInstrumentPtr() const
- {
- CModDoc *pModDoc = GetDocument();
- if(pModDoc == nullptr)
- return nullptr;
- return pModDoc->GetSoundFile().Instruments[m_nInstrument];
- }
- // Get a pointer to the currently selected envelope.
- // This function also implicitely validates the moddoc and soundfile pointers.
- InstrumentEnvelope *CViewInstrument::GetEnvelopePtr() const
- {
- // First do some standard checks...
- ModInstrument *pIns = GetInstrumentPtr();
- if(pIns == nullptr)
- return nullptr;
- return &pIns->GetEnvelope(m_nEnv);
- }
- bool CViewInstrument::CanMovePoint(uint32 envPoint, int step)
- {
- const InstrumentEnvelope *env = GetEnvelopePtr();
- if(env == nullptr)
- return false;
- // Can't move first point
- if(envPoint == 0)
- {
- return false;
- }
- // Can't move left of previous point
- if((step < 0) && (env->at(envPoint).tick - env->at(envPoint - 1).tick <= -step))
- {
- return false;
- }
- // Can't move right of next point
- if((step > 0) && (envPoint < env->size() - 1) && (env->at(envPoint + 1).tick - env->at(envPoint).tick <= step))
- {
- return false;
- }
- return true;
- }
- BOOL CViewInstrument::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
- {
- // Ctrl + mouse wheel: envelope zoom.
- if(nFlags == MK_CONTROL)
- {
- // Speed up zoom scrolling by some factor (might need some tuning).
- const float speedUpFactor = std::max(1.0f, m_zoom * 7.0f / ENV_MAX_ZOOM);
- EnvSetZoom(m_zoom + speedUpFactor * (zDelta / WHEEL_DELTA));
- }
- return CModScrollView::OnMouseWheel(nFlags, zDelta, pt);
- }
- void CViewInstrument::OnXButtonUp(UINT nFlags, UINT nButton, CPoint point)
- {
- if(nButton == XBUTTON1)
- OnPrevInstrument();
- else if(nButton == XBUTTON2)
- OnNextInstrument();
- CModScrollView::OnXButtonUp(nFlags, nButton, point);
- }
- void CViewInstrument::OnEnvLoad()
- {
- if(GetInstrumentPtr() == nullptr)
- return;
- FileDialog dlg = OpenFileDialog()
- .DefaultExtension("envelope")
- .ExtensionFilter("Instrument Envelopes (*.envelope)|*.envelope||")
- .WorkingDirectory(TrackerSettings::Instance().PathInstruments.GetWorkingDir());
- if(!dlg.Show(this)) return;
- TrackerSettings::Instance().PathInstruments.SetWorkingDir(dlg.GetWorkingDirectory());
- PrepareUndo("Replace Envelope");
- if(GetDocument()->LoadEnvelope(m_nInstrument, m_nEnv, dlg.GetFirstFile()))
- {
- SetModified(InstrumentHint(m_nInstrument).Envelope(), true);
- } else
- {
- GetDocument()->GetInstrumentUndo().RemoveLastUndoStep(m_nInstrument);
- }
- }
- void CViewInstrument::OnEnvSave()
- {
- const InstrumentEnvelope *env = GetEnvelopePtr();
- if(env == nullptr || env->empty())
- {
- MessageBeep(MB_ICONWARNING);
- return;
- }
- FileDialog dlg = SaveFileDialog()
- .DefaultExtension("envelope")
- .ExtensionFilter("Instrument Envelopes (*.envelope)|*.envelope||")
- .WorkingDirectory(TrackerSettings::Instance().PathInstruments.GetWorkingDir());
- if(!dlg.Show(this)) return;
- TrackerSettings::Instance().PathInstruments.SetWorkingDir(dlg.GetWorkingDirectory());
- if(!GetDocument()->SaveEnvelope(m_nInstrument, m_nEnv, dlg.GetFirstFile()))
- {
- Reporting::Error(MPT_CFORMAT("Unable to save file {}")(dlg.GetFirstFile()), _T("OpenMPT"), this);
- }
- }
- void CViewInstrument::OnUpdateUndo(CCmdUI *pCmdUI)
- {
- CModDoc *pModDoc = GetDocument();
- if((pCmdUI) && (pModDoc))
- {
- pCmdUI->Enable(pModDoc->GetInstrumentUndo().CanUndo(m_nInstrument));
- pCmdUI->SetText(CMainFrame::GetInputHandler()->GetKeyTextFromCommand(kcEditUndo, _T("Undo ") + mpt::ToCString(pModDoc->GetSoundFile().GetCharsetInternal(), pModDoc->GetInstrumentUndo().GetUndoName(m_nInstrument))));
- }
- }
- void CViewInstrument::OnUpdateRedo(CCmdUI *pCmdUI)
- {
- CModDoc *pModDoc = GetDocument();
- if((pCmdUI) && (pModDoc))
- {
- pCmdUI->Enable(pModDoc->GetInstrumentUndo().CanRedo(m_nInstrument));
- pCmdUI->SetText(CMainFrame::GetInputHandler()->GetKeyTextFromCommand(kcEditRedo, _T("Redo ") + mpt::ToCString(pModDoc->GetSoundFile().GetCharsetInternal(), pModDoc->GetInstrumentUndo().GetRedoName(m_nInstrument))));
- }
- }
- void CViewInstrument::OnEditUndo()
- {
- CModDoc *pModDoc = GetDocument();
- if(pModDoc == nullptr)
- return;
- if(pModDoc->GetInstrumentUndo().Undo(m_nInstrument))
- {
- SetModified(InstrumentHint().Info().Envelope().Names(), true);
- }
- }
- void CViewInstrument::OnEditRedo()
- {
- CModDoc *pModDoc = GetDocument();
- if(pModDoc == nullptr)
- return;
- if(pModDoc->GetInstrumentUndo().Redo(m_nInstrument))
- {
- SetModified(InstrumentHint().Info().Envelope().Names(), true);
- }
- }
- INT_PTR CViewInstrument::OnToolHitTest(CPoint point, TOOLINFO *pTI) const
- {
- CRect ncRect;
- ClientToScreen(&point);
- const auto ncButton = GetNcButtonAtPoint(point, &ncRect);
- if(ncButton == uint32_max)
- return CModScrollView::OnToolHitTest(point, pTI);
-
- auto buttonID = cLeftBarButtons[ncButton];
- ScreenToClient(&ncRect);
- pTI->hwnd = m_hWnd;
- pTI->uId = buttonID;
- pTI->rect = ncRect;
- CString text = LoadResourceString(buttonID);
- CommandID cmd = kcNull;
- switch(buttonID)
- {
- case ID_ENVSEL_VOLUME: cmd = kcInstrumentEnvelopeSwitchToVolume; break;
- case ID_ENVSEL_PANNING: cmd = kcInstrumentEnvelopeSwitchToPanning; break;
- case ID_ENVSEL_PITCH: cmd = kcInstrumentEnvelopeSwitchToPitch; break;
- case ID_ENVELOPE_VOLUME: cmd = kcInstrumentEnvelopeToggleVolume; break;
- case ID_ENVELOPE_PANNING: cmd = kcInstrumentEnvelopeTogglePanning; break;
- case ID_ENVELOPE_PITCH: cmd = kcInstrumentEnvelopeTogglePitch; break;
- case ID_ENVELOPE_FILTER: cmd = kcInstrumentEnvelopeToggleFilter; break;
- case ID_ENVELOPE_SETLOOP: cmd = kcInstrumentEnvelopeToggleLoop; break;
- case ID_ENVELOPE_SUSTAIN: cmd = kcInstrumentEnvelopeToggleSustain; break;
- case ID_ENVELOPE_CARRY: cmd = kcInstrumentEnvelopeToggleCarry; break;
- case ID_INSTRUMENT_SAMPLEMAP: cmd = kcInsNoteMapEditSampleMap; break;
- case ID_ENVELOPE_ZOOM_IN: cmd = kcInstrumentEnvelopeZoomIn; break;
- case ID_ENVELOPE_ZOOM_OUT: cmd = kcInstrumentEnvelopeZoomOut; break;
- case ID_ENVELOPE_LOAD: cmd = kcInstrumentEnvelopeLoad; break;
- case ID_ENVELOPE_SAVE: cmd = kcInstrumentEnvelopeSave; break;
- }
- if(cmd != kcNull)
- {
- auto keyText = CMainFrame::GetInputHandler()->m_activeCommandSet->GetKeyTextFromCommand(cmd, 0);
- if(!keyText.IsEmpty())
- text += MPT_CFORMAT(" ({})")(keyText);
- }
- // MFC will free() the text
- auto size = text.GetLength() + 1;
- TCHAR *textP = static_cast<TCHAR *>(calloc(size, sizeof(TCHAR)));
- std::copy(text.GetString(), text.GetString() + size, textP);
- pTI->lpszText = textP;
- return buttonID;
- }
- // Accessible description for screen readers
- HRESULT CViewInstrument::get_accName(VARIANT varChild, BSTR *pszName)
- {
- const InstrumentEnvelope *env = GetEnvelopePtr();
- if(env == nullptr)
- return CModScrollView::get_accName(varChild, pszName);
- const TCHAR *typeStr = _T("");
- switch(m_nEnv)
- {
- case ENV_VOLUME: typeStr = _T("Volume"); break;
- case ENV_PANNING: typeStr = _T("Panning"); break;
- case ENV_PITCH: typeStr = env->dwFlags[ENV_FILTER] ? _T("Filter") : _T("Pitch"); break;
- }
- CString str;
- if(env->empty() || m_nDragItem == 0)
- {
- str = typeStr;
- if(env->empty())
- str += _T(" envelope has no points");
- else
- str += MPT_CFORMAT(" envelope, {} point{}")(env->size(), env->size() == 1 ? CString(_T("")) : CString(_T("s")));
- } else
- {
- bool isEnvPoint = false;
- auto point = DragItemToEnvPoint();
- auto tick = EnvGetTick(point);
- switch(m_nDragItem)
- {
- case ENV_DRAGLOOPSTART: str = _T("Loop start"); break;
- case ENV_DRAGLOOPEND: str = _T("Loop end"); break;
- case ENV_DRAGSUSTAINSTART: str = _T("Sustain loop start"); break;
- case ENV_DRAGSUSTAINEND: str = _T("Sustain loop end"); break;
- default: isEnvPoint = true;
- }
- if(!isEnvPoint)
- {
- str += MPT_CFORMAT(" at point {}, tick {}")(point + 1, tick);
- } else
- {
- str = MPT_CFORMAT("Point {}, tick {}, {} {}")(point + 1, tick, CString(typeStr), EnvValueToString(EnvGetTick(point), EnvGetValue(point)));
- if(env->dwFlags[ENV_LOOP])
- {
- if(point == env->nLoopStart)
- str += _T(", loop start");
- if(point == env->nLoopEnd)
- str += _T(", loop end");
- }
- if(env->dwFlags[ENV_SUSTAIN])
- {
- if(point == env->nLoopStart)
- str += _T(", sustain loop start");
- if(point == env->nLoopEnd)
- str += _T(", sustain loop end");
- }
- if(env->nReleaseNode == point)
- str += _T(", release node");
- }
- }
- *pszName = str.AllocSysString();
- return S_OK;
- }
- OPENMPT_NAMESPACE_END
|