feat(users/Profpatsch/lyric): add vscode extension & helpers

* tap-bpm: simple CLI program that accepts key inputs and averages a
BPM value

* lyric-timing-mpv-script: If you press Ctrl+l, mpv attaches the
  current timestamp to a .lrc file named after the song.
  This is for manually timing missing songs for uploading them to
  https://lrclib.net/

* extension: vscode extension for `.lrc` files, currently with the
  following features:

    1. A “jump to LRC position” command which reads an .lrc timestamp
    from the current line and expects mpv to listen on
    `~/tmp/mpv-socket` (via `--input-ipc-server`), and will seek to
    the exact timestamp (down to the ms) in the currently playing
    song.

    2. Some initial linting warnings

      - A lint that warns if the difference to the next timestamp is
      more than 10s (which usually means there’s an instrumental and
      the previous line is stuck)

      - A lint that checks that timestamps are monotonically
      increasing

Change-Id: I32a4ac0e2c5bbe3d94e45ffcf647f81bc7c08aa0
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12537
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
Profpatsch 2024-09-28 01:30:49 +02:00
parent 970dcaa04f
commit 9bec21ea1c
17 changed files with 643 additions and 0 deletions

View file

@ -0,0 +1,16 @@
import { tapBpm } from "./tap-bpm.js";
async function main() {
// subcommand for tap-bpm
if (process.argv[2] === "tap-bpm") {
await tapBpm();
}
}
await main();
// sleep in a loop to block nodejs
console.log("Blocking event loop...");
while (true) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}

View file

@ -0,0 +1,79 @@
// create a node command line listener that allows the user to press any key , and averages the distances between the key presses to determine the BPM (with a window of 4 key presses). If the user presses q, the program should exit and print the final BPM.
// Import the necessary modules
import * as readline from "readline";
export function tapBpm() {
// Set up readline interface to listen for keypresses
readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);
// accept SIGINT on stdin
// Array to store the time differences between the last 4 key presses
const timeDifferences: number[] = [];
let lastPressTime: number | null = null;
// Function to calculate BPM based on average time between keypresses
function calculateBPM() {
if (timeDifferences.length < 1) {
return 0;
}
const averageTimeDiff =
timeDifferences.reduce((acc, curr) => acc + curr, 0) /
timeDifferences.length;
return (60 * 1000) / averageTimeDiff;
}
// Handle the SIGINT (Ctrl+C) event manually
process.on("SIGINT", () => {
console.log(
"\nExiting via SIGINT (Ctrl+C)... Final BPM:",
calculateBPM().toFixed(2)
);
process.exit();
});
// Listen for keypress events
process.stdin.on("keypress", (str, key) => {
// Exit if 'q' is pressed
if (key.name === "q") {
console.log("Exiting... Final BPM:", calculateBPM().toFixed(2));
process.exit();
}
// Handle Ctrl+C (SIGINT)
if (key.sequence === "\u0003") {
// '\u0003' is the raw code for Ctrl+C
console.log(
"\nExiting via Ctrl+C... Final BPM:",
calculateBPM().toFixed(2)
);
process.exit();
}
// Capture the current time of the keypress
const currentTime = Date.now();
// If it's not the first keypress, calculate the time difference
if (lastPressTime !== null) {
const timeDiff = currentTime - lastPressTime;
// Add the time difference to the array (limit to last 10 key presses)
if (timeDifferences.length >= 10) {
timeDifferences.shift(); // Remove the oldest time difference
}
timeDifferences.push(timeDiff);
// Calculate and display the BPM
const bpm = calculateBPM();
console.log("Current BPM:", bpm.toFixed(2));
} else {
console.log("Waiting for more key presses to calculate BPM...");
}
// Update the lastPressTime to the current time
lastPressTime = currentTime;
});
console.log('Press any key to calculate BPM, press "q" to quit.');
}