diff --git a/src/API.ts b/src/API.ts index 423922f..633ef95 100644 --- a/src/API.ts +++ b/src/API.ts @@ -745,7 +745,7 @@ export class UserAPI { if (id !== "" && zid !== "z0") { // Sync named patterns to z0 by default - player.sync("z0"); + player.sync("z0", false); } return player; diff --git a/src/classes/ZPlayer.ts b/src/classes/ZPlayer.ts index e8bfcec..674e338 100644 --- a/src/classes/ZPlayer.ts +++ b/src/classes/ZPlayer.ts @@ -17,6 +17,7 @@ export class Player extends AbstractEvent { startCallTime: number = 0; lastCallTime: number = 0; waitTime = 0; + cueName: string|undefined = undefined; played: boolean = false; current!: Pitch | Chord | ZRest; retro: boolean = false; @@ -133,6 +134,7 @@ export class Player extends AbstractEvent { const timeToPlayNext = this.current && + this.waitTime >= 0 && this.pulseToSecond(this.origin()) >= this.pulseToSecond(this.lastCallTime) + this.pulseToSecond(this.current.duration * 4 * this.app.clock.ppqn) && @@ -158,8 +160,19 @@ export class Player extends AbstractEvent { return areWeThereYet; }; + checkCue() { + if(this.ziffers.atLast()) { + if(this.cueName && this.app.api.cueTimes[this.cueName]) { + delete this.app.api.cueTimes[this.cueName]; + this.cueName = undefined; + this.waitTime = -1; + } + } + } + sound(name?: string | string[] | SoundParams | SoundParams[]) { if (this.areWeThereYet()) { + this.checkCue(); const event = this.next() as Pitch | Chord | ZRest; const noteLengthInSeconds = this.app.clock.convertPulseToSecond( event.duration * 4 * this.app.clock.ppqn, @@ -214,6 +227,7 @@ export class Player extends AbstractEvent { midi(value: number | undefined = undefined) { if (this.areWeThereYet()) { + this.checkCue(); const event = this.next() as Pitch | Chord | ZRest; const obj = event.getExisting( "note", @@ -316,14 +330,28 @@ export class Player extends AbstractEvent { return this; } - wait(value: number | string | Function) { - + listen(value: string) { if(typeof value === "string") { const cueTime = this.app.api.cueTimes[value]; + this.cueName = value; if(cueTime && this.app.clock.pulses_since_origin <= cueTime) { this.waitTime = cueTime; } else { - this.waitTime = -1; + this.waitTime = -1; + } + return this; + } + } + + wait(value: number | string | Function) { + + if(typeof value === "string") { + const cueTime = this.app.api.cueTimes[value]; + this.cueName = value; + if(cueTime && this.app.clock.pulses_since_origin <= cueTime) { + this.waitTime = cueTime; + } else if(this.atTheBeginning()){ + this.waitTime = -1; } return this; } @@ -343,12 +371,24 @@ export class Player extends AbstractEvent { return this; } - sync(value: string | Function) { + sync(value: string | Function, manualSync: boolean = true) { + + if(typeof value === "string") { + if(manualSync) { + const cueTime = this.app.api.cueTimes[value]; + if(cueTime) { + this.waitTime = cueTime; + } else { + this.waitTime = -1; + } + } + return this; + } + if (this.atTheBeginning() && this.notStarted()) { const origin = this.app.clock.pulses_since_origin; - const syncId = typeof value === "function" ? value.name : value; if (origin > 0) { - const syncPattern = this.app.api.patternCache.get(syncId) as Player; + const syncPattern = this.app.api.patternCache.get(value.name) as Player; if (syncPattern) { const syncPatternDuration = syncPattern.ziffers.duration; const syncPatternStart = syncPattern.startCallTime; diff --git a/src/documentation/patterns/ziffers/ziffers_syncing.ts b/src/documentation/patterns/ziffers/ziffers_syncing.ts index 933052c..70b3003 100644 --- a/src/documentation/patterns/ziffers/ziffers_syncing.ts +++ b/src/documentation/patterns/ziffers/ziffers_syncing.ts @@ -6,31 +6,50 @@ export const ziffers_syncing = (application: Editor): string => { return ` # Synchronization -Ziffers patterns can be synced to any event using cue(name: string)) and wait(name: string) or by using sync(name: Function) and wait(name: Function) methods from the ziffers patterns. +Ziffers patterns can be synced to any event by using **cue**, **sync**, **wait** and **listen** methods. ## Sync with cue -The cue(name: string) methods can be used to send cue messages for ziffers patterns. The wait(name: string) method is used to wait for the cue message to start the pattern. +The cue(name: string) methods can be used to send cue messages for ziffers patterns. The wait(name: string) method is used to wait for the cue message to be received before starting the next cycle. ${makeExample( - "Sending cue from event", + "Sending cue from event and wait", ` beat(4.0) :: sound("bd").cue("foo").out(); - z1("q 0 3 e 2 1 2 1").wait("foo").sound("sine").out(); + z1("e 0 3 2 1 2 1").wait("foo").sound("sine").out(); `, true, )} +The sync(name: string) method is used to sync the ziffers pattern to the cue message. + ${makeExample( "Delayed start using individual cue", ` - onbar(3) :: cue("bar") - z1("0 4 2 -2").wait("bar") - .sound("ST40:3").stretch([2,1,3,.1].beat(0.5)).out(); + register('christmas', n=>n.room(0.25).size(2).speed([0.5, 0.25, 0.125]) + .delay(0.5).delayt(1/3).delayfb(0.5).bpf(200+usine(1/3)*500).out()) + onbar(1) :: cue("bar") + onbar(2) :: cue('baz') + z1("<0.25 0.125> 0 4 2 -2").sync("bar").sound("ST40:25").christmas() + z2("<0.25 0.125> 0 6 4 -4").sync("baz").sound("ST40:25").christmas() `, true, )} +The listen(name: string) method can be used to listen for the cue messages and play one event from the pattern for every cue. + + ${makeExample( + "Delayed start using individual cue", + ` + beat(1.0) :: cue("boom") + + z1("bd ").listen("boom") + .sound().out() + `, + true, + )} + + ## Sync with beat Patterns can also be synced using beat and setting the note length of events to zero using **z** duration character or noteLength(number) method.