Dogalog:一个基于Prolog的实时编程音乐环境
Dogalog: A realtime Prolog-based livecoding music environment

原始链接: https://github.com/danja/dogalog

## Dogalog:使用Prolog进行实时编程音乐 Dogalog是一个基于Prolog的实时编程系统构建的实时音乐环境。用户编写逻辑规则来生成算法节奏和旋律,代码更改会自动应用并以视觉方式呈现。它专为移动设备优先使用而设计,并可以作为渐进式Web应用安装以供离线访问。 Dogalog的核心在于使用类似Prolog的语句定义音乐事件。内置谓词,如`beat`、`every`、`euc`(欧几里得节奏)和`prob`(概率),控制时间和模式。一套全面的内置函数允许进行音阶/和弦生成、随机化以及通过`cycle`和`cooldown`进行有状态操作。 Dogalog拥有模块化架构和广泛的测试(88%以上覆盖率),并包含一个13步的交互式教程。主要功能包括跨代码更新的状态保存、时间网格调度器以及用于实时声音生成的WebAudio合成。 它使用纯JavaScript、CodeMirror 6和WebAudio API构建,并从TidalCycles和Sonic Pi等工具中汲取灵感。通过打开开发服务器并点击“开始”来开始实时编程,或深入教程以获得引导式学习体验。

## Dogalog:一个实时Prolog音乐环境 一个名为Dogalog(github.com/danja)的新型实时编程音乐环境在Hacker News上受到关注。与TidalCycles、Sonic Pi和FoxDot等为现场表演设计的、时间为先的系统不同,Dogalog利用约束求解方法进行作曲,旨在用于离线使用。 讨论强调了与类似项目的比较。Sonic Pi仍然受欢迎,专注于教育和易用性,而TidalCycles(基于Haskell)和Strudel(TidalCycles的WebAssembly版本)等替代方案正在出现。Bytebeats也被提及,虽然概念不同,但相关。 Dogalog的演示收到了积极的初步反馈,但有用户报告在Android Chrome上出现音频问题。有趣的是,该项目是“氛围编码”的——作者在最初并不了解其底层的Prolog语言的情况下创建的!用户对潜在的创意音乐探索表示兴奋,特别是约束和弦和音阶的想法。
相关文章

原文

Dogalog is a realtime Prolog-based livecoding music environment where you write logic rules to create algorithmic rhythmic patterns and melodies.

  • Livecoding: Auto-evaluation with visual feedback - code changes apply automatically
  • State Preservation: Cycle counters and cooldowns persist across updates
  • Interactive Tutorial: Built-in 13-step guided tutorial for learning
  • PWA Support: Install as an app, works offline
  • Mobile-First: Touch-friendly UI optimized for all devices
  • Modular Architecture: Clean separation of concerns, all files <100 lines
  • Comprehensive Testing: 123 tests with 88%+ coverage

Open the dev server URL, click Tutorial to learn, or click Start and begin livecoding!

Rules are Prolog-like statements that define when sounds should play:

% Kick drum on every beat
event(kick, 60, 80, T) :- beat(T, 1).

% Snare on beats 2 and 4
event(snare, 60, 90, T) :- beat(T, 2).

% Hi-hats every 8th note
event(hat, 60, 70, T) :- every(T, 0.5).

The system asks event(Voice, Pitch, Velocity, Time) on every step and plays all matching results.

  • beat(T, N) - Trigger on beat N (1 = downbeat, 2 = halfway, 4 = quarter notes)
  • every(T, Step) - Trigger at regular intervals (0.5 = twice per beat)
  • phase(T, N, K) - Trigger on phase K of N divisions
  • euc(T, K, N, B, R) - Euclidean rhythm (K hits over N steps)
  • prob(P) - Succeed with probability P (0.0-1.0)
  • choose(List, X) - Pick random element
  • cycle(List, X) - Cycle through elements sequentially (stateful!)
  • pick(List, X) - Backtrack through all elements
  • rand(Min, Max, X) - Random float
  • randint(Min, Max, X) - Random integer
  • scale(Root, Mode, Degree, Oct, Midi) - Convert scale degree to MIDI note
  • chord(Root, Quality, Oct, Midi) - Generate chord tones
  • transpose(Note, Offset, Out) - Transpose by semitones
  • within(T, Start, End) - Time range check (for song structure)
  • cooldown(Now, Last, Gap) - Prevent rapid retriggering
  • eq(A, B), lt(A, B), gt(A, B) - Comparisons
  • distinct(List) - Check all elements are unique
  • add(A, B, C) - Arithmetic
  • range(Start, End, Step, X) - Generate number sequences
  • rotate(List, Shift, OutList) - Rotate lists
  • kick - Synthesized kick drum
  • snare - Noise-based snare
  • hat - Noise-based hi-hat
  • sine - Sine wave monosynth (use MIDI pitch)

Four-on-the-floor with backbeat:

event(kick, 60, 100, T) :- euc(T, 4, 16, 4, 0).
event(snare, 60, 90, T) :- euc(T, 2, 16, 4, 4).

Complex polyrhythm:

event(kick, 60, 100, T) :- euc(T, 3, 8, 0.5, 0).
event(snare, 60, 80, T) :- euc(T, 5, 8, 0.5, 2).

Pentatonic melody:

note(N) :- cycle([1, 3, 4, 5, 8], D), scale(60, minor_pent, D, 0, N).
event(sine, N, 70, T) :- every(T, 0.5), note(N).

Available modes: major, minor, dorian, phrygian, lydian, mixolydian, locrian, minor_pent, major_pent, blues, whole_tone, chromatic

arp(N) :- chord(60, minor, 0, Notes), choose(Notes, N).
event(sine, N, 70, T) :- every(T, 0.25), arp(N).

Chord qualities: maj, min, dim, aug, sus2, sus4, maj7, min7, dom7, dim7

Random velocities:

vel(V) :- choose([60, 80, 100], V).
event(hat, 60, V, T) :- every(T, 0.25), vel(V).

Sparse pattern:

event(snare, 60, 80, T) :- beat(T, 2), prob(0.3).

Song Structure with within

% Intro: just kick (beats 0-8)
event(kick, 60, 100, T) :- beat(T, 1).

% Verse: add snare (beats 8-16)
event(snare, 60, 80, T) :- beat(T, 2), within(T, 8, 16).

% Chorus: add melody (beats 16-24)
melody(N) :- scale(60, major, D, 0, N), cycle([1,3,5,8], D).
event(sine, N, 70, T) :- every(T, 0.5), melody(N), within(T, 16, 24).
% Regular pattern
event(kick, 60, 100, T) :- beat(T, 1).

% Fill every 4+ bars
fill(T) :- beat(T, 1), cooldown(T, last_fill, 4).
event(snare, 60, V, T) :- fill(T), every(T, 0.25), choose([80,90,100], V).
npm install          # Install dependencies
npm run dev          # Start dev server (http://localhost:5173)
npm run build        # Build for production
npm run preview      # Preview production build
npm test             # Run tests
npm run test:ui      # Run tests with UI
npm run test:coverage # Generate coverage report
npm run docs:html    # Build manual and cheatsheet
src/
├── prolog/          # Prolog engine
│   ├── builtins/    # Builtin predicates (modular)
│   ├── parser.js    # Parser
│   ├── resolution.js # SLD resolution with generators
│   ├── tokenizer.js # Tokenizer
│   ├── unify.js     # Unification
│   └── terms.js     # Term constructors
├── audio/           # WebAudio synthesis
│   └── audioEngine.js
├── scheduler/       # Timing and execution
│   ├── scheduler.js
│   ├── stateManager.js
│   └── transitionManager.js
├── livecoding/      # Auto-evaluation
│   ├── codeValidator.js
│   └── liveEvaluator.js
├── tutorial/        # Tutorial system
│   ├── tutorialManager.js
│   ├── tutorialOverlay.js
│   └── steps.js
├── ui/              # User interface
│   ├── components/  # Reusable components
│   ├── template.js
│   ├── controls.js
│   └── validationIndicator.js
├── help/            # Documentation
│   └── builtinDocs.js
├── config/          # Configuration
│   └── defaults.js
├── app.js           # Application orchestrator
└── main.js          # Entry point
  • Prolog Engine: Custom implementation with SLD resolution using ES6 generators for backtracking
  • Livecoding: Debounced auto-evaluation (300ms) with syntax validation
  • State Management: Centralized state for cycle counters and cooldowns (persists across code updates)
  • Scheduler: Time-grid based (16th notes) with swing and lookahead support
  • Audio: WebAudio synthesis without samples - all sounds generated in real-time
  • UI: Mobile-first, progressive enhancement, DOM-based components
  • 123 tests across 16 test files
  • Coverage: 88.52% statements, 90.42% functions
  • Integration tests for livecoding, state preservation, example loading
  • UI component tests with vitest + jsdom
  • Installable on mobile and desktop
  • Offline support with service worker
  • Caches all assets and documentation
  • Manifest with icons and theme colors
  • Interactive Tutorial: Click "Tutorial" button in the app for 13 guided steps
  • Full Tutorial: Comprehensive guide teaching both Prolog and livecoding
  • Manual: Complete reference for all built-ins and syntax
  • Cheatsheet: Quick reference for common patterns
  • Live Demo: GitHub Pages
  1. User edits code in editor
  2. After 300ms debounce, code is validated
  3. If valid: parse → compile → swap program (with smooth transition)
  4. State (cycles, cooldowns) persists across updates
  5. Visual indicator shows validation state (green/red/yellow)
% This pattern's state persists when you edit other code:
drums(D) :- cycle([kick, snare, hat], D).
event(D, 60, 80, T) :- beat(T, 1), drums(D).

% Editing this won't reset the cycle counter!

Euclidean rhythms distribute K hits as evenly as possible over N steps using the Euclidean algorithm. The result is musically interesting patterns used in music worldwide:

  • euc(T, 3, 8, 0.5, 0) - Tresillo pattern (Cuban music)
  • euc(T, 5, 8, 0.5, 0) - Cinquillo pattern
  • euc(T, 5, 12, 0.5, 0) - Common rock beat
  • Modern browsers with WebAudio API
  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14.1+
  • Mobile browsers (iOS Safari, Chrome Android)

MIT

Built with vanilla JavaScript, CodeMirror 6, and WebAudio API. Inspired by TidalCycles, Sonic Pi, and Datalog.

联系我们 contact @ memedata.com