I use LMMS (to create songs/music) and it save the document in xml (.mmp).
In purebasic, I have created a little tool, to change some attributs of notes : len, pos, vol, note (key) and pan.
Thanks to the xml example in the doc, it's ok to loadxml(), get the note and its attributs, and change the attributs (len, pos, vol, note, pan).
But I don't know how to save the changes, with exactly the same xml node like the original file, but with the attributs of notes changed.
Do you know How I can save with my changes ?
here is a simple example of file created with LMMS :
Code: Select all
<?xml version="1.0"?>
<!DOCTYPE lmms-project>
<lmms-project creatorversion="1.2.2" creator="LMMS" version="1.0" type="song">
<head bpm="60" mastervol="100" masterpitch="0" timesig_denominator="4" timesig_numerator="4"/>
<song>
<trackcontainer x="5" visible="1" width="600" minimized="0" type="song" maximized="0" y="5" height="300">
<track muted="0" name="Beat/Bassline 0" solo="0" type="1">
<bbtrack>
<trackcontainer x="610" visible="0" width="700" minimized="0" type="bbtrackcontainer" maximized="0" y="5" height="400">
<track muted="0" name="Kicker" solo="0" type="0">
<instrumenttrack usemasterpitch="1" pan="0" fxch="0" basenote="57" pitch="0" vol="100" pitchrange="1">
<instrument name="kicker">
<kicker endfreq="40" dist="0.8" click="0.4" decay_syncmode="0" gain="1" decay_numerator="4" decay_denominator="4" endnote="0" version="1" startfreq="150" decay="440" env="0.163" slope="0.06" distend="0.8" noise="0" startnote="1"/>
</instrument>
<eldata fcut="14000" ftype="0" fres="0.5" fwet="0">
<elvol lspd_denominator="4" pdel="0" sustain="0.5" hold="0.5" x100="0" dec="0.5" lpdel="0" latt="0" lspd_numerator="4" lspd_syncmode="0" lamt="0" lshp="0" att="0" ctlenvamt="0" rel="0.1" amt="0" userwavefile="" lspd="0.1"/>
<elcut lspd_denominator="4" pdel="0" sustain="0.5" hold="0.5" x100="0" dec="0.5" lpdel="0" latt="0" lspd_numerator="4" lspd_syncmode="0" lamt="0" lshp="0" att="0" ctlenvamt="0" rel="0.1" amt="0" userwavefile="" lspd="0.1"/>
<elres lspd_denominator="4" pdel="0" sustain="0.5" hold="0.5" x100="0" dec="0.5" lpdel="0" latt="0" lspd_numerator="4" lspd_syncmode="0" lamt="0" lshp="0" att="0" ctlenvamt="0" rel="0.1" amt="0" userwavefile="" lspd="0.1"/>
</eldata>
<chordcreator chordrange="1" chord-enabled="0" chord="0"/>
<arpeggiator arpcycle="0" arptime_numerator="4" arptime_syncmode="0" arpskip="0" arpgate="100" arptime="100" arp-enabled="0" arptime_denominator="4" arp="0" arprange="1" arpmiss="0" arpdir="0" arpmode="0"/>
<midiport fixedoutputnote="-1" writable="0" fixedoutputvelocity="-1" outputprogram="1" outputchannel="1" outputcontroller="0" readable="0" inputchannel="0" basevelocity="63" fixedinputvelocity="-1" inputcontroller="0"/>
<fxchain numofeffects="0" enabled="0"/>
</instrumenttrack>
<pattern muted="0" steps="16" name="Kicker" pos="0" type="0">
<note pan="0" len="-192" vol="100" key="57" pos="0"/>
<note pan="0" len="-192" vol="100" key="57" pos="48"/>
<note pan="0" len="-192" vol="100" key="57" pos="96"/>
<note pan="0" len="-192" vol="100" key="57" pos="144"/>
</pattern>
</track>
</trackcontainer>
</bbtrack>
</track>
<track muted="0" name="Automation track" solo="0" type="5">
<automationtrack/>
</track>
<track muted="0" name="Vibed" solo="0" type="0">
<instrumenttrack usemasterpitch="1" pan="0" fxch="0" basenote="57" pitch="0" vol="100" pitchrange="1">
<instrument name="vibedstrings">
<vibedstrings volume0="100" pickup0="0.05" pick0="0" octave0="2" stiffness0="0" active6="0" slap0="0" length0="1" active1="0" active7="0" active4="0" active0="1" impulse0="0" active2="0" version="0.1" detune0="0" active3="0" pan0="0" graph0="AAAAADD7SD02vcg9g0AWPsLFRz7Nz3g+MaCUPtR8rD4W78M+gOjaPupa8T49nAM/2jkOP8B/GD+aZyI/SusrP/MENT/6rj0/A+RFPwKfTT8y21Q/G5RbP5jFYT/Ya2c/XoNsPwgJcT8L+nQ/+FN4P78Uez+sOn0/bcR+Pw+xfz8AAIA/D7F/P23Efj+sOn0/vhR7P/hTeD8K+nQ/CAlxP16DbD/Ya2c/l8VhPxqUWz8w21Q/Ap9NPwTkRT/4rj0/8wQ1P0jrKz+ZZyI/vX8YP9k5Dj89nAM/5lrxPn/o2j4Q78M+0nysPjOglD7Fz3g+wcVHPnpAFj4wvcg9/fpIPS69u7Ms+0i9R73IvYVAFr7NxUe+0M94vjiglL7XfKy+Fe/DvoXo2r7rWvG+P5wDv9s5Dr/Afxi/m2civ0rrK7/1BDW/+q49vwPkRb8Dn02/NNtUvxmUW7+YxWG/2Wtnv2GDbL8ICXG/C/p0v/lTeL++FHu/rDp9v23Efr8PsX+/AACAvw+xf79txH6/rDp9v74Ue7/3U3i/Cfp0vwgJcb9dg2y/1Wtnv5jFYb8ZlFu/L9tUvwOfTb8D5EW/9649v+8ENb9K6yu/l2civ7x/GL/bOQ6/PJwDv+Na8b526Nq+Fe/Dvs98rL4ooJS+z894vrzFR750QBa+BL3IvSb7SL0=" active8="0" active5="0"/>
</instrument>
<eldata fcut="14000" ftype="0" fres="0.5" fwet="0">
<elvol lspd_denominator="4" pdel="0" sustain="0.5" hold="0.5" x100="0" dec="0.5" lpdel="0" latt="0" lspd_numerator="4" lspd_syncmode="0" lamt="0" lshp="0" att="0" ctlenvamt="0" rel="0.1" amt="0" userwavefile="" lspd="0.1"/>
<elcut lspd_denominator="4" pdel="0" sustain="0.5" hold="0.5" x100="0" dec="0.5" lpdel="0" latt="0" lspd_numerator="4" lspd_syncmode="0" lamt="0" lshp="0" att="0" ctlenvamt="0" rel="0.1" amt="0" userwavefile="" lspd="0.1"/>
<elres lspd_denominator="4" pdel="0" sustain="0.5" hold="0.5" x100="0" dec="0.5" lpdel="0" latt="0" lspd_numerator="4" lspd_syncmode="0" lamt="0" lshp="0" att="0" ctlenvamt="0" rel="0.1" amt="0" userwavefile="" lspd="0.1"/>
</eldata>
<chordcreator chordrange="1" chord-enabled="0" chord="0"/>
<arpeggiator arpcycle="0" arptime_numerator="4" arptime_syncmode="0" arpskip="0" arpgate="100" arptime="200" arp-enabled="0" arptime_denominator="4" arp="0" arprange="1" arpmiss="0" arpdir="0" arpmode="0"/>
<midiport fixedoutputnote="-1" writable="0" fixedoutputvelocity="-1" outputprogram="1" outputchannel="1" outputcontroller="0" readable="0" inputchannel="0" basevelocity="63" fixedinputvelocity="-1" inputcontroller="0"/>
<fxchain numofeffects="0" enabled="0"/>
</instrumenttrack>
<pattern muted="0" steps="16" name="Vibed" pos="0" type="1">
<note pan="0" len="48" vol="100" key="48" pos="0"/>
<note pan="0" len="48" vol="100" key="50" pos="48"/>
<note pan="0" len="48" vol="100" key="52" pos="96"/>
<note pan="0" len="48" vol="100" key="53" pos="144"/>
<note pan="0" len="48" vol="100" key="55" pos="192"/>
<note pan="0" len="48" vol="100" key="57" pos="240"/>
<note pan="0" len="48" vol="100" key="59" pos="288"/>
<note pan="0" len="48" vol="100" key="60" pos="336"/>
</pattern>
</track>
</trackcontainer>
<track muted="0" name="Automation track" solo="0" type="6">
<automationtrack/>
<automationpattern mute="0" len="192" tens="1" prog="0" name="Numerator" pos="0"/>
<automationpattern mute="0" len="192" tens="1" prog="0" name="Denominator" pos="0"/>
<automationpattern mute="0" len="192" tens="1" prog="0" name="Tempo" pos="0"/>
<automationpattern mute="0" len="192" tens="1" prog="0" name="Master volume" pos="0"/>
<automationpattern mute="0" len="192" tens="1" prog="0" name="Master pitch" pos="0"/>
</track>
<fxmixer x="5" visible="1" width="543" minimized="0" maximized="0" y="310" height="333">
<fxchannel muted="0" soloed="0" volume="1" name="Master" num="0">
<fxchain numofeffects="0" enabled="0"/>
</fxchannel>
</fxmixer>
<ControllerRackView x="680" visible="0" width="350" minimized="0" maximized="0" y="310" height="200"/>
<pianoroll x="5" visible="0" width="860" minimized="0" maximized="0" y="5" height="480"/>
<automationeditor x="1" visible="0" width="860" minimized="0" maximized="0" y="1" height="400"/>
<projectnotes x="700" visible="0" width="687" minimized="0" maximized="0" y="10" height="400"><![CDATA[<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>]]></projectnotes>
<timeline lp0pos="0" lpstate="1" lp1pos="384"/>
<controllers/>
</song>
</lmms-project>
What I would to change is this zone for example:
Code: Select all
<pattern muted="0" steps="16" name="Vibed" pos="0" type="1">
<note pan="0" len="48" vol="100" key="48" pos="0"/>
<note pan="0" len="48" vol="100" key="50" pos="48"/>
<note pan="0" len="48" vol="100" key="52" pos="96"/>
<note pan="0" len="48" vol="100" key="53" pos="144"/>
<note pan="0" len="48" vol="100" key="55" pos="192"/>
<note pan="0" len="48" vol="100" key="57" pos="240"/>
<note pan="0" len="48" vol="100" key="59" pos="288"/>
<note pan="0" len="48" vol="100" key="60" pos="336"/>
</pattern>
Code: Select all
;
; ------------------------------------------------------------
; code based on : PureBasic - Xml
; 02.2022
; ------------------------------------------------------------
#Window = 0
#TreeGadget = 0
#XML = 0
Structure sNote
len.i
pos.i
vol.a
key.u
pan.f
EndStructure
Global Dim note.sNote(0) ; original notes
Global Dim noteChanged.sNote(0)
Global Nbnote=-1, countnote
Procedure ChangeNote(i,len,pos,vol,key,pan)
; to change the note
With noteChanged(i)
\len = len
\pos = pos
\vol = vol
\key = key
\pan = pan
EndWith
EndProcedure
Procedure SetNote(i,len,pos,vol,key,pan)
; To add Or set a note
If i=-1
Nbnote+1
ReDim note(Nbnote)
ReDim noteChanged(Nbnote)
i = nbnote
EndIf
; set the original note
With note(i)
\len = len
\pos = pos
\vol = vol
\key = key
\pan = pan
EndWith
; only change : pos and vol
ChangeNote(i,len,pos+Random(3)-Random(3),vol+Random(3)-Random(3),key,pan)
EndProcedure
Procedure FillTree(*CurrentNode, CurrentSublevel)
; Ignore anything except normal nodes. See the manual for
; XMLNodeType() for an explanation of the other node types.
If XMLNodeType(*CurrentNode) = #PB_XML_Normal
; Add this node to the tree. Add name and attributes
Text$ = GetXMLNodeName(*CurrentNode) + " : "
If ExamineXMLAttributes(*CurrentNode)
While NextXMLAttribute(*CurrentNode)
val =Val( XMLAttributeValue(*CurrentNode))
Text$ + XMLAttributeName(*CurrentNode) + "=" + Chr(34) + Str(val) + Chr(34) + " "
Select GetXMLNodeName(*CurrentNode)
Case "head"
info$ = info$+ XMLAttributeName(*CurrentNode)+"="+Chr(34) + Str(val) + Chr(34) + " "
Select XMLAttributeName(*CurrentNode)
Case "timesig_numerator"
timesig_numerator=Val
Case "bpm"
bpm=Val
Case "mastervol"
mastervol=Val
Case "timesig_denominator"
timesig_denominator=Val
Case "masterpitch"
masterpitch=Val
EndSelect
Case "note"
Select XMLAttributeName(*CurrentNode)
Case "len"
len = Val
Case "pos"
pos = Val
Case "vol"
vol = Val
Case "key"
key = Val
Case "pan"
pan = Val
EndSelect
EndSelect
Wend
If GetXMLNodeName(*CurrentNode) = "head"
Debug info$
ElseIf GetXMLNodeName(*CurrentNode) = "note"
; Debug "note trouvée !! " +Str(countnote) +" : "+Str(len)+"/"+Str(pos)+"/"+Str(vol)+"/"+Str(key)+"/"+Str(pan)+"/"
countnote+1
SetNote(-1,len,pos,vol,key,pan)
EndIf
EndIf
Text$+ " " + GetXMLNodeText(*CurrentNode)
AddGadgetItem(#TreeGadget, -1, Text$, 0, CurrentSublevel)
; Now get the first child node (if any)
;
*ChildNode = ChildXMLNode(*CurrentNode)
; Loop through all available child nodes and call this procedure again
;
While *ChildNode <> 0
FillTree(*ChildNode, CurrentSublevel + 1)
*ChildNode = NextXMLNode(*ChildNode)
Wend
EndIf
EndProcedure
FileName$ = OpenFileRequester("Choose XML file...", "", "XML files (*.xml)|*.xml|All files (*.*)|*.*", 0)
If FileName$ <> ""
If LoadXML(#XML, FileName$)
; Note:
; The LoadXML() succeed if the file could be read. This does not mean that
; there was no error in the XML though. To check this, XMLStatus() can be
; used.
;
; Display an error message if there was a markup error
;
If XMLStatus(#XML) <> #PB_XML_Success
Message$ = "Error in the XML file:" + Chr(13)
Message$ + "Message: " + XMLError(#XML) + Chr(13)
Message$ + "Line: " + Str(XMLErrorLine(#XML)) + " Character: " + Str(XMLErrorPosition(#XML))
MessageRequester("Error", Message$)
EndIf
; Note:
; Even if there was an error in the XML, all nodes before the error position
; are still accessible, so open the window and show the tree anyway.
If OpenWindow(#Window, 0, 0, 1024, 500, "XML Example", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MaximizeGadget)
TreeGadget(#TreeGadget, 10, 10, 1024-20, 500-20)
; Get the main XML node, and call the FillTree() procedure with it
;
*MainNode = MainXMLNode(#XML)
If *MainNode
FillTree(*MainNode, 0)
EndIf
; Expand all nodes for a nicer view
;
For i = 0 To CountGadgetItems(#TreeGadget) - 1
SetGadgetItemState(#TreeGadget, i, #PB_Tree_Expanded)
Next i
Debug "notes found : "+Str(countnote)+" / "+Str(ArraySize(note())+1)
; Show the note
Debug "original notes : "
info$ =""
For i= 0 To ArraySize(note())
info$+ "len="+Str(note(i)\len)+" Pos="+Str(note(i)\pos)+" vol="+Str(note(i)\vol)+" key="+Str(note(i)\key)+" pan="+Str(note(i)\pan)+Chr(10)
Next
Debug info$
Debug "Changed notes : "
info$ =""
For i= 0 To ArraySize(noteChanged())
info$+ "len="+Str(noteChanged(i)\len)+" Pos="+Str(noteChanged(i)\pos)+" vol="+Str(noteChanged(i)\vol)+" key="+Str(noteChanged(i)\key)+
" pan="+Str(noteChanged(i)\pan)+Chr(10)
Next
Debug info$
; Wait for the window close event.
Repeat
Event = WaitWindowEvent()
Select event
Case #PB_Event_SizeWindow
ResizeGadget(#TreeGadget, 10, 10, WindowWidth(0)-20, WindowHeight(0)-20)
EndSelect
Until Event = #PB_Event_CloseWindow
EndIf
Else
MessageRequester("Error", "The file cannot be opened.")
EndIf
EndIf

thank you.