[SCM] mma/master: add two utilities and man pages from upstream author's mma_1.7_all.deb

bolangi-guest at users.alioth.debian.org bolangi-guest at users.alioth.debian.org
Thu Feb 3 09:50:22 UTC 2011


The following commit has been merged in the master branch:
commit 5e93df6b7ebd5adedf728e845908b04f6778e475
Author: Joel Roth <joelz at pobox.com>
Date:   Wed Feb 2 23:11:26 2011 -1000

    add two utilities and man pages from upstream author's mma_1.7_all.deb
    
    (placed in debian/ directory)

diff --git a/debian/mma-mnx b/debian/mma-mnx
new file mode 100755
index 0000000..2620ef0
--- /dev/null
+++ b/debian/mma-mnx
@@ -0,0 +1,466 @@
+#!/usr/bin/env python
+
+# Extract midi solos for including into mma scripts using MIDINote.
+# Bob van der Poel, Jan/09
+
+import os, sys, math, time, getopt
+
+# Some constants/globals
+
+voiceNames=[
+    'Piano1', 'Piano2','Piano3',
+    'Honky-TonkPiano', 'RhodesPiano', 'EPiano',
+    'HarpsiChord', 'Clavinet', 'Celesta',
+    'Glockenspiel', 'MusicBox', 'Vibraphone',
+    'Marimba', 'Xylophone', 'TubularBells', 'Santur',
+    'Organ1', 'Organ2', 'Organ3', 'ChurchOrgan',
+    'ReedOrgan', 'Accordion', 'Harmonica',
+    'Bandoneon', 'NylonGuitar', 'SteelGuitar',
+    'JazzGuitar', 'CleanGuitar', 'MutedGuitar',
+    'OverDriveGuitar', 'DistortonGuitar',
+    'GuitarHarmonics', 'AcousticBass',
+    'FingeredBass', 'PickedBass', 'FretlessBass',
+    'SlapBass1', 'SlapBass2', 'SynthBass1',
+    'SynthBass2', 'Violin', 'Viola', 'Cello',
+    'ContraBass', 'TremoloStrings',
+    'PizzicatoString', 'OrchestralHarp', 'Timpani',
+    'Strings', 'SlowStrings', 'SynthStrings1',
+    'SynthStrings2', 'ChoirAahs', 'VoiceOohs',
+    'SynthVox', 'OrchestraHit', 'Trumpet',
+    'Trombone', 'Tuba', 'MutedTrumpet', 'FrenchHorn',
+    'BrassSection', 'SynthBrass1', 'SynthBrass2',
+    'SopranoSax', 'AltoSax', 'TenorSax',
+    'BaritoneSax', 'Oboe', 'EnglishHorn', 'Bassoon',
+    'Clarinet', 'Piccolo', 'Flute', 'Recorder',
+    'PanFlute', 'BottleBlow', 'Shakuhachi',
+    'Whistle', 'Ocarina', 'SquareWave', 'SawWave',
+    'SynCalliope', 'ChifferLead', 'Charang',
+    'SoloVoice', '5thSawWave', 'Bass&Lead',
+    'Fantasia', 'WarmPad', 'PolySynth', 'SpaceVoice',
+    'BowedGlass', 'MetalPad', 'HaloPad', 'SweepPad',
+    'IceRain', 'SoundTrack', 'Crystal', 'Atmosphere',
+    'Brightness', 'Goblins', 'EchoDrops',
+    'StarTheme', 'Sitar', 'Banjo', 'Shamisen',
+    'Koto', 'Kalimba', 'BagPipe', 'Fiddle', 'Shanai',
+    'TinkleBell', 'AgogoBells', 'SteelDrums',
+    'WoodBlock', 'TaikoDrum', 'MelodicTom1',
+    'SynthDrum', 'ReverseCymbal', 'GuitarFretNoise',
+    'BreathNoise', 'SeaShore', 'BirdTweet',
+    'TelephoneRing', 'HelicopterBlade',
+    'Applause/Noise', 'GunShot' ]
+
+# Controller names. Tables are borrowed from:
+#     http://www.midi.org/about-midi/table3.shtml
+
+ctrlNames = {
+    0:'Bank', 1:'Modulation', 2:'Breath',
+    3:'Ctrl3', 4:'Foot', 5:'Portamento',
+    6:'Data', 7:'Volume', 8:'Balance',
+    9:'Ctrl9', 10:'Pan', 11:'Expression',
+    12:'Effect1', 13:'Effect2', 14:'Ctrl14',
+    15:'Ctrl15', 16:'General1', 17:'General2',
+    18:'General3', 19:'General4', 20:'Ctrl20',
+    21:'Ctrl21', 22:'Ctrl22', 23:'Ctrl23',
+    24:'Ctrl24', 25:'Ctrl25', 26:'Ctrl26',
+    27:'Ctrl27', 28:'Ctrl28', 29:'Ctrl29',
+    30:'Ctrl30', 31:'Ctrl31', 32:'BankLSB',
+    33:'ModulationLSB', 34:'BreathLSB', 35:'Ctrl35',
+    36:'FootLSB', 37:'PortamentoLSB', 38:'DataLSB',
+    39:'VolumeLSB', 40:'BalanceLSB', 41:'Ctrl41',
+    42:'PanLSB', 43:'ExpressionLSB', 44:'Effect1LSB',
+    45:'Effect2LSB', 46:'Ctrl46', 47:'Ctrl47',
+    48:'General1LSB', 49:'General2LSB', 50:'General3LSB',
+    51:'General4LSB', 52:'Ctrl52', 53:'Ctrl53',
+    54:'Ctrl54', 55:'Ctrl55', 56:'Ctrl56',
+    57:'Ctrl57', 58:'Ctrl58', 59:'Ctrl59',
+    60:'Ctrl60', 61:'Ctrl61', 62:'Ctrl62',
+    63:'Ctrl63', 64:'Sustain', 65:'Portamento',
+    66:'Sostenuto', 67:'SoftPedal', 68:'Legato',
+    69:'Hold2', 70:'Variation', 71:'Resonance',
+    72:'ReleaseTime', 73:'AttackTime', 74:'Brightness',
+    75:'DecayTime', 76:'VibratoRate', 77:'VibratoDepth',
+    78:'VibratoDelay', 79:'Ctrl79', 80:'General5',
+    81:'General6', 82:'General7', 83:'General8',
+    84:'PortamentoCtrl', 85:'Ctrl85', 86:'Ctrl86',
+    87:'Ctrl87', 88:'Ctrl88', 89:'Ctrl89',
+    90:'Ctrl90', 91:'Reverb', 92:'Tremolo',
+    93:'Chorus', 94:'Detune', 95:'Phaser',
+    96:'DataInc', 97:'DataDec', 98:'NonRegLSB',
+    99:'NonRegMSB', 100:'RegParLSB', 101:'RegParMSB',
+    102:'Ctrl102', 103:'Ctrl103', 104:'Ctrl104',
+    105:'Ctrl105', 106:'Ctrl106', 107:'Ctrl107',
+    108:'Ctrl108', 109:'Ctrl109', 110:'Ctrl110',
+    111:'Ctrl111', 112:'Ctrl112', 113:'Ctrl113',
+    114:'Ctrl114', 115:'Ctrl115', 116:'Ctrl116',
+    117:'Ctrl117', 118:'Ctrl118', 119:'Ctrl119',
+    # pseudo controllers, also called channel mode messages
+    120:'AllSoundsOff', 121:'ResetAll', 122:'LocalCtrl',
+    123:'AllNotesOff', 124:'OmniOff', 125:'OmniOn',
+    126:'PolyOff', 127:'PolyOn' }
+
+# This is our midi file reader. Sucked out of ys2mma
+
+class MF:
+
+    def __init__(self, filename):
+
+        """ The filename is assumed to be a valid midi file and is read and
+            parsed. The events found are separated into channels and inserted
+            into events{}. The stucture of events() is:
+                 events[ch]     - a entry for each channel
+                 events[ch][ev] - entry for each offset 
+
+            we also create a few helpful variables:
+                 voices[] - the last voice found for each channel, defaults to 0
+                 metanames[] - set for ??/
+                 tempo       - pulled out of header info
+
+            NOTE: All events are read/parsed but only the limited set
+                  needed are saved ... meta events, etc. are just dumped.
+        """
+
+        self.events        = {}
+        self.voices        = [ 0 ] * 16   # last voice found for each track
+        self.metanames     = []
+        self.tempo         = 120          # default tempo if none found in file
+ 
+        for c in range(0,16):   # create an empty entry for each possible channel
+            self.events[c]=[]
+
+        # read in file
+
+        try:
+            inpath = file(filename, "rb")
+        except:
+            error("Unable to open MIDI file %s for reading" % filename)
+
+        self.midifile=inpath.read()
+        inpath.close()
+        self.offset = 0
+
+        hd = self.chars(4) # Ensure this is valid header
+        if hd != 'MThd':
+            error("Expecting 'HThd', %s not a standard midi file." % filename)
+
+        # the next chunk is a 32bit length (always 6), format (0 or 1),
+        # number of tracks, beat division
+
+        a = self.m32i() 
+        if a != 6:
+            error("Expecting a 32 bit value of 6 in header")
+
+        format=self.m16i()
+        if format not in (0,1):
+            error("MIDI file format %s not recognized" % format)
+
+        ntracks=self.m16i()
+        self.beatDivision=self.m16i()
+
+        # Finished the header, now we do each track
+
+        for tr in range(ntracks):
+            tm=0    # this is the offset pointer, incremented as we parse event times
+            hdr = self.chars(4)
+            if hdr != 'MTrk':
+                error("Malformed MIDI file in track header")
+            trlen = self.m32i()     # track length (we don't use it)
+
+            lastevent = None
+
+            """ Parse the midi file. We have to parse off each event, even
+                though many will just be thrown away. You can't just skip around
+                in a midi file :)
+            """
+
+            while 1:
+                tm += self.mvarlen()        # adjust total offset by delta
+
+                ev=self.m8b()               # command byte
+
+                # if the command byte is < 0x80 then we are doing running status
+                if ev < 0x80:
+                    if not lastevent:
+                        error("Illegal running status in %s at $%06x"  % (filename, self.offset))
+                    self.offset -= 1
+                    ev=lastevent
+
+                sValue = ev>>4         # Shift MSBs to get a 4 bit value for the command
+                channel = ev & 0x0f    # and the channel number (0..15)
+                evptr = self.events[channel]
+
+                if sValue == 0x8:           # note off event
+                    evptr.append([tm, 'NoteOff', self.m8b(), self.m8b() ])
+
+                elif sValue == 0x9:         # note on event
+                    note=self.m8b()
+                    vel=self.m8b()
+                    # this needs to be conditional FIXME!
+                    if vel == 0:
+                        evptr.append([tm, 'NoteOff', note, vel])
+                    else:
+                        evptr.append([tm, 'NoteOn', note, vel])
+
+                elif sValue == 0xa:         # key pressure
+                    self.m8b()  # grab and ignore key pressure
+                    self.m8b()
+
+                elif sValue == 0xb:         # control change
+                    evptr.append([tm, 'Controller', self.m8b(), self.m8b() ])
+                    
+                elif sValue == 0xc:         # program change
+                    v = self.m8b()
+                    evptr.append( [tm, 'ProgChange', v])
+                    self.voices[channel] = v
+
+                elif sValue == 0xd:         # channel pressure
+                    evptr.append( [tm, 'ChannelPressure', self.m8b() ])
+
+                elif sValue == 0xe:         # pitch blend
+                    evptr.append([tm, 'PitchBend',  self.m8b()+(self.m8b()*128) ])
+
+                elif sValue == 0xf:      # system events
+                    if ev == 0xff:       # meta events
+                        a=self.m8b()
+                        stuff=self.chars(self.mvarlen())
+ 
+                        if a == 0x2f: # end of track
+                            evptr.append([tm, "EOT", stuff])
+                            break
+  
+                        elif a == 0x58: # time sig
+                            self.BperB = ord(stuff[0])
+                            self.timedenom = 2 ** ord(stuff[1])
+
+                        else:       # ignore anything else
+                            pass
+
+                    elif ev == 0xf0:    # system exclusive
+                        self.offset += self.mvarlen()
+ 
+                    elif ev == 0xf2:    # song position pointer, 2 bytes
+                        self.offset += 2
+
+                    elif ev == 0xf3:    # song select, 1 byte
+                        self.offset += 1
+
+                    else:       # all others are single byte commands
+                        pass
+
+                if ev >= 0x80 and ev <= 0xef:
+                    lastevent = ev
+
+        self.metanames.append( [tm, "EOF"])
+
+
+    def mvarlen(self):
+        """ Convert variable length midi value to int. """
+
+        x=0L
+        for i in range(4):
+
+            try:
+                byte=ord(self.midifile[self.offset])
+                self.offset += 1
+            except:
+                error("Invalid MIDI file include (varlen->int).")
+
+            if byte < 0x80:
+                x = ( x << 7 ) + byte
+                break
+            else:
+                x = ( x << 7 ) + ( byte & 0x7f )
+
+        return int(x)
+
+    # Class routines to grab bits of the midi
+
+    def chars(self, count):
+        """ Return 'count' chars from file (updates global pointer). """
+
+        bytes=self.midifile[self.offset:self.offset+count]
+        self.offset+=count
+        return bytes
+
+
+    def m8b(self):
+        """ Get 1 byte/8 bit value (updates global pointer). """
+
+        try:
+            byte = self.midifile[self.offset]
+            self.offset += 1
+        except:
+            error("Invalid MIDI file include (byte, offset=%s)." % self.offset)
+
+        return ord(byte)
+
+
+    def m32i(self):
+        """ Get 4 byte/32 bit integer. """
+
+        x = 0L
+        for i in range(4):
+            try:
+                byte = self.midifile[self.offset]
+                self.offset += 1
+            except:
+                error("Invalid MIDI file include (i32->int, offset=%s)." % self.offset)
+            x = (x << 8) + ord(byte)
+
+        return int(x)
+
+
+    def m16i(self):
+        """ Get 2 byte/16 bit integer. """
+
+        x = 0L
+        for i in range(2):
+            try:
+                byte = self.midifile[self.offset]
+                self.offset += 1
+            except:
+                error("Invalid MIDI file include (i16->int, offset=%s)." % self.offset)
+            x = (x << 8) + ord(byte)
+
+        return int(x)
+
+
+#####################################################
+# Routines for errors, usage, etc.
+
+def error(msg):
+    print "ERROR: %s" % msg
+    sys.exit(1)
+
+def usage():
+    print "mma-mnx.py - Extracts note events from MIDI files"
+    print "             for future inclusion into MMA files"
+    print "             using MidiNote (mnx==MidiNote eXtract)."
+    print "usage: mma-mnx.py INFILE [options]"
+    print "Options:"
+    print "   -h this screen"
+    print "   -v display version"
+    print "   -c CHANNEL channel to extract data"
+
+    sys.exit(1)
+
+def showversion():
+    print "0.1"
+    sys.exit(0)
+
+def doOpts():
+    """ Parse off the command line options. """
+
+    global channel, infile
+
+    try:
+        opts, args = getopt.gnu_getopt(sys.argv[1:], "hvc:", [])
+    except getopt.GetoptError:
+        usage()
+    for o, a in opts:
+
+        if o == "-v":
+            showversion()
+
+        elif o == "-h":
+            usage()
+
+        elif o == "-c":
+            channel = int(a)
+
+        else:
+            usage()
+
+    if len(args) != 1:
+        usage()
+
+    infile = args[0]  
+
+
+def chReport(mf):
+    """ Report number of channels, events. """
+
+    for a in range(0,16):
+        if len(mf.events[a]):
+            print "  Channel %02s  Total Events: %04s  Voice: %s" % \
+                (a+1, len(mf.events[a]), voiceNames[mf.voices[a]])
+    sys.exit(0)
+
+def chDump(mf):
+    """ Make up a list of recognized events for MMA midinote. """
+
+    events = mf.events[channel-1]
+    ons=[]
+    quarters=mf.beatDivision  # beats per quarter note
+
+    print "// Note data for %s. Offsets=Ticks  Duration=Ticks" % (infile)
+
+    # Go though track and change all offsets to MMA's 192 BperQ
+
+    if quarters != 192:
+        print "// MIDI file tick/beat of %s differs from MMA's 192." \
+           " Will try to compensate" % quarters
+
+        adjust = 192. / quarters
+        for i in xrange(len(events)):
+            events[i][0] = int(events[i][0] * adjust)
+        quarters = 192
+
+    beatBar = mf.BperB * quarters   # beats per bar
+    bprint=-1     # last bar number printed
+
+    for i,a in enumerate(events):
+        thisbar = int(a[0]/beatBar)
+
+        # Determine current bar number
+
+        if thisbar > bprint:
+            print "// %s" % thisbar
+            bprint=thisbar
+
+        if a[1] == 'NoteOn':
+            start=a[0]
+            end=-1
+            note=a[2]
+            for aa in events[i:]:
+                if aa[1]=='NoteOff' and aa[2]==note:
+                    end=aa[0]
+                    break
+            if end == -1:
+                end = start+1
+            dur = end-start
+
+            print "Note %d %d %d %d" % (a[0], note, a[3], dur )
+
+        elif a[1] == 'PitchBend':   # pitch bend
+            # NOTE, we subtract 8191 from the real value to keep
+            # our values -8191 to +8192.
+            print "PB %s %d " % (a[0], a[2]-8191)
+
+        elif a[1] == 'ChannelPressure':   # channel aftertouch
+            print "CHaT %s %s" % (a[0], a[2])
+
+        elif a[1] == 'Controller':   # controller
+            print "Ctrl %s %s %s" % (a[0], ctrlNames[a[2]], a[3])
+
+
+
+########################################################
+######  Start of mainline code.
+
+
+channel = 0     # midi channel to extract 1..16
+infile = ''     # name of the midi file
+
+doOpts()        # get command line options/filename
+
+mididata=MF(infile)
+
+if not mididata.BperB:
+    error("Expecting file to have valid time signature.")
+
+if channel == 0:
+    chReport(mididata)
+else:
+    chDump(mididata)
+
+# eof
diff --git a/debian/mma-mnx.1 b/debian/mma-mnx.1
new file mode 100644
index 0000000..87f5a1d
--- /dev/null
+++ b/debian/mma-mnx.1
@@ -0,0 +1,36 @@
+.TH mma-mnx 1
+.SH NAME
+mma-mnx  \- Convert MIDI file to MMA-readable form
+.SH SYNOPSIS
+.PP
+.B mma-mnx <somefile.mid>
+
+.SH DESCRIPTION
+
+This program is used to extract note and other data from an
+existing midi file in a format which the MMA MidiNote command
+understands.
+.PP
+If you just run the program on a file you will get a report as
+to the number of channels in the file, etc. 
+.PP
+To extract data use the -c option stating the midi channel for the
+data to extract. Note, Pitch Bend, Controller and Channel Aftertouch
+data will be printed for the specified channel. Save using redirect
+if you want. You can now use your favorite editor to import the data
+to your mma file.
+
+.SH SEE ALSO
+mma(1)
+
+.SH RESOURCES
+The latest version of this program is always distributed with
+.B MMA
+and is available at http://www.mellowood.ca/mma
+
+.SH AUTHOR
+Bob van der Poel <bob at mellowood.ca>
+.SH LICENSE
+mma-mnx is Copyright 2009 Bob van der Poel. Free use of this software is granted
+under the terms of the GNU General Public License.
+
diff --git a/util/mma-rm2std.py b/debian/mma-rm2std
similarity index 100%
copy from util/mma-rm2std.py
copy to debian/mma-rm2std
diff --git a/debian/mma-rm2std.1 b/debian/mma-rm2std.1
new file mode 100644
index 0000000..d856969
--- /dev/null
+++ b/debian/mma-rm2std.1
@@ -0,0 +1,30 @@
+.TH mma-rm2std 1
+.SH NAME
+mma-rm2std  \- Convert MIDI file to MMA-readable form
+.SH SYNOPSIS
+.PP
+.B mma-rm2std <mma-file>
+
+.SH DESCRIPTION
+
+This program reads a named mma file and converts Roman numeral
+chord notation to standard output. All other input is passed
+unchanged.
+.PP
+It shows how to access some of the mma library from other programs.
+It also shows that the MMA library functions should be converted
+to a real library! Oh well.
+
+.SH SEE ALSO
+mma(1)
+
+.SH RESOURCES
+The latest version of this program is always distributed with
+.B MMA
+and is available at http://www.mellowood.ca/mma
+
+.SH AUTHOR
+Bob van der Poel <bob at mellowood.ca>
+.SH LICENSE
+mma-rm2std is Copyright 2010 Bob van der Poel. Free use of this software is granted
+under the terms of the GNU General Public License.

-- 
mma packaging



More information about the pkg-multimedia-commits mailing list