MT-PowerDrumKit Alternative ?

Support & discussion regarding DAWs and MIDI sequencers.

Moderators: khz, MattKingUSA

User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

MT-PowerDrumKit Alternative ?

Postby headwar » Mon May 02, 2016 1:31 pm

Hi,

I'm looking for an alternative to MT-PowerDrumKit, which is both a drumkit emulator and a pattern sequencer, freeware for Ms Windows (and a brilliant and simple one). I know I could run it through Wine/Carla but an open source, native solution would be preferred.

The drumkit emulator part is totally doable in lots of ways (soundfonts, or my favorite, Drumgizmo). The pattern sequencer, though, is hard to emulate.
I already have a bank of midi patterns (extracted from MT-PowerDrumKit's exe resources) , now I need to be able to sequence them.

I think I've tried every Github & Sourceforge midi app to do it, with no success. The closest I've emulated it was with the always good Hydrogen, by converting my midi patterns to H2's own format (thanks to Domino Marama's m2hps, http://dominodesigns.info/m2hpc/index.html), but :
1) it lacks preview, you have to import the pattern in the editor to hear it
2) the library cannot be sorted, nor directories created (I have over 9000 patterns)
3) the patterns cannot be imported on the same track, each import creates its own one
4) to the best of my knowledge, it cannot directly handle a reference track, unless syncing it with a DAW playing said reference track.

Has anyone got an idea ? Thanks in advance,
- Hw

jochen
Established Member
Posts: 8
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Postby jochen » Sun May 15, 2016 8:49 am

How did you manage to extract the midi patterns?

User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Postby headwar » Sun May 15, 2016 2:34 pm

Hi,

Well, nothing fancy, just a resources extractor and a little dumb homemade script to split the biggest file into its smaller parts.

jochen
Established Member
Posts: 8
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Postby jochen » Mon May 16, 2016 8:46 pm

Hi,

I wrote a simple ruby-script that extracts the MIDI-Files:

Code: Select all

#encoding: utf-8
require 'rexml/document'
require 'fileutils'

dll = ARGV[0]
dest = ARGV[1]

data= IO.read('MT-PowerDrumKit.dll', :encoding=>'ascii-8bit')

xml_start = data.index('<GrooveDef')
xml_end = data.index('</GrooveDef>')+'</GrooveDef>'.length
xml = data[xml_start..xml_end]

data_start = xml_end+2

doc = REXML::Document.new(xml)
root = doc.root
root.elements.each("SuperStyle") do |ss|
  ss.elements.each("Style") do |s|
    s.elements.each("Groove") do |g|
      n_g = g.attributes["Name"].gsub("/","_")

      path = File.join([dest] + [ss, s, g].map{|e| e.attributes["Name"].gsub("/","_")})
      FileUtils.mkdir_p(path)
      offset = g.attributes["Offset"].to_i
      size = g.attributes["Size"].to_i
      File.open(File.join(path, n_g)+".mid","w"){|fil| fil.write(data[data_start+offset, size])}
      g.elements.each("Fill") do |f|
        n_f = f.attributes["Name"].gsub("/","_")
        offset = f.attributes["Offset"].to_i
        size = f.attributes["Size"].to_i
        File.open(File.join(path, n_f)+".mid","w"){|fil| fil.write(data[data_start+offset, size])}
      end
    end
  end
end




Just use it like:

Code: Select all

ruby extract.rb ./MT-PowerDrumKit.dll ./midi

and everything will be in ./midi.



Regards,
Jochen
Last edited by jochen on Tue May 17, 2016 5:19 am, edited 1 time in total.

User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Postby headwar » Mon May 16, 2016 9:29 pm

Hi,

Mine was in php and worked after the files were extracted from the exe, but its pretty close ;)

So I hope it helps someone out there, but doesn't help me. Has anyone got a clue how to sequence these extracted midi files ?

Regards,
Hw

jochen
Established Member
Posts: 8
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Postby jochen » Tue May 17, 2016 6:36 pm

Hi Hw,

to sequence the extracted grooves and fills I wrote another ruby script. Use it like

Code: Select all

ruby seq.rb groove01.mid 3 fill01.mid 1 groove02.mid 3 fill02.mid 1 output.mid


Always add parameters in pairs: midi-file + how many bars you want to use from it.
The last parameter is the output filename.

To playback the resulting file I use:

Code: Select all

jack-smf-player -t -a MT-PowerDrumKit:events-in test.mid



Code: Select all

#encoding: utf-8

class Event
   attr_reader :dtime, :data, :type, :note
   def initialize(dtime, data, type, note=nil)
      @dtime = dtime
      @data = data
      @type = type
      @note = note
   end   
 
  def dtime=(val)
    buffer = []
    buffer << (val & 0x7f)
    val = (val >> 7)
    while val > 0
      buffer << (0x80 + (val & 0x7f))
      val = (val >> 7)
    end

    @data.shift while (@data[0]&0x80).nonzero?
    @data.shift
    buffer.each{|b| @data.unshift(b)}
  end
   
   def self.eot
      self.new(dtime = 0, data = [0x00, 0xff, 0x2f,0x00], :eot)      
   end
   
end

class SMF
   attr_reader :events, :data, :tr_len, :len, :eob
   
   def initialize(file)
      @data = IO.read(file,:mode=>'rb', :encoding=>'ascii-8bit')
      parse
    @eob = @len
   end
   
   def getb
      return nil if @data.length <= @data_pos
      b = @data.bytes[@data_pos]
      @data_pos+=1
      b
   end
 
  def bars(n)
    tmp = []
    time = 0
    @eob = (n*@numer.to_f/2**@denom*4*@hd_dtt).to_i
    @events.each do |e|
      if (time + e.dtime) < @eob
        tmp << e
        time += e.dtime
      else
        break
      end   
    end
    @events = tmp
    @len = time
  end
 
  def append(smf)
    d = @eob - @len
    warn "d: #{d}"
    smf.events.first.dtime = d
    @events.concat(smf.events)
    @len = @eob + smf.len
    @eob += smf.eob
   
  end
 
  def save_as(fn)
    es = @events.dup
    es << Event.eot
    edata = es.map{|e| e.data.map{|d| d.chr}.join}.join
    mid = @data[0,18] + [edata.length].pack("N") + edata
    File.open(fn,"wb"){|f| f.write(mid)}
  end
 
   def parse
      @hd_id = @data[0,4]
      @hd_len = @data[4,4].unpack("N")[0]
      @hd_fmt = @data[8,2].unpack("n")[0]
      @hd_n = @data[10,2].unpack("n")[0]
      @hd_dtt = @data[12,2].unpack("n")[0]
      
      @tr_id = @data[14,4]
      @tr_len = @data[18,4].unpack("N")
      
      @data_pos = 22
      state = :wait_start
      time = []
      cmd = nil
      meta_cmd = nil
      val = 0
      txt_len = nil
      txt = ""
      b = ""
      @len = 0
      ev_data = []
      @events = []
      while b = getb do
         case state
            when :wait_start
               ev_data << b
               if (b&0x80).nonzero?
                  time << (b&0x7f)
               else
                  time << b
                  val = 0
                  time.each do |v|
                     val = (val << 7) + v
                  end                  
                  @len += val
                  time = []
                  state = :wait_cmd                                    
               end
            when :wait_cmd
               ev_data << b
               cmd = b
               if cmd == 0xFF
                  state = :wait_meta_cmd
               elsif (cmd&0x90).nonzero?                  
                  note = getb
                  vel = getb
                  ev_data << note
                  ev_data << vel                  
                  @events << Event.new(val, ev_data.dup,:note_on, note)
                  ev_data = []
                  state = :wait_start
               else
                  raise  "unknown cmd: #{b.to_s(16)} (#{@data_pos})"
               end
            when :wait_meta_cmd
               meta_cnd = b
               ev_data << b
               if b == 0x03
                  state = :wait_text_length
               elsif b == 0x58
                  t = []
                  t << getb #len
                  t << @numer = getb
                  t << @denom = getb
                  t << getb #tpb
                  t << getb #32pb
                  ev_data.concat(t)
                  @events << Event.new(val, ev_data.dup, :time_sig)
                  ev_data = []
                  state = :wait_start
               elsif b == 0x2f # end of track
                  getb # 0
                  ev_data = []
                  state = :wait_start
               else
                  raise "unknown meta cmd:  #{b.to_s(16)}"
               end
            when :wait_text_length
               txt_len = b
               ev_data << b
               state = :wait_text
            when :wait_text
               txt << b
               ev_data << b
               if txt_len > 1
                  txt_len -= 1
               else
                  state = :wait_start
                  @events << Event.new(val, ev_data.dup, :txt)
                  ev_data = []
               end
         end
      end
   end
   
end


if __FILE__==$0
 
  output = ARGV.pop
  midis = []
  (1..ARGV.length).step(2) do |i|
    n = ARGV[i].to_i
    smf = SMF.new(ARGV[i-1])
    smf.bars(n)
    midis << smf
  end
  first = midis.shift
  midis.each { |m| first.append(m) }
  first.save_as(output)
end



User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Postby headwar » Tue May 17, 2016 10:05 pm

Hi again,

@Jochen, Thanks for the script ! Not what I'm asking for but definitely a great tool. Though, you are probably in my exact position, having thousands of drum loops, choosing one is the most complex part. You seem to be quite fluent in ruby, any way you think you could create a program with a GUI, that allows to browse our collection of midis and set them in place, with an easy "listen on hover/single click" ?

@Beck, Good tip ! LMMS has a better browser than Hydrogen. It suffer 3 main drawbacks for my intended use though :
1) doesnt preview on hover or single click : I have to import the midi to hear it
2) each imported part is put on its own track (with a soundfont player), and cannot be directly dragged in place on a track where the midi channel of the soundfont is already set to drums.
3) I haven't found the way to export midi from a track, to import in Ardour.

Maybe some LMMS guru could help us ?

User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Postby headwar » Wed May 18, 2016 10:02 am

Hi Beck,

Regarding the 3 points mentioned,

The 1st point would be enough to make it a practical solution, so I hope its feasible and someone with the know-how will chime in ;)
2) copy pasting with ctrl+click works, but in my use case, it's very uncomfortable as it creates as many new tracks as I've imported sequences
3) I want to import the midi in Ardour (not the audio), to be able to use e.g. Drumgizmo to synth the drum hits. LMMS has a built-in export feature for audio, but AFAICT no midi export (seems to be part of the upcoming 1.2 version though).

Thanks for the ideas !

jochen
Established Member
Posts: 8
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Postby jochen » Fri May 20, 2016 7:45 am

For me, the biggest problem of using MT-PowerDrumKit under Linux was that dragging and dropping of the sequence to Qtractor, Ardour, etc. does not work.

Now I wrote a simple application that reads the grooves from the DLL and lets you browse, preview and sequence them. Then the sequence can be saved to a file or directly be dragged and dropped to Qtractor or Ardour.

* Preview of a groove is initiated by a double click.
* Use the Add-button or simple drag and drop a groove to the sequence list.
* the Play-button starts playback of the sequence.
* Export saves the sequence to a file of your choice.
* Drag the Export-button to Qtractor or Ardour to have the sequence there.

Dependencies:
* ruby
* Active Support (gem install activesupport)
* qtbindings (gem install qtbindings)

If you want to try it, you have to modify config.rb (path to dll, playback command).

run it with:

Code: Select all

ruby sequencer.rb
You do not have the required permissions to view the files attached to this post.

User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Postby headwar » Fri May 20, 2016 11:43 am

Hi jochen, and thanks for your hard work !

For those wanting to install your sequencer, here's how I did based on error messages :

Code: Select all

sudo apt-get install ruby
sudo apt-get install ruby1.9.1-dev
sudo apt-get install cmake
sudo apt-get install qt-sdk
sudo gem install activesupport
sudo gem install qtbindings

downloading Jack-smf-utils (https://sourceforge.net/projects/jack-smf-utils/)
uncompressing it in a folder, then in that folder,

Code: Select all

./configure
make
sudo make install


I've also copied the MT-PowerDrumKit.dll and MT-PowerDrumKit-Content.pdk in the directory where I put Sequencer, and edited the config.rb file to :

Code: Select all

module SeqConfig
   PLAY_CMD = "jack-smf-player -t -a MT-PowerDrumKit:events-in"
   KILL_CMD = "killall jack-smf-player"
   
   DLL = "MT-PowerDrumKit.dll"   
end


I have a few problems though :
1) Clicking on a rythm gets no sound out, the console reads :

Code: Select all

jack-smf-player: aucun processus trouvé
jack-smf-player: format: 0 (single track); number of tracks: 1; division: 480 PPQN.
jack-smf-player: format: 0 (single track); number of tracks: 1; division: 480 PPQN.
jack-smf-player: Cannot connect to MT-PowerDrumKit:events-in.
jack-smf-player: Couldn't connect to 'MT-PowerDrumKit:events-in', exiting.


2) Clicking the "play" button results in a crash :

Code: Select all

(myhomepath)/Téléchargements/sequencer/smf.rb:49:in `getb': undefined method `[]' for #<Enumerator:0x000000030a7f00> (NoMethodError)
   from /home/edouard/Téléchargements/sequencer/smf.rb:115:in `parse'
   from /home/edouard/Téléchargements/sequencer/smf.rb:42:in `initialize'
   from /home/edouard/Téléchargements/sequencer/pdk.rb:36:in `new'
   from /home/edouard/Téléchargements/sequencer/pdk.rb:36:in `block in write_seq'
   from /home/edouard/Téléchargements/sequencer/pdk.rb:35:in `each'
   from /home/edouard/Téléchargements/sequencer/pdk.rb:35:in `write_seq'
   from /home/edouard/Téléchargements/sequencer/pdk.rb:55:in `play_seq'
   from sequencer.rb:202:in `playSeq'
   from /var/lib/gems/1.9.1/gems/qtbindings-4.8.6.2/lib/Qt/qtruby4.rb:479:in `qt_metacall'
   from /var/lib/gems/1.9.1/gems/qtbindings-4.8.6.2/lib/Qt/qtruby4.rb:479:in `method_missing'
   from /var/lib/gems/1.9.1/gems/qtbindings-4.8.6.2/lib/Qt/qtruby4.rb:479:in `exec'
   from sequencer.rb:298:in `<main>'


3) Clicking the "export" button lets me select a file name, then crashes the app with the same error message seen in (2)

4) I got random crashes on clicking the left treeview :

Code: Select all

sequencer.rb:72:in `&': can't convert Qt::Enum into Integer (TypeError)
   from sequencer.rb:72:in `mouseMoveEvent'
   from /var/lib/gems/1.9.1/gems/qtbindings-4.8.6.2/lib/Qt/qtruby4.rb:479:in `method_missing'
   from /var/lib/gems/1.9.1/gems/qtbindings-4.8.6.2/lib/Qt/qtruby4.rb:479:in `exec'
   from sequencer.rb:298:in `<main>'


I hope my report is meaningful to you more than it is to me, this app would be very useful !

Regards, (and again, thanks for your hard work)
Hw

jochen
Established Member
Posts: 8
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Postby jochen » Fri May 20, 2016 12:16 pm

Hello Hw,

1) in

Code: Select all

PLAY_CMD = "jack-smf-player -t -a MT-PowerDrumKit:events-in"

the parameter "-a MT-PowerDrumKit:events-in" means, jack-smf-player should send the midi data to the jack-midi-port "MT-PowerDrumKit:events-in". If you got MT-PowerDrumKit running through carla, this port should be available. But of course you can choose to use another port that belongs to another application..

2,3,4) You are using ruby 1.9.1 while i developed with ruby>=2.0.0. I wonder how you could install qtbindings with 1.9.1? If I try to install it with 1.9.2 I get

Code: Select all

ERROR:  Error installing qtbindings:
        qtbindings requires Ruby version >= 2.0.0.


I modified the commands that gave you the errors so that they should also work with 1.9.1, but as I can't install qtbindings I can't test it... there may be other problems...

Can you install a newer ruby (>=2.0.0)? That would be better.

regards,
Jochen
You do not have the required permissions to view the files attached to this post.

User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Postby headwar » Fri May 20, 2016 2:26 pm

SUCCEEEESSS !!! :)

Thanks for having modified your script.

Remember my OP : I wanted no wine in my config.

So, following your advice, I changed the config's playback function to :

Code: Select all

PLAY_CMD = "jack-smf-player -t -a qsynth:midi"

Lanched Qsynth, opened the fluidR3_GM.sf2 soundfont, changed the channel/bank to 128/0

I works ! I can now enjoy your script and create drumlines ! No need for MT-PowerDrumKit's except for the midi resources :)
Thanks a lot !
BTW, I didn't change my ruby version, so I'm still <2.

tavasti
Established Member
Posts: 478
Joined: Tue Feb 16, 2016 6:56 am
Location: Kangasala, Finland
Contact:

Re: MT-PowerDrumKit Alternative ?

Postby tavasti » Thu Jun 01, 2017 7:25 pm

jochen wrote:Now I wrote a simple application that reads the grooves from the DLL and lets you browse, preview and sequence them. Then the sequence can be saved to a file or directly be dragged and dropped to Qtractor or Ardour.
...
Dependencies:
* ruby
* Active Support (gem install activesupport)
* qtbindings (gem install qtbindings)

Wanted to try this, but unfortunately 'gem install qtbindings' fails. Running ubuntu 16.04. From error log:
/usr/bin/cc -DCHECK_FUNCTION_EXISTS=pthread_create -o CMakeFiles/cmTC_61ec7.dir/CheckFunctionExists.c.o -c /usr/share/cmake-3.5/Modules/CheckFunctionExists.c
Linking C executable cmTC_61ec7
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_61ec7.dir/link.txt --verbose=1
/usr/bin/cc -DCHECK_FUNCTION_EXISTS=pthread_create CMakeFiles/cmTC_61ec7.dir/CheckFunctionExists.c.o -o cmTC_61ec7 -rdynamic -lpthreads
/usr/bin/ld: cannot find -lpthreads
collect2: error: ld returned 1 exit status

I'm not familiar with ruby & gems, but I know that there is no library pthreads but it is pthread. :-o
Linux veteran & Novice musician

Hear my music at https://audiu.net/users/tawaste

tavasti
Established Member
Posts: 478
Joined: Tue Feb 16, 2016 6:56 am
Location: Kangasala, Finland
Contact:

Re: MT-PowerDrumKit Alternative ?

Postby tavasti » Tue Jul 10, 2018 7:44 am

Got back to this. Got ruby gems installed, build error messges were confusing me when I was too tired. Actual problem was ruby-dev package missing.

I wanted drums to be played from hydrogen, so I used pmidi instead of jack-smf-player.
pmidi -l # to list ports


And from that I could get port to connect. To config.rb:
PLAY_CMD = "pmidi -p 129:0"


I got it playing, but does not sound very good. It sounds like all drum samples play short, maybe getting note off soon after note on, and hydrogen honoring those note off commands?

Edit: in hydgen midi options selecting 'ignore note-off' will fix issue!

Edit2: and hydrogen has also jack-midi option, so it would be possible to use jack-smf-player also
Linux veteran & Novice musician

Hear my music at https://audiu.net/users/tawaste

tavasti
Established Member
Posts: 478
Joined: Tue Feb 16, 2016 6:56 am
Location: Kangasala, Finland
Contact:

Re: MT-PowerDrumKit Alternative ?

Postby tavasti » Wed Jul 11, 2018 8:38 am

jochen wrote:Now I wrote a simple application that reads the grooves from the DLL and lets you browse, preview and sequence them. Then the sequence can be saved to a file or directly be dragged and dropped to Qtractor or Ardour.

* Preview of a groove is initiated by a double click.
* Use the Add-button or simple drag and drop a groove to the sequence list.
* the Play-button starts playback of the sequence.
* Export saves the sequence to a file of your choice.
* Drag the Export-button to Qtractor or Ardour to have the sequence there.

This is really great!

One additional feature would be great: setting tempo. Now everything plays on 120 BPM, and if looking for suitable beat for something really different, spotting the one you want is not trivial.

So what would be needed:
- text field for inputting tempo
- calculate 60000000/BPM
- if there is some ruby lib for modifying midi file, then use that, but if not, it can be done with smfsh:
smfsh> load input.mid
smfsh> add 0 ff51030ac55a
smfsh> save output.mid

In example I had tempo 85, which will result in hex 0AC55A. Tempomap event is ff5103.

Edit: https://github.com/jimm/midilib
Linux veteran & Novice musician

Hear my music at https://audiu.net/users/tawaste


Return to “Recorders & Sequencers”

Who is online

Users browsing this forum: No registered users and 1 guest