Page 1 of 2
MT-PowerDrumKit Alternative ?
Posted: Mon May 02, 2016 1:31 pm
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
Re: MT-PowerDrumKit Alternative ?
Posted: Sun May 15, 2016 8:49 am
by jochen
How did you manage to extract the midi patterns?
Re: MT-PowerDrumKit Alternative ?
Posted: Sun May 15, 2016 2:34 pm
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.
Re: MT-PowerDrumKit Alternative ?
Posted: Mon May 16, 2016 8:46 pm
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
Re: MT-PowerDrumKit Alternative ?
Posted: Mon May 16, 2016 9:29 pm
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
Re: MT-PowerDrumKit Alternative ?
Posted: Tue May 17, 2016 6:36 pm
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
Re: MT-PowerDrumKit Alternative ?
Posted: Tue May 17, 2016 10:05 pm
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 ?
Re: MT-PowerDrumKit Alternative ?
Posted: Wed May 18, 2016 10:02 am
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 !
Re: MT-PowerDrumKit Alternative ?
Posted: Fri May 20, 2016 7:45 am
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:
Re: MT-PowerDrumKit Alternative ?
Posted: Fri May 20, 2016 11:43 am
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
Re: MT-PowerDrumKit Alternative ?
Posted: Fri May 20, 2016 12:16 pm
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
Re: MT-PowerDrumKit Alternative ?
Posted: Fri May 20, 2016 2:26 pm
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.
Re: MT-PowerDrumKit Alternative ?
Posted: Thu Jun 01, 2017 7:25 pm
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.
Re: MT-PowerDrumKit Alternative ?
Posted: Tue Jul 10, 2018 7:44 am
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
Re: MT-PowerDrumKit Alternative ?
Posted: Wed Jul 11, 2018 8:38 am
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