MT-PowerDrumKit Alternative ?

Support & discussion regarding DAWs and MIDI sequencers.

Moderators: MattKingUSA, khz

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

MT-PowerDrumKit Alternative ?

Post by headwar »

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: 9
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Post by jochen »

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 ?

Post by headwar »

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: 9
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Post by jochen »

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 ?

Post by headwar »

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: 9
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Post by jochen »

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 ?

Post by headwar »

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 ?

Post by headwar »

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: 9
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Post by jochen »

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
Attachments
sequencer.tar.gz
(4.83 KiB) Downloaded 131 times
User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Post by headwar »

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: 9
Joined: Tue Jan 27, 2009 7:05 pm

Re: MT-PowerDrumKit Alternative ?

Post by jochen »

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
Attachments
sequencer.tar.gz
(5.08 KiB) Downloaded 123 times
User avatar
headwar
Established Member
Posts: 40
Joined: Tue Jul 29, 2014 8:29 pm

Re: MT-PowerDrumKit Alternative ?

Post by headwar »

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: 2047
Joined: Tue Feb 16, 2016 6:56 am
Location: Kangasala, Finland
Has thanked: 369 times
Been thanked: 208 times
Contact:

Re: MT-PowerDrumKit Alternative ?

Post by tavasti »

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

Latest track: https://www.youtube.com/watch?v=ycVrgGtrBmM

tavasti
Established Member
Posts: 2047
Joined: Tue Feb 16, 2016 6:56 am
Location: Kangasala, Finland
Has thanked: 369 times
Been thanked: 208 times
Contact:

Re: MT-PowerDrumKit Alternative ?

Post by tavasti »

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

Latest track: https://www.youtube.com/watch?v=ycVrgGtrBmM

tavasti
Established Member
Posts: 2047
Joined: Tue Feb 16, 2016 6:56 am
Location: Kangasala, Finland
Has thanked: 369 times
Been thanked: 208 times
Contact:

Re: MT-PowerDrumKit Alternative ?

Post by tavasti »

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

Latest track: https://www.youtube.com/watch?v=ycVrgGtrBmM

Post Reply