[prev in list] [next in list] [prev in thread] [next in thread] 

List:       lilypond-user
Subject:    Re: [svoboda@mandal.lti.cs.cmu.edu] Lilypond Comments!
From:       svoboda () mandal ! lti ! cs ! cmu ! edu
Date:       2004-06-30 18:46:16
Message-ID: uwifz8cq3yf.fsf () mandal ! lti ! cs ! cmu ! edu
[Download RAW message or body]

svoboda@mandal.lti.cs.cmu.edu 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                    arslan_ibn_daud@yahoo.com
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)))
)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic