diff options
| author | Yuchen Pei <id@ypei.org> | 2023-08-19 18:16:32 +1000 | 
|---|---|---|
| committer | Yuchen Pei <id@ypei.org> | 2023-08-19 18:16:32 +1000 | 
| commit | 6f0796a53f2f8bd0027714796b9feac054bee313 (patch) | |
| tree | 12a25942d33f160cbcb83736175580f3e3de1525 /emacs/.emacs.d/lisp/my/my-spc.el | |
| parent | b9fb53c365c64c66e3f7fea05b54bec7f7d68100 (diff) | |
Adding a file handling snes spc music files.
Also update emms random album mechanism to assign low weight to the
discovery directory
Diffstat (limited to 'emacs/.emacs.d/lisp/my/my-spc.el')
| -rw-r--r-- | emacs/.emacs.d/lisp/my/my-spc.el | 144 | 
1 files changed, 144 insertions, 0 deletions
| diff --git a/emacs/.emacs.d/lisp/my/my-spc.el b/emacs/.emacs.d/lisp/my/my-spc.el new file mode 100644 index 0000000..a6ecab3 --- /dev/null +++ b/emacs/.emacs.d/lisp/my/my-spc.el @@ -0,0 +1,144 @@ +;;; my-spc.el -- handling spc files -*- lexical-binding: t -*- + +;; Copyright (C) 2023 Free Software Foundation. + +;; Author: Yuchen Pei <id@ypei.org> +;;         Warren Wilkinson <warrenwilkinson@gmail.com> +;; Maintainer: Yuchen Pei <id@ypei.org> +;; Package-Requires: ((emacs "28")) + +;; This file is part of dotted. + +;; dotted is free software: you can redistribute it and/or modify it under +;; the terms of the GNU Affero General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; dotted 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 Affero General +;; Public License for more details. + +;; You should have received a copy of the GNU Affero General Public +;; License along with dotted.  If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; handling spc files. + +;;; Code: + +(require 'bindat) + +(defconst my-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 my-spc--id666-header-bindat-spec +  '((file-identifier vec 33) +    (eval (unless (equal last my-spc--id666-magic-array) +            (error "id666 framing mismatch: expected `%s', got `%s'" +                   my-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 my-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 my-spc--id666-header-bindat-spec +                   (buffer-string)))) + +(defun my-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 (my-spc--decode-id666-header filename))) +        (when (= 26 (bindat-get-field header 'has-id666)) +          `( +            (title . ,(bindat-get-field header 'song-title)) +            (album . ,(bindat-get-field header 'game-title)) +            (artist . ,(bindat-get-field header 'artist)) +            (comment . ,(bindat-get-field header 'comment)) +            (dumper . ,(bindat-get-field header 'dumper)) +            (date . ,(bindat-get-field header 'date)) +            (fadeout . ,(bindat-get-field header 'fadeout)) +            (fadeout-length . ,(bindat-get-field header 'fadeout)) +            (extension . ,(file-name-extension filename)) +            (number . ,(replace-regexp-in-string +                        "[^-]+-" "" +                        (file-name-base filename))) +            ))) +    (error nil))) + +(defun my-spc-format-file-name (file) +  "Format a filename from an spc FILE. + +artist/album/title (note).extension" +  (when-let* ((metadata (my-spc-decode-id666 file)) +              (artist (alist-get 'artist metadata)) +              (album (alist-get 'album metadata)) +              (title (alist-get 'title metadata)) +              (extension (alist-get 'extension metadata)) +              (number (alist-get 'number metadata))) +    (if (or (string-empty-p artist) +            (string-empty-p album) +            (string-empty-p title) +            (string-empty-p extension) +            (string-empty-p number)) +        nil +      (format "%s/%s/%s %s.%s" artist album number title extension)))) + +(defun my-spc-file-rename (dir) +  "Rename all spc files under DIR using dired." +  (let ((pairs +         (seq-filter +          'cdr +          (mapcar +           (lambda (file) +             (cons (expand-file-name file) +                   (format "%s/%s" +                           (expand-file-name my-audio-incoming-dir) +                           (my-spc-format-file-name file)))) +           (directory-files-recursively dir "\\`.*\\.spc\\'"))))) +    (when (y-or-n-p +           (print +            (format +             "Will do the following renaming: %s\nContinue?" +             (string-join +              (mapcar (lambda (pair) +                        (format "%s -> %s" (car pair) (cdr pair))) +                      pairs) +              "\n")))) +      (mapc +       (lambda (pair) +         (dired-rename-file (car pair) (cdr pair) t)) +       pairs)))) + +(provide 'my-spc) +;;; my-spc.el ends here | 
