Reputation: 39896
The context is that of a musical piano. I am interested in catching key-up events that occur when the sustain pedal is not pressed.
I have these streams:
pedalDown$
pedalUp$
keyUp$
How can I pipe these together into an observable unsustainedUp$
that emits of keyUp$
events only while the pedal is not down?
I thought this could work, but unsustainedUp$
fires even when the keyUp$
comes after a pedalDown$
and before a pedalUp$
.
unsustainedUp$ = keyUp$.pipe(
skipUntil(pedalUp$),
takeUntil(pedalDown$),
repeat()
)
// once at setup, fire into pedal-up to get this into the correct, normal piano initial state
pedalUp$.next()
Upvotes: 1
Views: 54
Reputation: 96969
I think you could do it like this. Maybe you'll need startWith()
depending on pedalUp$
functionality.
Btw, are pedalDown$
and the others Subjects
, BehaviorSubjects
or ReplaySubjects
?:
pedalUp$.pipe(
switchMap(() => keyUp$.pipe(
takeUntil(pedalDown$),
)),
Live demo: https://stackblitz.com/edit/rxjs-v2wkhq?devtoolsheight=60
I tried also your solution because it looks to me like it should work as well and it does:
https://stackblitz.com/edit/rxjs-ngorgw?devtoolsheight=60
So make sure when the source Observables emit because that might be the issue.
Upvotes: 2
Reputation: 8062
The setup of your streams makes this somewhat harder. One way to do this is to encode whether the pedal is currently up in its own stream that emits true when the pedal is up and false when it is down. Here I've defaulted to true
(The pedal starts up).
We can then combine the two, filter out all values when the pedal is down, and then emit the keyUp$
values when appropriate.
like so:
const isPedalUp$ = merge(
pedalUp$.pipe(mapTo(true)),
pedalDown$.pipe(mapTo(false))
).pipe(
startWith(true)
);
unsustainedUp$ = keyUp$.pipe(
withLatestFrom(isPedalUp$),
filter(([_,isUp]) => isUp),
map(([kepUp,_]) => kepUp)
);
Another approach is to switch into and out of keyUp$
. You'll need to multicast keyUp$
if it isn't already.
unsustainedUp$ = merge(
pedalUp$.pipe(mapTo(true)),
pedalDown$.pipe(mapTo(false))
).pipe(
startWith(true),
switchMap(isUp => isUp ?
keyUp$,
EMPTY
)
);
Upvotes: 1