diff options
Diffstat (limited to 'emacs')
| -rw-r--r-- | emacs/.emacs.d/lisp/my/my-emms.el | 31 | ||||
| -rw-r--r-- | emacs/.emacs.d/lisp/my/my-spc.el | 144 | 
2 files changed, 170 insertions, 5 deletions
| diff --git a/emacs/.emacs.d/lisp/my/my-emms.el b/emacs/.emacs.d/lisp/my/my-emms.el index dadbb55..fa0ae17 100644 --- a/emacs/.emacs.d/lisp/my/my-emms.el +++ b/emacs/.emacs.d/lisp/my/my-emms.el @@ -39,7 +39,7 @@  (defun my-emms-mpv-toggle-video ()    (interactive)    (if (member "--no-video" emms-player-mpv-parameters) -      (progn  +      (progn          (setq emms-player-mpv-parameters                (remove "--no-video" emms-player-mpv-parameters))          (message "emms: video enabled!")) @@ -126,6 +126,14 @@                         playlist buffer-name)))      (and saved-buffer (emms-playlist-set-playlist-buffer saved-buffer)))) +(defun my-emms-add-directory-files-as-url (dir) +  "Add all files under directory DIR as file:// url." +  (mapc +   (lambda (file) +     (emms-add-url (format "file://%s" file))) +   (directory-files-recursively (expand-file-name dir) ".*")) +  ) +  (defun my-emms-add-all ()    (interactive)    (mapc 'my-emms-load-from-native my-emms-native-playlists) @@ -147,13 +155,13 @@ either 'audio or 'video      (emms-playlist-set-playlist-buffer to)      (with-current-buffer to (emms-playlist-clear))      (let ((emms-track-initialize-functions nil)) -      (my-emms-add-url-lists from        -       (alist-get type my-extension-types))) +      (my-emms-add-url-lists from +                             (alist-get type my-extension-types)))      (with-current-buffer to (emms-sort))))  (defvar my-emms-playlist-alist nil    "alist controlling playlists, where the cdr of each item is an also an alist, -with possible keys 'source and 'type.  +with possible keys 'source and 'type.  'source is a list of files of url lists.  'type is one of 'audio, 'video, or 'audiovideo") @@ -371,6 +379,19 @@ filter extensions from filter-exts."      (setq my-emms-albums-cache (vconcat album-list))      (message "Emms album cache updated."))) +(defun my-emms-get-random-album () +  "Returns a random album from the current playlist. + +We put a low weight on discovery album, currently any directory +under /zzz-seren/." +  (let ((album +         (elt my-emms-albums-cache (random (length my-emms-albums-cache))))) +    (while (and (string-match "/zzz-seren/" album) +                (>= (random 100) 4)) +      (setq album +            (elt my-emms-albums-cache (random (length my-emms-albums-cache))))) +    album)) +  (defun my-emms-random-album (update-album)    (interactive "P")    (with-current-emms-playlist @@ -380,7 +401,7 @@ filter extensions from filter-exts."      (let ((saved-position (point)))        (goto-char (point-min))        (if (search-forward -           (elt my-emms-albums-cache (random (length my-emms-albums-cache))) +           (my-emms-get-random-album)             nil t)            (emms-playlist-mode-play-current-track)          (goto-char saved-position) 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 | 
