Mercurial > hg > amuse
changeset 236:a5d065905f6d
Add midi-db.
Ignore-this: c6f4fc32efa4453ddbdc478793eedd52
A basic implementation for working with MIDI files stored in the database.
It is a test case for `versioned' data, but only partially implemented at the moment.
darcs-hash:20100223152703-16a00-4388d2720907d777a1c6c6b3a010885ce0fe06a7.gz
committer: Jamie Forth <j.forth@gold.ac.uk>
author | j.forth <j.forth@gold.ac.uk> |
---|---|
date | Thu, 24 Feb 2011 11:23:18 +0000 |
parents | ea45a3d0730c |
children | be5cd4c5ecc2 |
files | amuse-midi-db.asd implementations/midi-db/batch-midifiles-db.lisp implementations/midi-db/classes.lisp implementations/midi-db/db-insert-functions.lisp implementations/midi-db/db-select-functions.lisp implementations/midi-db/db-setup.lisp implementations/midi-db/examples/example.lisp implementations/midi-db/examples/importing-midifiles.lisp implementations/midi-db/methods.lisp implementations/midi-db/package.lisp |
diffstat | 10 files changed, 870 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/amuse-midi-db.asd Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,21 @@ +(asdf:defsystem amuse-midi-db + :name "amuse-midi-db" + :description "" + :depends-on ("amuse" "amuse-database-admin" "amuse-midi") + :components + ((:module implementations + :components + ((:module midi-db + :components + ((:file "package") + (:file "classes" :depends-on ("package")) + (:file "db-insert-functions" :depends-on ("package" + "classes")) + (:file "db-select-functions" :depends-on ("package" + "classes")) + (:file "db-setup" :depends-on ("package")) + (:file "batch-midifiles-db" :depends-on ("package" + "db-insert-functions" + "classes")) + (:file "methods" :depends-on ("classes")) + ))))))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/batch-midifiles-db.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,19 @@ +(cl:in-package #:amuse-midi-db) + +(defun import-midifiles (path collection-identifier database) + "<Path> should be a string or pathname object, which designates a + directory containing midifiles to be imported, + e.g. '/home/foo/my-midi-files/' (note trailing slash)." + (let ((midifile-paths + (append (directory (merge-pathnames path "*.mid*")) + (directory (merge-pathnames path "*.MID*"))))) + (unless midifile-paths + (warn "No midifiles in: ~A" path) + (return-from import-midifiles nil)) + (loop for midifile-path in midifile-paths + for i from 1 + do (import-composition + (get-composition + (make-midifile-identifier midifile-path)) + collection-identifier database) + finally (format t "~S midifiles added to database.~%" i))))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/classes.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,177 @@ +(cl:in-package #:amuse-midi-db) + +(defclass midi-db-object (amuse-object) ()) + +(defclass midi-db-identifier (identifier midi-db-object) ()) + +(defclass midi-db-collection-identifier (midi-db-identifier) + ((collection-id :initarg :collection-id + :accessor collection-id + :initform nil)) + (:documentation "Class to represent midi-db collection identifiers.")) + +(defun make-midi-db-collection-identifier (collection-id) + (make-instance 'midi-db-collection-identifier + :collection-id collection-id)) + +(defclass midi-db-composition-identifier (composition-identifier + midi-db-identifier) + ((composition-id :reader composition-id + :initarg :composition-id)) + (:documentation "Class to represent midi-db composition identifiers.")) + +(defun make-midi-db-composition-identifier (composition-id) + (make-instance 'midi-db-composition-identifier + :composition-id composition-id)) + +(defclass midi-db-composition (midi-composition midi-db-object) + ((collection-identifier :initarg :collection-identifier + :reader collection-identifier) + (filename :initarg :filename + :reader filename) + (owner :initarg :owner + :reader owner) + (version :initarg :version + :reader version) + (creation-timestamp :initarg :creation-timestamp + :reader creation-timestamp) + (deletion-timestamp :initarg :deletion-timestamp + :reader deletion-timestamp)) + (:documentation "Midi-db class with slots for additional database + fields. FIXME: This should perhaps be a subclass of 'versioned + constituents'?")) + +(defun make-midi-db-composition (events start duration tempi timesigs + keysigs identifier + collection-identifier timebase + filename owner version + creation-timestamp + deletion-timestamp) + "Make a midi-db composition. This does not do the usual +adjust-sequence initialisation (calling +%recompute-standard-composition-period). FIXME: Is this bad?" + (make-instance 'midi-db-composition + :%data events + :time start + :interval duration + :time-signatures timesigs + :tempi tempi + :key-signatures keysigs + :identifier identifier + :collection-identifier collection-identifier + :midi-timebase timebase + :filename filename + :owner owner + :version version + :creation-timestamp creation-timestamp + :deletion-timestamp deletion-timestamp)) + +(defmethod initialize-instance :after ((composition + midi-db-composition) &key) + "Initialize each event so that it knows what composition it belongs +to." + (sequence:dosequence (e composition t) + (%set-composition composition e))) + +(defclass midi-db-event (midi-db-object linked-event) + ((collection-identifier :initarg :collection-identifier + :reader collection-identifier) + (composition-identifier :initarg :composition-identifier + :reader composition-identifier) + (identifier :initarg :identifier + :reader identifier) + (version :initarg :version + :reader version))) + +(defclass midi-db-pitched-event (midi-pitched-event midi-db-event) + () + (:documentation "Midi-db class with slots for additional database + fields. FIXME: This should perhaps be a subclass of 'versioned + constituents'?")) + +(defclass midi-db-percussive-event (midi-percussive-event midi-db-event) + () + (:documentation "Midi-db class with slots for additional database + fields. FIXME: This should perhaps be a subclass of 'versioned + constituents'?")) + +(defun make-midi-db-pitched-event (collection-identifier + composition-identifier + event-identifier track channel + patch pitch velocity start duration + version &optional composition) + (make-instance 'midi-db-pitched-event + :collection-identifier collection-identifier + :composition-identifier composition-identifier + :identifier event-identifier + :track track + :channel channel + :patch patch + :number pitch + :velocity velocity + :time start + :interval duration + :version version + :composition composition)) + +(defun make-midi-db-percussive-event (collection-identifier + composition-identifier + event-identifier track channel + patch drum-sound velocity start + duration version &optional + composition) + (make-instance 'midi-db-percussive-event + :collection-identifier collection-identifier + :composition-identifier composition-identifier + :identifier event-identifier + :track track + :channel channel + :patch patch + :sound drum-sound + :velocity velocity + :time start + :interval duration + :version version + :composition composition)) + +(defclass midi-db-tempi (standard-tempo-period midi-db-object) + ((version :initarg :version + :reader version)) + (:documentation "FIXME: subclass versioned constituent")) + +(defun make-midi-db-tempo (start duration microsecs-per-crotchet version) + (make-instance 'midi-db-tempi + :time start + :interval duration + :bpm (microsecond-per-crotchet-to-bpm + microsecs-per-crotchet) + :version version)) + +(defclass midi-db-timesig (standard-time-signature-period + midi-db-object) + ((version :initarg :version + :reader version)) + (:documentation "FIXME: subclass versioned constituent")) + +(defun make-midi-db-timesig (start duration numerator denominator + version) + (make-instance 'midi-db-timesig + :time start + :interval duration + :numerator numerator + :denominator denominator + :version version)) + +(defclass midi-db-keysig (midi-key-signature-period + midi-db-object) + ((version :initarg :version + :reader version)) + (:documentation "FIXME: subclass versioned constituent")) + +(defun make-midi-db-keysig (start duration mode sharp-count version) + (make-instance 'midi-db-keysig + :time start + :interval duration + :mode mode + :sharp-count sharp-count + :version version))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/db-insert-functions.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,162 @@ +(cl:in-package #:amuse-midi-db) + +(defun register-new-collection (collection-name description database) + (clsql:with-transaction (:database database) + "Error checking needed for duplicates." + #.(clsql:locally-enable-sql-reader-syntax) + (clsql:insert-records + :into "midi_db_collections" + :attributes '([collection-name] + [description]) + :values (list collection-name description) + :database database) + #.(clsql:locally-disable-sql-reader-syntax) + (make-midi-db-collection-identifier ;return new collection identifier + (clsql-mysql::mysql-insert-id + (clsql-mysql::database-mysql-ptr + database))))) + +(defvar *import-file* (pathname "/tmp/midi-db.txt")) + +(defun import-composition (composition collection-identifier database) + #.(clsql:locally-enable-sql-reader-syntax) + (let* ((collection-id (collection-id collection-identifier)) + (filename (file-namestring (midifile-identifier-pathname + (identifier composition)))) + (timebase (midi-timebase composition)) + (start (* (timepoint composition) timebase)) + (duration (* (duration composition) timebase)) + (composition-id)) + ;; add composition header + (clsql:with-transaction (:database database) + (clsql:insert-records :into "midi_db_compositions" + :attributes '([collection-id] [filename] + [timebase] [start] [duration]) + :values (list collection-id + filename + timebase + start + duration) + :database database) + (setf composition-id (clsql-mysql::mysql-insert-id + (clsql-mysql::database-mysql-ptr + database))) + #.(clsql:locally-disable-sql-reader-syntax) + ;; add tempo, timesig and keysig constituents + (%add-tempo-constituents collection-id composition-id + (tempi composition) timebase database) + (%add-timesig-constituents collection-id composition-id + (time-signatures composition) + timebase database) + (%add-keysig-constituents collection-id composition-id + (key-signatures composition) timebase + database) + (write-to-db-file collection-id composition-id composition) + (clsql:execute-command + (concatenate 'string + "LOAD DATA LOCAL INFILE '" + (namestring *import-file*) + "' INTO TABLE " + "midi_db_events") + :database database) + (delete-file *import-file*) + (format t "Composition added to db, id: ~A~%" composition-id)))) + + +;;;===================================================================== +;;; All the below are just helper functions. +;;;===================================================================== + +(defun write-to-db-file (collection-id composition-id composition) + (let ((timebase (midi-timebase composition))) + (with-open-file (stream *import-file* + :direction :output + :if-exists :supersede + :external-format :latin1) + (sequence:dosequence (event composition) + (format stream + "~S ~S \\N ~{~S ~}1~%" ; 1 is the + ; version number + collection-id composition-id + (if (amuse-utils:pitchedp event) + (list (midi-track event) + (midi-channel event) + (midi-patch event) + (midi-pitch-number event) + (midi-velocity event) + (* (timepoint event) timebase) + (* (duration event) timebase)) + (list (midi-track event) + (midi-channel event) + 0 ;FIXME no patch for perc? + (midi-drum-sound event) + (midi-velocity event) + (* (timepoint event) timebase) + (* (duration event) timebase))))))) + t) + +;;; FIXME: use macros here. + +(defun %add-tempo-constituents (collection-id composition-id tempi timebase + database) + #.(clsql:locally-enable-sql-reader-syntax) + (loop ;with constituent-id + for tempo in tempi + do (clsql:insert-records :into "midi_db_tempi" + :attributes '([collection-id] + [composition-id] + [start] + [duration] + [microsecs-per-crotchet]) + :values (list collection-id + composition-id + (* (timepoint tempo) timebase) + (* (duration tempo) timebase) + (microseconds-per-crotchet + tempo)) + :database database)) + #.(clsql:locally-disable-sql-reader-syntax)) + +(defun %add-timesig-constituents (collection-id composition-id timesigs + timebase database) + #.(clsql:locally-enable-sql-reader-syntax) + (loop for timesig in timesigs + do (clsql:insert-records :into "midi_db_timesigs" + :attributes '([collection-id] + [composition-id] + [start] + [duration] + [numerator] + [denominator]) + :values (list collection-id + composition-id + (* (timepoint timesig) timebase) + (* (duration timesig) timebase) + (time-signature-numerator + timesig) + (time-signature-denominator + timesig)) + :database database)) + #.(clsql:locally-disable-sql-reader-syntax)) + +(defun %add-keysig-constituents (collection-id composition-id keysigs + timebase database) + #.(clsql:locally-enable-sql-reader-syntax) + (loop for keysig in keysigs + do (clsql:insert-records :into "midi_db_keysigs" + :attributes '([collection-id] + [composition-id] + [start] + [duration] + [mode] + [sharp-count]) + :values (list collection-id + composition-id + (* (timepoint keysig) timebase) + (* (duration keysig) timebase) + (key-signature-mode + keysig) + (key-signature-sharps + keysig)) + :database database)) + #.(clsql:locally-disable-sql-reader-syntax))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/db-select-functions.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,220 @@ +(cl:in-package #:amuse-midi-db) + +(defmethod get-composition ((identifier midi-db-composition-identifier)) + (let ((database *amuse-database*)) ; Shaddow this to use a different + ; database (for debugging). + (destructuring-bind (collection-id filename timebase start + duration owner version + creation-timestamp + deletion-timestamp) + (%get-midi-db-composition-header identifier database) + (let* ((collection-identifier (make-midi-db-collection-identifier + collection-id)) + (events (%get-midi-db-events identifier + collection-identifier + version timebase database)) + (tempi (%get-midi-db-tempi identifier + collection-identifier version + timebase database)) + (timesigs (%get-midi-db-timesigs identifier + collection-identifier + version timebase database)) + (keysigs (%get-midi-db-keysigs identifier + collection-identifier + version timebase database))) + (make-midi-db-composition events + (/ start timebase) + (/ duration timebase) + tempi + timesigs + keysigs + identifier + collection-identifier + timebase + filename + owner + version + creation-timestamp + deletion-timestamp))))) + + +(defun %get-all-collection-headers () + #.(clsql:locally-enable-sql-reader-syntax) + (let ((collection-rows (clsql:select [collection-id] + [collection-name] [description] + :from "midi_db_collections" + :flatp t + :database *amuse-database*))) + #.(clsql:locally-disable-sql-reader-syntax) collection-rows)) + +(defun %get-midi-db-composition-header (identifier database) + "Basic low-level retrieval of constituents. Just takes an identifier +and returns a header without any checking of version or deletion +fields." + #.(clsql:locally-enable-sql-reader-syntax) + (let ((header-row (car (clsql:select + [collection-id] + [filename] + [timebase] + [start] + [duration] + [owner] + [version] + [creation-timestamp] + [deletion-timestamp] + :from "midi_db_compositions" + :where [= [composition-id] + (composition-id identifier)] + :flatp t + :database database)))) + #.(clsql:locally-disable-sql-reader-syntax) + header-row)) + +(defun %get-all-collection-composition-headers (collection-identifier) + #.(clsql:locally-enable-sql-reader-syntax) + (let ((header-rows (clsql:select + [collection-id] + [filename] + [timebase] + [start] + [duration] + [owner] + [version] + [creation-timestamp] + [deletion-timestamp] + :from "midi_db_compositions" + :where [= [collection-id] (collection-id + collection-identifier)] + :flatp t + :database *amuse-database*))) + #.(clsql:locally-disable-sql-reader-syntax) + header-rows)) + +(defun %get-all-composition-headers () + #.(clsql:locally-enable-sql-reader-syntax) + (let ((header-rows (clsql:select + [collection-id] + [filename] + [timebase] + [start] + [duration] + [owner] + [version] + [creation-timestamp] + [deletion-timestamp] + :from "midi_db_compositions" + :flatp t + :database *amuse-database*))) + #.(clsql:locally-disable-sql-reader-syntax) + header-rows)) + +(defun %get-midi-db-events (identifier collection-identifier version + timebase database) + (let ((event-rows (clsql:query (concatenate 'string " +SELECT event_id, track, channel, patch, pitch, velocity, start, duration, +version +FROM midi_db_events +WHERE collection_id = " (princ-to-string (collection-id collection-identifier)) " +AND composition_id= " (princ-to-string (composition-id identifier)) " +AND version = " (princ-to-string version)) + :flatp t + :database database))) + (%init-events identifier collection-identifier event-rows timebase))) + +(defun %init-events (identifier collection-identifier event-rows timebase) + (loop for event-row in event-rows + collecting (init-midi-db-event identifier collection-identifier event-row timebase) + into events + finally (return events))) + +(defun init-midi-db-event (identifier collection-identifier event-row timebase) + (destructuring-bind (event-id track channel patch pitch velocity + start duration version) + event-row + (if (= channel 10) + (make-midi-db-percussive-event (collection-id collection-identifier) + (composition-id identifier) + event-id track channel patch + pitch velocity + (/ start timebase) + (/ duration timebase) version) + (make-midi-db-pitched-event (collection-id collection-identifier) + (composition-id identifier) + event-id track channel patch pitch + velocity (/ start timebase) + (/ duration timebase) version)))) + +(defun %get-midi-db-tempi (identifier collection-identifier version + timebase database) + (declare (ignore version)) + (let ((tempo-rows (clsql:query (concatenate 'string " +SELECT start, duration, microsecs_per_crotchet, version +FROM midi_db_tempi +WHERE collection_id = " (princ-to-string (collection-id collection-identifier)) " +AND composition_id = " (princ-to-string (composition-id identifier))) +;AND version = " (princ-to-string version)) + :flatp t + :database database))) + (%init-midi-db-tempi tempo-rows timebase))) + +(defun %init-midi-db-tempi (tempo-rows timebase) + (loop for tempo-row in tempo-rows + collecting (init-midi-db-tempo tempo-row timebase) + into tempi + finally (return tempi))) + +(defun init-midi-db-tempo (tempo-row timebase) + (destructuring-bind (start duration microsecs-per-crotchet version) + tempo-row + (make-midi-db-tempo (/ start timebase) (/ duration timebase) + microsecs-per-crotchet version))) + +(defun %get-midi-db-timesigs (identifier collection-identifier version + timebase database) + (declare (ignore version)) + (let ((timesig-rows (clsql:query (concatenate 'string " +SELECT start, duration, numerator, denominator, version +FROM midi_db_timesigs +WHERE collection_id = " (princ-to-string (collection-id collection-identifier)) " +AND composition_id = " (princ-to-string (composition-id identifier))) +;AND version = " (princ-to-string version)) + :flatp t + :database database))) + (%init-midi-db-timesigs timesig-rows timebase))) + +(defun %init-midi-db-timesigs (timesig-rows timebase) + (loop for timesig-row in timesig-rows + collecting (init-midi-db-timesig timesig-row timebase) + into timesigs + finally (return timesigs))) + +(defun init-midi-db-timesig (timesig-row timebase) + (destructuring-bind (start duration numerator denominator version) + timesig-row + (make-midi-db-timesig (/ start timebase) (/ duration timebase) + numerator denominator version))) + +(defun %get-midi-db-keysigs (identifier collection-identifier version + timebase database) + (declare (ignore version)) + (let ((keysig-rows (clsql:query (concatenate 'string " +SELECT start, duration, mode, sharp_count, version +FROM midi_db_keysigs +WHERE collection_id = " (princ-to-string (collection-id collection-identifier)) " +AND composition_id = " (princ-to-string (composition-id identifier))) +;AND version = " (princ-to-string version)) + :flatp t + :database database))) + (%init-midi-db-keysigs keysig-rows timebase))) + +(defun %init-midi-db-keysigs (keysig-rows timebase) + (loop for keysig-row in keysig-rows + collecting (init-midi-db-keysig keysig-row timebase) + into keysigs + finally (return keysigs))) + +(defun init-midi-db-keysig (keysig-row timebase) + (destructuring-bind (start duration mode sharp-count version) + keysig-row + (make-midi-db-keysig (/ start timebase) (/ duration timebase) + mode sharp-count version)))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/db-setup.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,160 @@ +(cl:in-package #:amuse-midi-db) + +;; Creating tables + +(defun create-midi-db-tables (database) + (%create-midi-collections-table database) + (%create-midi-compositions-table database) + (%create-midi-events-table database) + (%create-midi-tempi-table database) + (%create-midi-timesigs-table database) + (%create-midi-keysigs-table database)) + +(defun %create-midi-collections-table (database) + #.(clsql:locally-enable-sql-reader-syntax) + (clsql:create-table "midi_db_collections" + '(([|collection-id|] clsql:smallint :unsigned + :not-null :auto-increment :primary-key) + ([|collection-name|] (clsql:varchar 255) + :not-null) + ([|description|] (clsql:varchar 255) + :not-null)) + :database database + :transactions t) + #.(clsql:locally-disable-sql-reader-syntax)) + +(defun %create-midi-compositions-table (database) + (clsql:execute-command " +CREATE TABLE midi_db_compositions ( +collection_id SMALLINT UNSIGNED NOT NULL, +composition_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, +filename VARCHAR(255) NOT NULL, +timebase SMALLINT UNSIGNED NOT NULL, +start INT UNSIGNED NOT NULL, +duration INT UNSIGNED NOT NULL, +owner CHAR(16) NULL, +version SMALLINT UNSIGNED NOT NULL DEFAULT 1, +creation_timestamp TIMESTAMP NULL, +deletion_timestamp TIMESTAMP NULL, +INDEX midi_composition_index ( +collection_id, composition_id, version)) +engine = innodb;" + :database database) + (%create-midi-composition-header-triggers database)) + +(defun %create-midi-composition-header-triggers (database) + (clsql:execute-command " +CREATE TRIGGER pre_insert_comp BEFORE INSERT ON midi_db_compositions +FOR EACH ROW +BEGIN +SET NEW.owner = SUBSTRING_INDEX(USER(),'@',1); +SET NEW.creation_timestamp = CURRENT_TIMESTAMP; +END;" + :database database)) + +(defun %create-midi-events-table (database) + (clsql:execute-command " +CREATE TABLE midi_db_events ( +collection_id SMALLINT UNSIGNED NOT NULL, +composition_id SMALLINT UNSIGNED NOT NULL, +event_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, +track SMALLINT UNSIGNED NOT NULL, +channel TINYINT UNSIGNED NOT NULL, +patch TINYINT UNSIGNED NOT NULL, +pitch TINYINT UNSIGNED NOT NULL, +velocity TINYINT UNSIGNED NOT NULL, +start INTEGER UNSIGNED NOT NULL, +duration INTEGER UNSIGNED NOT NULL, +version SMALLINT UNSIGNED NOT NULL DEFAULT 1, +INDEX collection_composition (collection_id, composition_id)) +engine = innodb;" + :database database)) + +(defun %create-midi-tempi-table (database) + (clsql:execute-command " +CREATE TABLE midi_db_tempi ( +collection_id SMALLINT UNSIGNED NOT NULL, +composition_id SMALLINT UNSIGNED NOT NULL, +constituent_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, +start INT UNSIGNED NOT NULL, +duration INT UNSIGNED NOT NULL, +microsecs_per_crotchet INTEGER UNSIGNED NOT NULL, +version SMALLINT UNSIGNED NOT NULL DEFAULT 1, +INDEX collection_composition (collection_id, composition_id, constituent_id)) +engine = innodb;" + :database database)) + +(defun %create-midi-timesigs-table (database) + (clsql:execute-command " +CREATE TABLE midi_db_timesigs ( +collection_id SMALLINT UNSIGNED NOT NULL, +composition_id SMALLINT UNSIGNED NOT NULL, +constituent_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, +start INT UNSIGNED NOT NULL, +duration INT UNSIGNED NOT NULL, +numerator TINYINT UNSIGNED NOT NULL, +denominator TINYINT UNSIGNED NOT NULL, +version SMALLINT UNSIGNED NOT NULL DEFAULT 1, +INDEX collection_composition (collection_id, composition_id, constituent_id)) +engine = innodb;" + :database database)) + +(defun %create-midi-keysigs-table (database) + (clsql:execute-command " +CREATE TABLE midi_db_keysigs ( +collection_id SMALLINT UNSIGNED NOT NULL, +composition_id SMALLINT UNSIGNED NOT NULL, +constituent_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, +start INT UNSIGNED NOT NULL, +duration INT UNSIGNED NOT NULL, +mode TINYINT UNSIGNED NOT NULL, +sharp_count TINYINT UNSIGNED NOT NULL, +version SMALLINT UNSIGNED NOT NULL DEFAULT 1, +INDEX collection_composition (collection_id, composition_id, constituent_id)) +engine = innodb;" + :database database)) + +;; Deleting tables + +(defun drop-midi-db-tables (database) + (%drop-midi-collections-table database) + (%drop-midi-compositions-table database) + (%drop-midi-events-table database) + (%drop-midi-tempi-table database) + (%drop-midi-timesigs-table database) + (%drop-midi-keysigs-table database)) + +(defun %drop-midi-collections-table (database) + (clsql:drop-table "midi_db_collections" + :if-does-not-exist :ignore + :database database)) + +(defun %drop-midi-compositions-table (database) + (clsql:drop-table "midi_db_compositions" + :if-does-not-exist :ignore + :database database)) + +(defun %drop-midi-events-table (database) + (clsql:drop-table "midi_db_events" + :if-does-not-exist :ignore + :database database)) + +(defun %drop-midi-constituent-headers-table (database) + (clsql:drop-table "midi_db_constituent_headers" + :if-does-not-exist :ignore + :database database)) + +(defun %drop-midi-tempi-table (database) + (clsql:drop-table "midi_db_tempi" + :if-does-not-exist :ignore + :database database)) + +(defun %drop-midi-timesigs-table (database) + (clsql:drop-table "midi_db_timesigs" + :if-does-not-exist :ignore + :database database)) + +(defun %drop-midi-keysigs-table (database) + (clsql:drop-table "midi_db_keysigs" + :if-does-not-exist :ignore + :database database))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/examples/example.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,15 @@ +(cl:in-package #:amuse-midi-db) + +(connect-to-database :database-name "amuse") + +(list-collections *package*) + +(list-compositions *package*) ; FIXME: is it a good idea for this to + ; be general or not? + +(list-collections *package* :compositions t) ; list both collections + ; and compositions + +(defparameter *composition* + (get-composition (make-midi-db-composition-identifier 1))) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/examples/importing-midifiles.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,51 @@ +(cl:in-package #:amuse-midi-db) + +(connect-to-database :database-name "amuse" + :username "jamief") ; needs to be adequate permissions + +(create-midi-db-tables *amuse-database*) + +;(drop-midi-db-tables *amuse-database*) + +(register-new-implementation *package*) + + +;;;===================================================================== +;;; Import collections of drum loops (from Marcus) +;;;===================================================================== + +;;; Dangerous Drums +(let ((collection-identifier + (register-new-collection "Dangerous Drums" + "Collection of drum loops. Each 'composition' is a collection of loops on separate tracks." + *amuse-database*))) + + (import-midifiles + "/home/jamie/Music/MIDIFiles/MarcusMIDIFiles/DangerousDrums/" + collection-identifier + *amuse-database*)) + + +;;; LA Riot v1 +(let ((collection-identifier + (register-new-collection "LA Riot V1" + "Collection of drum loops. Each 'composition' is a collection of loops on separate tracks." + *amuse-database*))) + + (import-midifiles + "/home/jamie/Music/MIDIFiles/MarcusMIDIFiles/LARiotv1/" + collection-identifier + *amuse-database*)) + +;;; Midi breakbeats v8 +(let ((collection-identifier + (register-new-collection "MIDI Breakbeats V8" + "Collection of drum loops. Each 'composition' is a collection of loops on separate tracks." + *amuse-database*))) + + (import-midifiles + "/home/jamie/Music/MIDIFiles/MarcusMIDIFiles/MIDIBreakbeatsv8/" + collection-identifier + *amuse-database*)) + +(disconnect-from-database)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/methods.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,38 @@ +(cl:in-package #:amuse-midi-db) + +(defmethod list-collections ((package (eql *package*)) &key + compositions (stream *standard-output*)) + "FIXME: better formatting." + (let ((collection-rows (%get-all-collection-headers))) + (flet ((print-separator (&optional (columns 77)) + (format stream "~% ~A" + (make-sequence 'string columns :initial-element #\-)))) + (loop for collection-row in collection-rows + do (destructuring-bind (collection-id collection-name description) + collection-row + (format stream "~%Collection-id: ~A~% Name: ~A~% Description: ~A~%" + collection-id collection-name description) + (when compositions + (list-compositions package + :collection-identifier + (make-midi-db-collection-identifier + collection-id)))) + do (print-separator))))) + +(defmethod list-compositions ((package (eql *package*)) &key + collection-identifier + (stream *standard-output*)) + (let ((composition-headers + (if collection-identifier + (%get-all-collection-composition-headers + collection-identifier) + (%get-all-composition-headers)))) + (loop for composition-header in composition-headers + do (destructuring-bind (collection-id filename timebase start + duration owner version + creation-timestamp + deletion-timestamp) + composition-header + (format stream "~%Collection-id: ~A filename: ~A timebase: ~A start: ~A duration: ~A owner: ~A version: ~A created: ~A deleted: ~A~%" + collection-id filename timebase start duration owner + version creation-timestamp deletion-timestamp)))))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/implementations/midi-db/package.lisp Thu Feb 24 11:23:18 2011 +0000 @@ -0,0 +1,7 @@ +(cl:defpackage #:amuse-midi-db + (:use #:common-lisp #:amuse #:amuse-utils #:amuse-tools + #:amuse-midi #:amuse-database-admin) + (:export #:midi-db-composition-identifier + #:make-midi-db-composition-identifier + #:composition-id + ))