SetXMLAttribute and save

Just starting out? Need help? Post your questions and find answers here.
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

SetXMLAttribute and save

Post by [blendman] »

HI

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>
The code I use for the the moment, to get the note (and change it with a random (it's just a test)) :

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


If have any idea how to save the xml with my changes, it would be great :)
thank you.
Fips
User
User
Posts: 35
Joined: Sun Feb 20, 2022 1:03 pm

Re: SetXMLAttribute and save

Post by Fips »

I'm not quiet sure I fully understand your problem, but maybe like this?

Code: Select all

SaveXML(#XML,"changed_file.mmp")
Post Reply