felixroos / leetsheet

music leadsheet notation format for javascript
4 stars 0 forks source link

Expanding repeats in Sheet.render() #6

Open lastant opened 4 years ago

lastant commented 4 years ago

I would like the method Sheet.render() to also expand the repeats like the single measure repeat (x / % symbol) and double measure repeat. Is there a simple way to add this functionality? Cause I'm a bit lost in the code :) Thanks!

felixroos commented 4 years ago

Could you elaborate a little more what you mean? A code example would be nice..

lastant commented 4 years ago

Basically such a test case:

expect(
  Snippet.testFormat(
    Sheet.render([{ body: ['A'] }, { body: ['x'], signs: ['}'] }])
  )
).toEqual('A A A A');

Even better if it would work not only for 'x', but also for the double measure repeat (designated by 'r' in iReal, but I think is currently missing in leetsheet)

felixroos commented 4 years ago

Hm I think the easiest solution is to just map over the measures and resolve the repeat signs. Just use Array.map:

export function fillRepeats(measures: Measure<string[]>[]) {
  let lastSymbol;
  return measures.map(measure => {
    measure = Measure.from(measure);
    return {
      ...measure,
      body: (measure.body as string[]).map(symbol => {
        if (symbol === 'x' && lastSymbol) {
          return lastSymbol;
        }
        if (symbol === 'x') { // no lastSymbol
          console.warn('cannot use repeat symbol "x" in first measure!');
          return 'x';
        }
        lastSymbol = symbol;
        return symbol;
      })
    }
  })
}

When applied to the measures before rendering, the test is passing:

test('repeated bars', () => {
  expect(
    Snippet.testFormat(
      Sheet.render(fillRepeats([{ body: ['A'] }, { body: ['x'], signs: ['}'] }]))
    )
  ).toEqual('A A A A');
})

Resolving the double repeats should work similar, you may need to use Array.reduce instead of Array.map to add extra measures

lastant commented 4 years ago

Thank you! Yea actually I eventually did this kind of post-processing. But I still think the render function should better provide the completely expanded result.