aboutsummaryrefslogtreecommitdiff
path: root/elisp/emms-info-spc.el
diff options
context:
space:
mode:
authorbard <[email protected]>2023-10-08 15:17:31 -0400
committerbard <[email protected]>2023-10-08 15:17:31 -0400
commita2ec9082998918158df250c1906d0f6c0c4889db (patch)
tree52e42110cc407b7a142fb6216df0d4cf2f82da1c /elisp/emms-info-spc.el
parent16b4c9ed8f62dccce9a3ec32810077a9140f8925 (diff)
emms package
Diffstat (limited to 'elisp/emms-info-spc.el')
-rw-r--r--elisp/emms-info-spc.el95
1 files changed, 95 insertions, 0 deletions
diff --git a/elisp/emms-info-spc.el b/elisp/emms-info-spc.el
new file mode 100644
index 0000000..fd092a5
--- /dev/null
+++ b/elisp/emms-info-spc.el
@@ -0,0 +1,95 @@
+;;; emms-info-spc.el --- Native Emacs Lisp info method for EMMS -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; Author: Warren Wilkinson <[email protected]>
+
+;; This file is part of EMMS.
+
+;; EMMS is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; EMMS is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with EMMS; see the file COPYING. If not, write to the Free
+;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+;; MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; This file provides a native emms-info-method for SPC files. (well,
+;; actually the id666 tag embedded inside them). "Native" means a pure
+;; Emacs Lisp implementation instead of one relying on external tools
+;; or libraries.
+
+;;; Code:
+
+(require 'bindat)
+
+(defconst emms-info-spc--id666-magic-array
+ [#x53 #x4e #x45 #x53 #x2d #x53 #x50#x43 #x37 #x30 #x30 #x20 #x53 #x6f #x75 #x6e #x64 #x20 #x46 #x69 #x6c #x65 #x20 #x44 #x61 #x74 #x61 #x20 #x76 #x30 #x2e #x33 #x30]
+ "id666 header magic pattern `SNES-SPC700 Sound File Data v0.30'")
+
+(defconst emms-info-spc--id666-header-bindat-spec
+ '((file-identifier vec 33)
+ (eval (unless (equal last emms-info-spc--id666-magic-array)
+ (error "id666 framing mismatch: expected `%s', got `%s'"
+ emms-info-spc--id666-magic-array
+ last)))
+ (unused u16)
+ (has-id666 u8)
+ (revision u8)
+ (pc-reg u16)
+ (a-reg u8)
+ (x-reg u8)
+ (y-reg u8)
+ (psw-reg u8)
+ (sp-reg u8)
+ (res-reg u16)
+ (song-title strz 32)
+ (game-title strz 32)
+ (dumper strz 16)
+ (comment strz 32)
+ (date strz 11)
+ (fadeout vec 3)
+ (fadeout-length vec 5)
+ (artist strz 32))
+ "id666 header specification.
+
+Sources:
+
+- URL `https://ocremix.org/info/SPC_Format_Specification'
+- URL `https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html'")
+
+(defun emms-info-spc--decode-id666-header (filename)
+ "Read and decode id666 header from FILENAME."
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert-file-contents-literally filename nil 0 210)
+ (bindat-unpack emms-info-spc--id666-header-bindat-spec
+ (buffer-string))))
+
+(defun emms-info-spc--decode-id666 (filename)
+ "Read and decode id666 metadata from FILENAME.
+Return metadata in a list of (FIELD . VALUE) cons cells, or nil
+in case of errors or if there were no known fields in FILENAME."
+ (condition-case nil
+ (let ((header (emms-info-spc--decode-id666-header filename)))
+ (when (= 26 (bindat-get-field header 'has-id666))
+ (list
+ (cons 'info-title (bindat-get-field header 'song-title))
+ (cons 'info-album (bindat-get-field header 'game-title))
+ (cons 'info-artist (bindat-get-field header 'artist))
+ (cons 'info-composer (bindat-get-field header 'artist))
+ (cons 'info-note (bindat-get-field header 'comment)))))
+ (error nil)))
+
+(provide 'emms-info-spc)
+
+;;; emms-info-spc.el ends here