> Yoni Rabkin <[email protected]> writes: > > Please write back when you get the OK from the copyright clerk.
Will do! > mpv also uses `emms-player-base-format-list', but using it is > optional. In any case, there is no problem with adding spc to that > list. I downloaded and tested mpv: mpv can also playback .spc files. > As for the rest, can you please split it out to a separate file such as > "emms-info-native-spc" or "emms-info-native-id666" or similar? That will > scale better as we add more native info methods. I've split it into emms-info-native-spc. I choose "-spc" over "-id666" because that's probably easier for a person trying to find the relevant code.
diff --git a/emms-info-native-spc.el b/emms-info-native-spc.el new file mode 100644 index 0000000..ebfde2c --- /dev/null +++ b/emms-info-native-spc.el @@ -0,0 +1,95 @@ +;;; emms-info-native-spc.el --- Native Emacs Lisp info method for EMMS -*- lexical-binding: t; -*- + +;; Copyright (C) 2023-2024 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-native-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-native-spc--id666-header-bindat-spec + '((file-identifier vec 33) + (eval (unless (equal last emms-info-native-spc--id666-magic-array) + (error "id666 framing mismatch: expected `%s', got `%s'" + emms-info-native-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-native-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-native-spc--id666-header-bindat-spec + (buffer-string)))) + +(defun emms-info-native-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-native-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-native-spc) + +;;; emms-info-native-spc.el ends here diff --git a/emms-info-native.el b/emms-info-native.el index 3e3e2d4..6c8bfff 100644 --- a/emms-info-native.el +++ b/emms-info-native.el @@ -51,6 +51,10 @@ ;; encryption are not supported. Based on id3v2 Informal Standards, ;; see URL `https://id3.org'. ;; +;; - SPC files with extension `.spc' and id666 tags. This is an audio +;; file based on a memory dump from an SPC700, a special audio chip +;; found within Super Nintendos. +;; ;; Format detection is based solely on filename extension, which is ;; matched case-insensitively. @@ -59,6 +63,7 @@ (require 'bindat) (require 'cl-lib) (require 'emms-info) +(require 'emms-info-native-spc) (require 'seq) (require 'subr-x) @@ -954,6 +959,8 @@ strings." (emms-info-native--decode-flac-comments filename)) ((eq stream-type 'mp3) (emms-info-native--decode-id3v2 filename)) + ((eq stream-type 'spc) + (emms-info-native-spc--decode-id666 filename)) (t nil)))) (defun emms-info-native--find-stream-type (filename) @@ -967,6 +974,7 @@ Return one of symbols `vorbis', `opus', `flac', or `mp3'." ((string-match ".opus$" filename) 'opus) ((string-match ".flac$" filename) 'flac) ((string-match ".mp3$" filename) 'mp3) + ((string-match ".spc$" filename) 'spc) (t nil)))) (provide 'emms-info-native) diff --git a/emms.el b/emms.el index 8581dfe..e003c72 100644 --- a/emms.el +++ b/emms.el @@ -376,7 +376,7 @@ Point will not be restored afterward." '("ogg" "mp3" "wav" "mpg" "mpeg" "wmv" "wma" "mov" "avi" "divx" "ogm" "ogv" "asf" "mkv" "rm" "rmvb" "mp4" "flac" "vob" "m4a" "ape" - "flv" "webm" "aif" "opus") + "flv" "webm" "aif" "opus" "spc") "A list of common formats which player definitions can use.")
