;;; cddb.el --- functions for doing things with CD-DA disc ids ;; Author: Noah Friedman ;; Created: 2020-09-24 ;; Public domain. ;;; Comment: ;; See https://en.wikipedia.org/wiki/CDDB ;; TODO: Fetch CD track info from gnudb.org ;;; Code: (require 'cl-lib) (defun cddb-discid (&rest starts) "Compute the CDDB1 hash id for an audio CD and return it as a string. Args should be the offset of the start of each track, in the form \"MM:SS:FF\" where MM are minutes, SS are seconds, and FF are hundredths of a second; or in frames where one frame is 1/75 of a second. The first arg is usually \"00:00:00\" or 0 \(the standard 2s or 150 frame lead-in is added automatically\). The final arg should be the total length (in MSF or frames) of the disc, which cannot be inferred from just the start times of the tracks, since there is no other indication of the length of the final track." (cl-flet ((msd2sec (lambda (msd) (setq msd (mapcar 'string-to-number (split-string msd ":"))) (floor (+ (* (nth 0 msd) 60) (+ (nth 1 msd) 0) (* (nth 2 msd) 0.01))))) (sum-digits (lambda (n) (let ((sum 0)) (while (> n 0) (setq sum (+ sum (% n 10)) n (/ n 10))) sum)))) (let* ((strats (reverse starts)) (total (if (stringp (car strats)) (msd2sec (car strats)) (/ (car strats) 75))) (secs (mapcar (lambda (s) (+ 2 (if (stringp s) (msd2sec s) (/ s 75)))) (cdr strats))) (sum (mapcar #'sum-digits secs))) (format "%02x%04x%02x" (% (apply '+ sum) 255) total (1- (length starts)))))) ;; This should return "970ae60c" ;;(let ((a (discid "00:00:00" "09:47:23" "11:39:05" "14:53:40" "17:01:53" ;; "20:44:25" "22:01:43" "23:32:69" "34:23:32" "37:35:29" ;; "39:30:42" "43:44:04" "46:30:27")) ;; (b (discid 0 44048 52430 67015 76628 93325 99118 105969 154757 ;; 169154 177792 196804 209277))) ;; (if (equal a b) ;; a ;; (list 'failed a b))) (provide 'cddb) ;;; cddb.el ends here.