Merge remote-tracking branch 'origin/main' into some-tunes

This commit is contained in:
Felix Roos 2022-10-30 19:36:16 +01:00
commit 50f88798d8
5 changed files with 2297 additions and 14 deletions

View File

@ -63,6 +63,17 @@ export class Pattern {
return new Pattern((state) => this.query(state.withSpan(func)));
}
withQuerySpanMaybe(func) {
const pat = this;
return new Pattern((state) => {
const newState = state.withSpan(func);
if (!newState.span) {
return [];
}
return pat.query(newState);
});
}
/**
* As with {@link Pattern#withQuerySpan}, but the function is applied to both the
* begin and end time of the query timespan.
@ -744,12 +755,17 @@ export class Pattern {
// // there is no gap.. so maybe revert to _fast?
// return this._fast(factor)
// }
// A bit fiddly, to drop zero-width queries at the start of the next cycle
const qf = function (span) {
const cycle = span.begin.sam();
const begin = cycle.add(span.begin.sub(cycle).mul(factor).min(1));
const end = cycle.add(span.end.sub(cycle).mul(factor).min(1));
return new TimeSpan(begin, end);
const bpos = span.begin.sub(cycle).mul(factor).min(1);
const epos = span.end.sub(cycle).mul(factor).min(1);
if (bpos >= 1) {
return undefined;
}
return new TimeSpan(cycle.add(bpos), cycle.add(epos));
};
// Also fiddly, to maintain the right 'whole' relative to the part
const ef = function (hap) {
const begin = hap.part.begin;
const end = hap.part.end;
@ -765,9 +781,9 @@ export class Pattern {
);
return new Hap(newWhole, newPart, hap.value, hap.context);
};
return this.withQuerySpan(qf)._withHap(ef)._splitQueries();
return this.withQuerySpanMaybe(qf)._withHap(ef)._splitQueries();
}
// Compress each cycle into the given timespan, leaving a gap
_compress(b, e) {
if (b.gt(e) || b.gt(1) || e.gt(1) || b.lt(0) || e.lt(0)) {

View File

@ -137,6 +137,9 @@ describe('Pattern', () => {
it('Can make a pattern', () => {
expect(pure('hello').query(st(0.5, 2.5)).length).toBe(3);
});
it('Supports zero-width queries', () => {
expect(pure('hello').queryArc(0,0).length).toBe(1);
});
});
describe('fmap()', () => {
it('Can add things', () => {
@ -430,6 +433,16 @@ describe('Pattern', () => {
// mini('[c3 g3]/2 eb3') always plays [c3 eb3]
// mini('eb3 [c3 g3]/2 ') always plays [c3 g3]
});
it('Supports zero-length queries', () => {
expect(steady('a')._slow(1).queryArc(0,0)
).toStrictEqual(steady('a').queryArc(0,0))
});
});
describe('slow()', () => {
it('Supports zero-length queries', () => {
expect(steady('a').slow(1)._setContext({}).queryArc(0,0)
).toStrictEqual(steady('a')._setContext({}).queryArc(0,0))
});
});
describe('inside', () => {
it('can rev inside a cycle', () => {

View File

@ -18,6 +18,11 @@ export class TimeSpan {
const end = this.end;
const end_sam = end.sam();
// Support zero-width timespans
if (begin.equals(end)) {
return([new TimeSpan(begin, end)]);
}
while (end.gt(begin)) {
// If begin and end are in the same cycle, we're done.
if (begin.sam().equals(end_sam)) {

View File

@ -100,12 +100,8 @@ const getSoundfontKey = (s) => {
const getSampleBufferSource = async (s, n, note, speed) => {
let transpose = 0;
let midi;
if (note !== undefined) {
midi = typeof note === 'string' ? toMidi(note) : note;
transpose = midi - 36; // C3 is middle C
}
let midi = typeof note === 'string' ? toMidi(note) : note || 36;
transpose = midi - 36; // C3 is middle C
const ac = getAudioContext();
// is sample from loaded samples(..)
@ -128,9 +124,6 @@ const getSampleBufferSource = async (s, n, note, speed) => {
if (Array.isArray(bank)) {
sampleUrl = bank[n % bank.length];
} else {
if (!note) {
throw new Error('no note(...) set for sound', s);
}
const midiDiff = (noteA) => toMidi(noteA) - midi;
// object format will expect keys as notes
const closest = Object.keys(bank)

File diff suppressed because it is too large Load Diff