| 
 DirectMusic: 
  Modifying Music 
By: Jack Hoxley 
Written: June 2000 
  Download: 
  DM_Modify.Zip 
  (10kb) DM_DLSFX.zip (485kb) 
 
 
 
 
You can only go so far with the 
  two previous tutorials; sooner or later you will need to learn how to change 
  things. This is what this tutorial is about. There are only a few things that 
  can be done to "normal" music; most of the interesting things can 
  only be done when using DLS files. 
I will be using a modified version 
  of the DM_Midi program to demonstrate how to do these things; you can download 
  it above, or you can download it fromt he downloads page. 
Changing the Volume 
  This is quite important, and is very simple. Using this you can let your user 
  set how loud he/she wants the music to be played; this can be very important 
  as not everyone playing your game will want to hear your music. You could also 
  program it so that you have fade-in's or fade-outs. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        Sub SetVolume(nVolume As 
      Byte)  
      'This formula allows you to specify a volume between 
       
      '0-100; similiar to a percentage  
      perf.SetMasterVolume (nVolume * 42 - 3000)  
      End Sub 
       
      'You can then call this procedure like so: 
      call SetVolume(100) 'Max volume 
      SetVolume 50 'Half Volume | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Changing the Tempo 
  This isn't quite as useful or important as changing the volume, but it will 
  probably be useful somewhere. So far the only use I've found for it is amusement 
  (sped up Mozart mainly) :) 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        Sub SetTempo(nTempo As Single) 
      'the tempo must be between 0.25 and 2  
      'the default is 1; 2 would double this, 0.5 would half this  
      perf.SetMasterTempo nTempo  
      End Sub 
       
      'You can call this like so: 
      call SetTempo(0.9) 'Slightly Slow 
      SetTempo(2) 'Double speed  | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Done. Those are the two main 
  effects that you can use with "normal" music. 
DLS Effects 
  These are probably the better effects; but they're also harder to use - like 
  most things in DirectX. Although strictly speaking these aren't effects; they're 
  still different things to do with your music. The main problem (and what makes 
  it difficult) is that you need to know what's in the DLS collection. Which will 
  require software; some basic knowledge, and if you intend to make your own then 
  you'll need musical knowledge. 
The effect to be demonstrated 
  here is playing notes - MIDI notes. A DLS collection with one instrument has 
  a different tone for every entry on a normal keyboard. We just choose one of 
  these notes to play. This is where the idea of DLS files comes in - a MIDI piece 
  is no more than a set of notes to play; each one intended for a different instrument 
  - the DLS provides the instruments; so what if the instruments are totally messed 
  up - ie, not normal notes? You start getting interesting effects. 
If you're sending notes it allows 
  you to create dynamic music; you could have atmospheric music most of the time; 
  and easily switch to heart-pounding action music, which adds a further dimension 
  to gameplay. A good example of this is XCOM: Apocalypse (Should you have played 
  it; if not, why not?) - the music in that changes from atmospheric creapy music 
  to action-fighting music; although it doesn't actually use DirectMusic to do 
  this. 
Step1: Initialising everything. 
  To use a DLS collection for playing notes you dont need any music to actually 
  play; but you need it just for the way that DirectMusic works. You need a segment 
  in order to load/connect to a DLS collection - this segment can be complete 
  silence, as you're never going to play it. It is advisable in this case to load 
  the smallest possible file. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        'After doing normal initialisation, 
        put this line in: 
        Call perf.SendPatchPMSG(0, DMUS_PMSGF_REFTIME, 1, 127, 0, 0)  
         
        'This next part goes where you normally load your 
        music: 
         
        'Load our DLS Collection  
        Set col = loader.LoadCollection(App.Path & "\boids.dls")  
         
        'This segment is never played; but we require a 
        segment 
        'in order to use a DLS file. This could either be a segment  
        'or a MIDI file - it doesn't matter  
        Set seg = loader.LoadSegment(App.Path & "\sample.sgt")  
        Call seg.ConnectToCollection(col)  
        Call seg.Download(perf)  | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Step2: Playing a Note 
  Playing a note requires that we describe what it's going to be. DirectX has 
  a built in type definition for this, called DMUS_NOTE_PMSG. We then fill this 
  out with all the relevent details and pass it through to DirectMusic; which 
  generates us a note. There are two ways of sending a note; in our own time, 
  or within the time of the music playing. As we want the note to play immediately 
  we want it to play in our own time; If you had ANY music playing at the same 
  time you'd have to play it in the music's time. This would require that you 
  worked out exactly where you were currently and then play it. Or; you could 
  set it up so that certain notes are played at certain times throughout a piece 
  of music. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        'We fill out a description 
      of the note to be played; 
                                                                          'then
                                                                          we
                                                                          play
                                                                          it.
                                                                          NOTE:
                                                                          If you
                                                                          play
                                                                          the
                                                                          same
                                                                          note 
                                                                          'before
                                                                          the
                                                                          previous
                                                                          note
                                                                          has
                                                                          finished
                                                                          you'll
                                                                          get
                                                                          weird 
                                                                          'results
                                                                          -
                                                                          mixing
                                                                          and
                                                                          frequency
                                                                          changes 
       
      Dim noteMsg As DMUS_NOTE_PMSG  
       
      noteMsg.velocity = 255 'Volume (or Velocity/speed 
      of the sound) 
      noteMsg.flags = DMUS_NOTEF_NOTEON 
      noteMsg.midiValue = 100 'Change this value for different 
      notes  
      noteMsg.mtDuration = 3000 'in ms 
      'We must have the first two flags as 0 and ......REFTIME  
      'otherwise we have to interact with the music time. As it is, 
      'the note will play immediately  
      Call perf.SendNotePMSG(0, DMUS_PMSGF_REFTIME, 1, noteMsg) | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Finished. There is only a certain 
  distance you can go using this without actually getting into the music making. 
  To use this properly you will need to know what's inside the DLS file you're 
  using. I recommend getting a copy of DierctMusic producer from Microsoft's developer 
  site. This program is specifically designed for the task of creating, viewing 
  and editing DLS collections and other DirectMusic mediums. 
You can download a working example 
  from the top of this page; or from my downloads page. 
   
                                       |