Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/app/studio/src/ui/header/TimeStateDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ import { Propagation } from "@opendaw/lib-box";

const className = Html.adoptStyleSheet(css, "TimeStateDisplay");

/** Parameters for constructing {@link TimeStateDisplay}. */
/** Parameters for constructing {@link TimeStateDisplay}.
*
* @public
*/
export type Construct = {
/** Lifecycle managing subscriptions. */
lifecycle: Lifecycle;
Expand All @@ -43,6 +46,9 @@ const maxBpm = 1000.0;
/**
* Displays transport position, tempo and meter.
*
* @param lifecycle - Lifecycle managing subscriptions.
* @param service - Service providing access to engine and project.
*
* @public
*/
export const TimeStateDisplay = ({ lifecycle, service }: Construct) => {
Expand Down
8 changes: 7 additions & 1 deletion packages/app/studio/src/ui/timeline/SnapSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {Colors} from "@opendaw/studio-core"

const className = Html.adoptStyleSheet(css, "SnapSelector")

/** Parameters for constructing {@link SnapSelector}. */
/** Parameters for constructing {@link SnapSelector}.
*
* @public
*/
export type Construct = {
/** Lifecycle managing subscriptions. */
lifecycle: Lifecycle
Expand All @@ -21,6 +24,9 @@ export type Construct = {
/**
* Dropdown for selecting timeline snap resolution.
*
* @param lifecycle - Lifecycle managing subscriptions.
* @param snapping - Snap settings that provide available options.
*
* @example
* ```tsx
* <SnapSelector lifecycle={lifecycle} snapping={snapping} />
Expand Down
5 changes: 4 additions & 1 deletion packages/app/studio/src/ui/timeline/TimeAxis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ const className = Html.adoptStyleSheet(css, "time-axis")
const MIN_TRACK_DURATION = 8 * PPQN.Bar
const MAX_TRACK_DURATION = 1024 * PPQN.Bar

/** Parameters for constructing {@link TimeAxis}. */
/** Parameters for constructing {@link TimeAxis}.
*
* @public
*/
export type Construct = {
/** Lifecycle managing subscriptions. */
lifecycle: Lifecycle
Expand Down
13 changes: 11 additions & 2 deletions packages/app/studio/src/ui/timeline/TimeGrid.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
/**
* Helpers for walking the musical grid of the timeline. Provides iteration
* Helpers for walking the musical grid of the timeline. Provides iteration
* utilities that call back for each bar, beat or subdivision within a range.
*/
import {PPQN} from "@opendaw/lib-dsp"
import {int, quantizeFloor} from "@opendaw/lib-std"
import {TimelineRange} from "@/ui/timeline/TimelineRange.ts"

/** Utilities for iterating over timeline grid divisions. */
/**
* Utilities for iterating over timeline grid divisions.
*
* @public
*/
export namespace TimeGrid {
/**
* Time signature expressed as `[nominator, denominator]`.
Expand All @@ -22,6 +26,11 @@ export namespace TimeGrid {
/**
* Iterates over grid fragments within the given range and calls `designer`
* for each division.
*
* @param param0 - Time signature `[nominator, denominator]`.
* @param range - Visible timeline range to iterate over.
* @param designer - Callback receiving details about each fragment.
* @param options - Optional minimum pixel length of a fragment.
*/
export const fragment = ([nominator, denominator]: Signature,
range: TimelineRange, designer: Designer, options?: Options): void => {
Expand Down
21 changes: 18 additions & 3 deletions packages/docs/docs-dev/architecture/tempo.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Tempo
# Tempo

openDAW expresses musical time in pulses per quarter note (PPQN). A bar in 4/4 time contains 3,840 pulses, providing a stable grid for sequencing and rendering.
openDAW expresses musical time in pulses per quarter note (PPQN). A bar in 4/4
time contains 3 840 pulses, providing a stable grid for sequencing and
rendering. The PPQN utility collects conversions between pulses, seconds and
samples and provides helpers for formatting musical positions.

## Conversions

Expand All @@ -11,5 +14,17 @@ const pulses = PPQN.secondsToPulses(1.5, 120);
const seconds = PPQN.pulsesToSeconds(PPQN.Bar, 90);
```

The timeline renders this grid via `TimeGrid` and `TimeAxis`, while `BPMTools.detect` can estimate the tempo of audio buffers.
## Tempo Detection

The `BPMTools.detect` function estimates the tempo of PCM buffers. It is
optimised for typical music ranges and returns a floating‑point BPM value.

```ts
import {BPMTools} from "@opendaw/lib-dsp";

const bpm = BPMTools.detect(buffer, sampleRate);
```

The timeline renders the musical grid via `TimeGrid` and `TimeAxis` and keeps it
in sync with tempo and meter changes.

4 changes: 4 additions & 0 deletions packages/docs/docs-user/features/timeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ import {PPQN} from "@opendaw/lib-dsp";

// Seconds per bar at 128 BPM
const barSeconds = PPQN.pulsesToSeconds(PPQN.Bar, 128);

// Estimate tempo of an audio buffer
import {BPMTools} from "@opendaw/lib-dsp";
const bpm = BPMTools.detect(buffer, sampleRate);
```

## Example Integration
Expand Down
2 changes: 2 additions & 0 deletions packages/lib/dsp/src/bpm-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {int} from "@opendaw/lib-std"
* The detector is optimised for music with tempos in the 90‑180 BPM range and
* operates on mono PCM data. It is a port of Mark Hills' `bpm(1)` algorithm with
* a small penalty applied to very slow candidates to avoid half‑tempo aliases.
*
* @public
*/
export namespace BPMTools {
/**
Expand Down
6 changes: 5 additions & 1 deletion packages/lib/dsp/src/fractions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import {PPQN, ppqn} from "./ppqn"
/** Tuple representing a musical fraction `n/d`. */
export type Fraction = Readonly<[int, int]>

/** Helpers for working with musical fractions. */
/**
* Helpers for working with musical fractions.
*
* @public
*/
export namespace Fraction {
/** Creates a builder for accumulating fractions. */
export const builder = () => new Builder()
Expand Down
11 changes: 9 additions & 2 deletions packages/lib/dsp/src/ppqn.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// Pulses per quarter note (PPQN)
// 960 = 3*5*2^6
/**
* Utilities and constants for pulses per quarter note (PPQN).
* A single bar in 4/4 time consists of 3,840 pulses where a quarter note equals
* 960 pulses (3 × 5 × 2^6).
*
* @public
*/

import {int} from "@opendaw/lib-std"

Expand All @@ -17,6 +22,7 @@ const SemiQuaver = Quarter >>> 2 // 240
*
* @param nominator - Beats per bar.
* @param denominator - Note value representing one beat.
* @returns Total pulses per bar.
*/
const fromSignature = (nominator: int, denominator: int) => Math.floor(Bar / denominator) * nominator
/**
Expand All @@ -25,6 +31,7 @@ const fromSignature = (nominator: int, denominator: int) => Math.floor(Bar / den
* @param ppqn - Pulse count to decompose.
* @param nominator - Beats per bar.
* @param denominator - Note value representing one beat.
* @returns Decomposed musical components.
*/
const toParts = (ppqn: ppqn, nominator: int = 4, denominator: int = 4) => {
const lowerPulses = fromSignature(1, denominator)
Expand Down
4 changes: 4 additions & 0 deletions packages/lib/std/src/time-span.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/**
* Time span calculation utilities.
*
* @public
*/
import { int, Unhandled } from "./lang";

/**
* Represents a span of time with millisecond precision and provides
* convenient factory methods and conversions.
*
* @public
*/
export class TimeSpan {
/** Time span representing positive infinity. */
Expand Down
2 changes: 2 additions & 0 deletions packages/studio/core/src/Engine.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/**
* Public interfaces for controlling the audio engine and reacting to note events.
*
* @packageDocumentation
*/
import {ppqn} from "@opendaw/lib-dsp"
import {
Expand Down