lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: address@hidden Lilypond Comments!


From: svoboda
Subject: Re: address@hidden Lilypond Comments!
Date: 30 Jun 2004 14:46:16 -0400
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

address@hidden writes:

> Hello, I have used Lilypond just last week to create a few musical
> scores (pop music with a chordline, melody line, and lyrics).
> 
> Anyway I have some comments regarding usage, mainly the problems I
> encountered. I can possibly fix them given some encouragement...mainly
> I want to know if anything has been done to address these problems?
> 
> (I'm using LilyPond 2.2 on both RH9 Linux and Windows XP)
> 
> 
> -> I use | a lot to separate measures, and am always running up
> against the "| not at a measure boundary" warning...obviously I am
> constantly having notes/measures between bars that don't add up to the
> time signature. This was a major slowdown and pain to deal with...I'd
> like to figure out some way to fix this problem.
> 
> One notion I have is an addition to LilyPond's emacs mode that
> operates similar to Emacs's column-mode (which automatically displays
> the cursor's column number on the modeline). This addition would
> simply indicate on the modeline just what beat the cursor is on...or
> rather how many beats lie between the cursor and the previous | or {.
> 
> With that in place, I could prevent those measure boundary warnings,
> b/c I would know how 'full' each measure was when I type it in.
> 
> Has anyone attacked this problem? I could be convinced to work on a
> patch if no one else has...
<snip>

Since no one else has attacked this problem, I figured I'd take a
whack at it. My results are appended to this message. Going to try it
for a few days & see how well it works. To use it, I tweaked my .emacs
file as follows:

    (load-library "lilypond-init.el") ; already there
    (load "/usr0/svoboda/sw/elisp/what-beat.el") ; this file
    (add-hook 'LilyPond-mode-hook (lambda () (local-set-key "\C-cb" 
'what-beat)))

Hence 'C-c b' displays the current beat in the minibuffer; displayed
as a ratio. i.e. if it shows 3/8, it means there are the equivalent of
3 eighth notes between the point and the last measure indicator (|).

Comments? Buggestions?

-- 
David Svoboda                    address@hidden
Senior Research Programmer       http://www.cs.cmu.edu/~svoboda
Language Technologies Institute  Practice Kind Randomness and
Carnegie Mellon University       Beautiful Acts of Nonsense

-----
(setq pitch-regex "\\([a-z]+[,']*\\(=[,']\\)?\\)\\|<[^>]*>")
(setq duration-regex "\\([ \t]*\\(128\\|6?4\\|3?2\\|16?\\|8\\)\\([.]*\\)\\([ 
\t]*[*][ \t]*\\([0-9]+\\)\\(/\\([1-9][0-9]*\\)\\)?\\)?\\)")

(defun extract-match (string match-num)
  (if (null (match-beginning match-num))
      nil
    (substring string (match-beginning match-num) (match-end match-num))))


(defun add-fractions (f1 f2)
  "Adds two fractions, both are (numerator denominator)"
  (set 'result (list (+ (* (car f1) (cadr f2)) (* (car f2) (cadr f1)))
                     (* (cadr f1) (cadr f2))))
  (set 'result (reduce-fraction result 2))
  (set 'result (reduce-fraction result 3))
  (set 'result (reduce-fraction result 5))
  (set 'result (reduce-fraction result 7))
)


(defun reduce-fraction (f divisor)
  "Eliminates divisor from fraction if present"
  (while (and (= 0 (% (car result) divisor))
              (= 0 (% (cadr result) divisor))
              (< 1 (cadr result))
              (< 0 (car result)))
    (set 'result (list (/ (car result) divisor) (/ (cadr result) divisor))))
  result
)


(defun parse-duration (duration)
  "Returns a duration string parsed as '(numerator denominator)"
  (string-match duration-regex duration)
  (let ((result (list 1 (string-to-int (extract-match duration 2))))
        (dots (extract-match duration 3))
        (numerator (or(extract-match duration 5) "1"))
        (denominator (or (extract-match duration 7) "1")))
    (if (and (not (null dots)) (< 0 (string-width dots)))
        (dotimes (dummy (string-width dots))
          (set 'result (list (1+ (* 2 (car result))) (* 2 (cadr result))))))
    (list (* (string-to-int numerator) (car result))
          (* (string-to-int denominator) (cadr result)))
))


(defun walk-note-duration ()
"Returns duration of next note, moving point past note.
If point is not before a note, returns nil
If next note has no duration, returns t"
  (if (not (looking-at pitch-regex))
      nil
    (progn
      (goto-char (match-end 0))
      (if (not (looking-at duration-regex))
          t
        (progn
          (goto-char (match-end 0))
          (parse-duration(match-string 0)))))))


(defun get-beat ()
  (save-excursion
    (save-restriction
      (let* ((end (point))
             (measure-start (or(re-search-backward "\|" 0 t) 0))
             (last-dur (or(re-search-backward duration-regex 0 t) 0))
             (duration (parse-duration(match-string 0)))
             (result '(0 1))) ; 0 in fraction form
        (if (= measure-start 0)
            (error "No | before point")
            (progn
              (goto-char (1+ measure-start))
              (skip-chars-forward " \t\n")
              (while (< (point) end)
                (set 'new-duration (walk-note-duration))
                (if (null new-duration)
                    (if (looking-at "\\\\times[ \t]*\\([1-9]*\\)/\\([1-9]*\\)[ 
\t\n]*{")
                        (let ((numerator (string-to-int(match-string 1)))
                              (denominator (string-to-int(match-string 2))))
                          (goto-char (match-end 0))
                          (skip-chars-forward " \t\n")
                          (while (and (not (looking-at "}"))
                                      (< (point) end))
                            (set 'new-duration (walk-note-duration))
                            (if (null new-duration)
                                (if (looking-at "\\\\[a-z]*[ \t]*[a-z]*")
                                    (goto-char (match-end 0))
                                  (error "Unknown text: %S %s" 
result(buffer-substring (point) end))))
                            (if (not (eq new-duration t))
                                (set 'duration new-duration))
                            (set 'result (add-fractions result
                                                       (list (* numerator (car 
duration))
                                                             (* denominator 
(cadr duration)))))
                            (skip-chars-forward " \t\n"))
                          (if (< (point) end)
                              (forward-char 1))) ; skip }
                      (if (looking-at "\\\\[a-z]*[ \t]*[a-z]*")
                          (goto-char (match-end 0))
                        (error "Unknown text: %S %s" result(buffer-substring 
(point) end))))
                  (if (not (eq new-duration t))
                      (set 'duration new-duration))
                  (set 'result (add-fractions result duration)))
                (skip-chars-forward " \t\n"))

              result
))))))

(defun what-beat ()
  "Returns how much of a measure lies between last measaure '|' and point.
Recognizes chords, triples, and /clef & other context words."
  (interactive)
  (let ((beat (get-beat)))
    (message "%d/%d" (car beat) (cadr beat)))
)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]