diff --git a/packages/core/hap.mjs b/packages/core/hap.mjs index a6e3c55a..5f820d64 100644 --- a/packages/core/hap.mjs +++ b/packages/core/hap.mjs @@ -4,6 +4,7 @@ Copyright (C) 2022 Strudel contributors - see . */ import Fraction from './fraction.mjs'; +import { stringifyValues } from './util.mjs'; export class Hap { /* @@ -148,13 +149,7 @@ export class Hap { } showWhole(compact = false) { - return `${this.whole == undefined ? '~' : this.whole.show()}: ${ - typeof this.value === 'object' - ? compact - ? JSON.stringify(this.value).slice(1, -1).replaceAll('"', '').replaceAll(',', ' ') - : JSON.stringify(this.value) - : this.value - }`; + return `${this.whole == undefined ? '~' : this.whole.show()}: ${stringifyValues(this.value, compact)}`; } combineContext(b) { diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 4168645b..dbf1b17f 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -21,6 +21,7 @@ import { numeralArgs, parseNumeral, pairs, + stringifyValues, } from './util.mjs'; import drawLine from './drawLine.mjs'; import { logger } from './logger.mjs'; @@ -852,14 +853,29 @@ export class Pattern { ); } - log(func = (_, hap) => `[hap] ${hap.showWhole(true)}`, getData = (_, hap) => ({ hap })) { + /** + * Writes the content of the current event to the console (visible in the side menu). + * @name log + * @memberof Pattern + * @example + * s("bd sd").log() + */ + log(func = (hap) => `[hap] ${hap.showWhole(true)}`, getData = (hap) => ({ hap })) { return this.onTrigger((...args) => { logger(func(...args), undefined, getData(...args)); }, false); } - logValues(func = id) { - return this.log((_, hap) => func(hap.value)); + /** + * A simplified version of `log` which writes all "values" (various configurable parameters) + * within the event to the console (visible in the side menu). + * @name logValues + * @memberof Pattern + * @example + * s("bd sd").gain("0.25 0.5 1").n("2 1 0").logValues() + */ + logValues(func = (value) => `[hap] ${stringifyValues(value, true)}`) { + return this.log((hap) => func(hap.value)); } ////////////////////////////////////////////////////////////////////// diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 93c4168c..1df5c877 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -6,7 +6,7 @@ This program is free software: you can redistribute it and/or modify it under th import Fraction from 'fraction.js'; -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; import { TimeSpan, @@ -55,6 +55,8 @@ import { expand, } from '../index.mjs'; +import { log, logValues } from '../pattern.mjs'; + import { steady } from '../signal.mjs'; import { n, s } from '../controls.mjs'; @@ -1306,4 +1308,40 @@ describe('Pattern', () => { ); }); }); + describe('log', () => { + it('logs to console', () => { + const mockConsoleLog = vi.spyOn(console, 'log').mockImplementation(() => {}); + const pattern = pure('a').log(); + const haps = pattern.queryArc(0, 1); + + // Force a trigger + haps.forEach((hap) => { + hap.context?.onTrigger?.(hap); + }); + + expect(mockConsoleLog).toHaveBeenCalledWith( + '%c[hap] 0/1 → 1/1: a', + 'background-color: black;color:white;border-radius:15px', + ); + mockConsoleLog.mockRestore(); + }); + }); + describe('logValues', () => { + it('logs values to console', () => { + const mockConsoleLog = vi.spyOn(console, 'log').mockImplementation(() => {}); + const pattern = pure('a').note('c#').logValues(); + const haps = pattern.queryArc(0, 1); + + // Force a trigger + haps.forEach((hap) => { + hap.context?.onTrigger?.(hap); + }); + + expect(mockConsoleLog).toHaveBeenCalledWith( + '%c[hap] value:a note:c#', + 'background-color: black;color:white;border-radius:15px', + ); + mockConsoleLog.mockRestore(); + }); + }); }); diff --git a/packages/core/util.mjs b/packages/core/util.mjs index 756fac8e..2e7c6e02 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -487,3 +487,13 @@ export function getCurrentKeyboardState() { // } // return lcm((x * y) / gcd(x, y), ...z); // }; + +// Takes values -- typically derived from events, i.e. `hap`s -- and renders them +// into a readable format +export function stringifyValues(value, compact = false) { + return typeof value === 'object' + ? compact + ? JSON.stringify(value).slice(1, -1).replaceAll('"', '').replaceAll(',', ' ') + : JSON.stringify(value) + : value; +} diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index eb6c238d..51dff68a 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -5285,6 +5285,40 @@ exports[`runs examples > example "lock" example index 0 1`] = ` ] `; +exports[`runs examples > example "log" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd ]", + "[ 1/2 → 1/1 | s:sd ]", + "[ 1/1 → 3/2 | s:bd ]", + "[ 3/2 → 2/1 | s:sd ]", + "[ 2/1 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 3/1 → 7/2 | s:bd ]", + "[ 7/2 → 4/1 | s:sd ]", +] +`; + +exports[`runs examples > example "logValues" example index 0 1`] = ` +[ + "[ (0/1 → 1/3) ⇝ 1/2 | s:bd gain:0.25 n:2 ]", + "[ 0/1 ⇜ (1/3 → 1/2) | s:bd gain:0.5 n:1 ]", + "[ (1/2 → 2/3) ⇝ 1/1 | s:sd gain:0.5 n:1 ]", + "[ 1/2 ⇜ (2/3 → 1/1) | s:sd gain:1 n:0 ]", + "[ (1/1 → 4/3) ⇝ 3/2 | s:bd gain:0.25 n:2 ]", + "[ 1/1 ⇜ (4/3 → 3/2) | s:bd gain:0.5 n:1 ]", + "[ (3/2 → 5/3) ⇝ 2/1 | s:sd gain:0.5 n:1 ]", + "[ 3/2 ⇜ (5/3 → 2/1) | s:sd gain:1 n:0 ]", + "[ (2/1 → 7/3) ⇝ 5/2 | s:bd gain:0.25 n:2 ]", + "[ 2/1 ⇜ (7/3 → 5/2) | s:bd gain:0.5 n:1 ]", + "[ (5/2 → 8/3) ⇝ 3/1 | s:sd gain:0.5 n:1 ]", + "[ 5/2 ⇜ (8/3 → 3/1) | s:sd gain:1 n:0 ]", + "[ (3/1 → 10/3) ⇝ 7/2 | s:bd gain:0.25 n:2 ]", + "[ 3/1 ⇜ (10/3 → 7/2) | s:bd gain:0.5 n:1 ]", + "[ (7/2 → 11/3) ⇝ 4/1 | s:sd gain:0.5 n:1 ]", + "[ 7/2 ⇜ (11/3 → 4/1) | s:sd gain:1 n:0 ]", +] +`; + exports[`runs examples > example "loop" example index 0 1`] = ` [ "[ 0/1 → 1/1 | s:casio loop:1 ]",