feat(users/Profpatsch/lyric/ext): add bpm on quantization
If the bpm header already exists, overwrite it with the new value. Also use an existing header as suggestion. Change-Id: If6431e8056504db437c31313d885b5ba0d0e55d5 Reviewed-on: https://cl.tvl.fyi/c/depot/+/12553 Tested-by: BuildkiteCI Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
		
							parent
							
								
									c014e39dfd
								
							
						
					
					
						commit
						102c9b30a7
					
				
					 1 changed files with 102 additions and 8 deletions
				
			
		| 
						 | 
					@ -164,12 +164,6 @@ async function shiftLyricsUp() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** first ask the user for the BPM of the track, then quantize the timestamps in the active text editor to the closest eighth note based on the given BPM */
 | 
					/** first ask the user for the BPM of the track, then quantize the timestamps in the active text editor to the closest eighth note based on the given BPM */
 | 
				
			||||||
async function quantizeLrc() {
 | 
					async function quantizeLrc() {
 | 
				
			||||||
  const bpm = await timeInputBpm();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (bpm === undefined) {
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const editor = vscode.window.activeTextEditor;
 | 
					  const editor = vscode.window.activeTextEditor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!editor) {
 | 
					  if (!editor) {
 | 
				
			||||||
| 
						 | 
					@ -179,6 +173,22 @@ async function quantizeLrc() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const ext = new Ext(editor.document);
 | 
					  const ext = new Ext(editor.document);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const startBpmStr = ext.findHeader('bpm')?.value;
 | 
				
			||||||
 | 
					  let startBpm;
 | 
				
			||||||
 | 
					  if (startBpmStr !== undefined) {
 | 
				
			||||||
 | 
					    startBpm = parseInt(startBpmStr, 10);
 | 
				
			||||||
 | 
					    if (isNaN(startBpm)) {
 | 
				
			||||||
 | 
					      startBpm = undefined;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const bpm = await timeInputBpm(startBpm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (bpm === undefined) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await ext.writeHeader('bpm', bpm.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getLine = (line: number) => ({
 | 
					  const getLine = (line: number) => ({
 | 
				
			||||||
    number: line,
 | 
					    number: line,
 | 
				
			||||||
    range: editor.document.lineAt(line),
 | 
					    range: editor.document.lineAt(line),
 | 
				
			||||||
| 
						 | 
					@ -214,9 +224,21 @@ async function quantizeLrc() {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// convert the given bpm to miliseconds
 | 
				
			||||||
 | 
					function bpmToMs(bpm: number) {
 | 
				
			||||||
 | 
					  return Math.floor((60 / bpm) * 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Show input boxes in a loop, and record the time between each input, averaging the last 5 inputs over a sliding window, then calculate the BPM of the average
 | 
					// Show input boxes in a loop, and record the time between each input, averaging the last 5 inputs over a sliding window, then calculate the BPM of the average
 | 
				
			||||||
async function timeInputBpm() {
 | 
					async function timeInputBpm(startBpm?: number) {
 | 
				
			||||||
  const timeDifferences: number[] = [500, 500, 500, 500, 500];
 | 
					  const startBpmMs = bpmToMs(startBpm ?? 120);
 | 
				
			||||||
 | 
					  const timeDifferences: number[] = [
 | 
				
			||||||
 | 
					    startBpmMs,
 | 
				
			||||||
 | 
					    startBpmMs,
 | 
				
			||||||
 | 
					    startBpmMs,
 | 
				
			||||||
 | 
					    startBpmMs,
 | 
				
			||||||
 | 
					    startBpmMs,
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
  // assign a weight to the time differences, so that the most recent time differences have more weight
 | 
					  // assign a weight to the time differences, so that the most recent time differences have more weight
 | 
				
			||||||
  const weights = [0.1, 0.1, 0.2, 0.3, 0.3];
 | 
					  const weights = [0.1, 0.1, 0.2, 0.3, 0.3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,6 +257,7 @@ async function timeInputBpm() {
 | 
				
			||||||
    const res = await vscode.window.showInputBox({
 | 
					    const res = await vscode.window.showInputBox({
 | 
				
			||||||
      prompt: `Press enter to record BPM (current BPM: ${calculateBPM()}), enter the final BPM once you know, or press esc to finish`,
 | 
					      prompt: `Press enter to record BPM (current BPM: ${calculateBPM()}), enter the final BPM once you know, or press esc to finish`,
 | 
				
			||||||
      placeHolder: 'BPM',
 | 
					      placeHolder: 'BPM',
 | 
				
			||||||
 | 
					      value: startBpm !== undefined ? startBpm.toString() : undefined,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    if (res === undefined) {
 | 
					    if (res === undefined) {
 | 
				
			||||||
      return undefined;
 | 
					      return undefined;
 | 
				
			||||||
| 
						 | 
					@ -398,6 +421,77 @@ class Ext {
 | 
				
			||||||
    const seconds = milliseconds / 1000;
 | 
					    const seconds = milliseconds / 1000;
 | 
				
			||||||
    return { milliseconds, seconds, text };
 | 
					    return { milliseconds, seconds, text };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Find a header line of the format
 | 
				
			||||||
 | 
					  // [header:value]
 | 
				
			||||||
 | 
					  // at the beginning of the lrc file (before the first empty line)
 | 
				
			||||||
 | 
					  findHeader(headerName: string) {
 | 
				
			||||||
 | 
					    for (let line = 0; line < this.document.lineCount; line++) {
 | 
				
			||||||
 | 
					      const text = this.document.lineAt(line).text;
 | 
				
			||||||
 | 
					      if (text.trim() === '') {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const match = text.match(/^\[(\w+):(.*)\]$/);
 | 
				
			||||||
 | 
					      if (match && match[1] === headerName) {
 | 
				
			||||||
 | 
					        return { key: match[1], value: match[2], line: line };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // check if the given line is a header line
 | 
				
			||||||
 | 
					  isHeaderLine(line: string) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      line.trim() !== '' &&
 | 
				
			||||||
 | 
					      line.match(/^\[(\w+):(.*)\]$/) !== null &&
 | 
				
			||||||
 | 
					      line.match(/^\[\d\d:\d\d.\d+\]/) === null
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // write the given header to the lrc file, if the header already exists, update the value
 | 
				
			||||||
 | 
					  async writeHeader(headerName: string, value: string) {
 | 
				
			||||||
 | 
					    const header = this.findHeader(headerName);
 | 
				
			||||||
 | 
					    const editor = findActiveEditor(this.document);
 | 
				
			||||||
 | 
					    if (!editor) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (header) {
 | 
				
			||||||
 | 
					      const lineRange = this.document.lineAt(header.line).range;
 | 
				
			||||||
 | 
					      await editor.edit(editBuilder => {
 | 
				
			||||||
 | 
					        editBuilder.replace(lineRange, `[${headerName}: ${value}]`);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // insert before the first timestamp line if no header is found, or after the last header if there are multiple headers
 | 
				
			||||||
 | 
					      let insertLine = 0;
 | 
				
			||||||
 | 
					      let extraNewline = '';
 | 
				
			||||||
 | 
					      for (let line = 0; line < this.document.lineCount; line++) {
 | 
				
			||||||
 | 
					        const text = this.document.lineAt(line).text;
 | 
				
			||||||
 | 
					        // check if header
 | 
				
			||||||
 | 
					        if (this.isHeaderLine(text)) {
 | 
				
			||||||
 | 
					          insertLine = line + 1;
 | 
				
			||||||
 | 
					        } else if (text.trim() === '') {
 | 
				
			||||||
 | 
					          insertLine = line;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          insertLine = line;
 | 
				
			||||||
 | 
					          if (line == 0) {
 | 
				
			||||||
 | 
					            extraNewline = '\n';
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      await editor.edit(editBuilder => {
 | 
				
			||||||
 | 
					        editBuilder.insert(
 | 
				
			||||||
 | 
					          new vscode.Position(insertLine, 0),
 | 
				
			||||||
 | 
					          `[${headerName}: ${value}]\n${extraNewline}`,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// find an active editor that has the given document opened
 | 
				
			||||||
 | 
					function findActiveEditor(document: vscode.TextDocument) {
 | 
				
			||||||
 | 
					  return vscode.window.visibleTextEditors.find(editor => editor.document === document);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function parseTimestamp(timestamp: string): number {
 | 
					function parseTimestamp(timestamp: string): number {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue