diff musiccutter.py @ 31:ea98c9507f47

Preliminary multi-page support. Breaks time marks though.
author Daniel O'Connor <darius@dons.net.au>
date Tue, 03 May 2016 18:04:41 +0930
parents f46cc9401e79
children 1d5dcaa3b07d
line wrap: on
line diff
--- a/musiccutter.py	Tue May 03 09:10:33 2016 +0930
+++ b/musiccutter.py	Tue May 03 18:04:41 2016 +0930
@@ -25,7 +25,7 @@
     m.processMidi(filename, base + '-%02d.pdf')
 
 class Midi2PDF(object):
-    def __init__(self, notefile, pagewidth, pageheight, pitch, slotsize, heel, leadin, timemarks, trytranspose, drawrect, notenames, notelines, noteoffset, timescale, notescale, fontname, fontsize):
+    def __init__(self, notefile, pagewidth, pageheight, pitch, slotsize, heel, leadin, timemarks, trytranspose, drawrect, notenames, notelines, noteoffset, pagesperpdf, timescale, notescale, fontname, fontsize):
         self.midi2note, self.note2midi = Midi2PDF.genmidi2note()
         self.note2slot, self.slot2note = Midi2PDF.loadnote2slot(notefile, self.note2midi)
         self.pagewidth = pagewidth # Dimensions are in millimetres
@@ -40,11 +40,14 @@
         self.notenames = notenames # Draw note names on the right edge
         self.notelines = notelines # Draw line rulers
         self.noteoffset = noteoffset # Amount to adjust note pitches by (+12 = 1 octave)
+        self.pagesperpdf = pagesperpdf # Number of pages to emit per PDF
         self.timescale = timescale # Width per second
         self.notescale = notescale # Multiply all note lengths by this (to get rearticulation)
         self.fontname = fontname
         self.fontsize = fontsize # Points
 
+        self.pdfwidth = self.pagewidth * self.pagesperpdf
+
     def processMidi(self, midifile, outpat):
         playablecount = 0
         unplayablecount = 0
@@ -57,10 +60,13 @@
             channels.append({})
 
         npages = int(math.ceil(((midi.length * self.timescale) + self.leadin) / self.pagewidth))
-        print 'npages', npages
+        npdfs = int(math.ceil(float(npages) / self.pagesperpdf))
+        print 'npages %d, npdfs %d' % (npages, npdfs)
+
         pdfs = []
-        for i in range(npages):
-            pdf = reportlab.pdfgen.canvas.Canvas(file(outpat % (i + 1), 'w'), pagesize = (self.pagewidth * mm, self.pageheight * mm))
+        for i in range(npdfs):
+            pdf = reportlab.pdfgen.canvas.Canvas(file(outpat % (i + 1), 'w'),
+                                                 pagesize = (self.pdfwidth * mm, self.pageheight * mm))
             pdfs.append(pdf)
 
         title = os.path.basename(midifile)
@@ -126,21 +132,27 @@
             print 'Transpose down:', transposedowncount
             print 'Transpose up:', transposeupcount
 
-        for pindx in range(len(pdfs)):
-            pdf = pdfs[pindx]
+        for pindx in range(npages):
+            pdf = pdfs[pindx / self.pagesperpdf] # PDF for this page
+            # Offset into PDF where the page starts
+            pageofs = self.pagewidth * (self.pagesperpdf - (pindx % self.pagesperpdf) - 1)
             # Add title and page number
-            Midi2PDF.textHelper(pdf, 0 * mm, 1 * mm, ENGRAVE_COLOUR, True, self.fontname, self.fontsize, '%s (%d / %d)' % (title, pindx + 1, npages))
-
+            Midi2PDF.textHelper(pdf, pageofs * mm, 1 * mm,
+                                ENGRAVE_COLOUR, True, self.fontname, self.fontsize,
+                                '%s (%d / %d)' % (title, pindx + 1, npages))
+            pdf.saveState()
             pdf.setLineWidth(0)
 
-            # Draw time marks
+            # Draw time marks every 5 seconds
             if self.timemarks:
+                pdfidx = pindx / self.pagesperpdf
+                # Work out start and end times (pdf 1 is special due to leadin)
                 tstart = self.leadin / self.timescale
-                tend = self.pagewidth / self.timescale
+                tend = (self.pagewidth * self.pagesperpdf) / self.timescale
                 if pindx > 0:
-                    tsize = self.pagewidth / self.timescale
-                    tstart = tend + tsize * pindx
-                    tend = tend + tsize * (pindx + 1)
+                    tsize = self.pagewidth  / self.timescale # Amount of time per pdf
+                    tstart = tend + tsize * pdfidx
+                    tend = tend + tsize * (pdfidx + 1)
                 for s in range(tstart, tend, 5):
                     x = self.pagewidth - (float(s * self.timescale + self.leadin) % self.pagewidth)
                     pdf.line(x * mm, self.heel, x * mm, self.pageheight * mm)
@@ -148,18 +160,19 @@
 
             # Draw rectangle around page (upper and right hand ends don't seem to render though)
             if self.drawrect:
-                pdf.rect(0, 0, self.pagewidth * mm, self.pageheight * mm, fill = False, stroke = True)
+                pdf.rect((pindx % self.pagesperpdf) * self.pagewidth * mm, 0,
+                         self.pagewidth * mm, self.pageheight * mm, fill = False, stroke = True)
 
             # Draw lines per note
             for slot in sorted(self.slot2note.keys()):
                 ofs = self.pageheight - (self.heel + slot * self.pitch) - self.slotsize / 2
                 if self.notelines:
-                    pdf.line(0, ofs * mm, self.pagewidth * mm, ofs * mm)
+                    pdf.line(0, ofs * mm, self.pdfwidth * mm, ofs * mm)
                 # Note name
                 if self.notenames:
-                    Midi2PDF.textHelper(pdf, (self.pagewidth - 10) * mm, (ofs + 0.5) * mm, ENGRAVE_COLOUR, False, self.fontname, self.fontsize, self.slot2note[slot])
-
-            # Save PDF
+                    Midi2PDF.textHelper(pdf, (self.pdfwidth - 10) * mm, (ofs + 0.5) * mm, ENGRAVE_COLOUR, False, self.fontname, self.fontsize, self.slot2note[slot])
+            pdf.restoreState()
+        for pdf in pdfs:
             pdf.save()
 
     # http://newt.phys.unsw.edu.au/jw/notes.html
@@ -198,24 +211,24 @@
 
     def emitnote(self, pdfs, slot, start, notelen):
         x = start * self.timescale + self.leadin # Convert start time to distance
-        pageidx = int(x / self.pagewidth) # Determine which page
-        x = x % self.pagewidth # and where on that page
+        pdfidx = int(x / self.pdfwidth) # Determine which pdf
+        x = x % self.pdfwidth # and where on that pdf
         h = self.slotsize
         y = self.pageheight - (self.heel + slot * self.pitch - self.slotsize / 2) - self.slotsize
         w = notelen * self.timescale # Convert note length in time to distance
 
-        print 'page = %d x = %.3f y = %.3f w = %.3f h = %.3f' % (pageidx, x, y, w, h)
+        print 'pdf = %d x = %.3f y = %.3f w = %.3f h = %.3f' % (pdfidx, x, y, w, h)
         w1 = w
-        # Check if the note crosses a page
-        if x + w > self.pagewidth:
-            w1 = self.pagewidth - x # Crop first note
+        # Check if the note crosses a pdf
+        if x + w > self.pdfwidth:
+            w1 = self.pdfwidth - x # Crop first note
             w2 = w - w1 # Calculate length of second note
-            assert w2 <= self.pagewidth, 'note extends for more than a page'
+            assert w2 <= self.pdfwidth, 'note extends for more than a pdf'
             # Emit second half of note
-            print 'split note, page %d w2 = %.3f' % (pageidx + 1, w2)
-            Midi2PDF._emitnote(pdfs[pageidx + 1], self.pagewidth - w2, y, w2, h)
+            print 'split note, pdf %d w2 = %.3f' % (pdfidx + 1, w2)
+            Midi2PDF._emitnote(pdfs[pdfidx + 1], self.pdfwidth - w2, y, w2, h)
 
-        Midi2PDF._emitnote(pdfs[pageidx], self.pagewidth - x - w1, y, w1, h)
+        Midi2PDF._emitnote(pdfs[pdfidx], self.pdfwidth - x - w1, y, w1, h)
 
     @staticmethod
     def _emitnote(pdf, x, y, w, h):