Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pattern start/end/length/indexing needs an overhaul #240

Open
desolationjones opened this issue Mar 31, 2021 · 12 comments
Open

Pattern start/end/length/indexing needs an overhaul #240

desolationjones opened this issue Mar 31, 2021 · 12 comments

Comments

@desolationjones
Copy link
Contributor

Please describe the bug.

Pattern length is totally decoupled from start/end.

Pattern end can precede pattern start.

The documentation and studies are unclear about pattern length and indexing.

Please include the hash displayed at startup and the release of the software (e.g. "Teletype v2.0.1 5f838c9")

v3.2 but surely earlier also

What steps are required to reproduce the bug?

  1. P.START 6; P.END 10; P.L 3, then look on Tracker at the two totally isolated pattern zones. Try indexing through with P.NEXT.
  2. As above, then P.END 1, then look at Tracker which doesn't reflect meaningful pattern bounds. Try indexing through with P.NEXT. Try various combinations of length, start, and end.
@desolationjones
Copy link
Contributor Author

This is not limited to manually-adjusted pattern bounds. We have data-editing OPs which destructively affect length, e.g. P.INS or P.POP, but none which affect start/end meaningfully.

I am very curious to hear if anyone utilizes both systems. Anecdotally, every user I've polled uses only one system and is confused about the difference.

@tehn
Copy link
Member

tehn commented Mar 31, 2021

can you clarify what the two systems are? do you mean manual P.START/END vs. P.POP/P.INS? the second are for treating the tracker like a stack, which is somewhat unusual hence i understand confusing.

i'll boot up TT and try your test cases--- those do sound like display (and possibly data) bugs.

@desolationjones
Copy link
Contributor Author

Length, displayed by brighter numbers in the tracker, defines a region of the the pattern which always begins at tracker index 0. It remains stationary regardless of manipulations to start/end. Length is affected by many data operations, from entering data manually in the tracker, to using P.POP to retrieve a value destructively.

Start and end, displayed by a scroll bar to the right of the pattern, defines a freely adjustable region of the pattern which can begin and end at any tracker index. Start and end are unaffected by all OPs other than P.START and P.END.

Pattern start does not become index 0, neither does it move the "length" region to begin at pattern start.

@desolationjones
Copy link
Contributor Author

desolationjones commented Mar 31, 2021

I would (perhaps naively) propose unifying these two systems such that:

  • Pattern start becomes index 0 for all data OPs. Tracker top as index 0 is only used when moving P.START and P.END (or something like a hypothetical P.MOVE OP, or a hypothetical data entry OP which inputs data directly to tracker disregarding pattern length/position).
  • Pattern end preceding pattern start means the pattern wraps off the bottom of the tracker screen. This should be transparent to the data OPs. P.WRAP defines only what happens when indexing past the bottom of pattern end, not tracker end.
  • Length == end - start + 1 (in all cases where the doesn't wrap the tracker)
  • Adjusting length preserves pattern start and is destructive to pattern end.
  • Adjusting start preserves length and is destructive to end (moves whole pattern) OR introduce P.MOVE which acts like that and have P.START preserve pattern end and be destructive to length.
  • Adjusting end preserves start and is destructive to length.

Quoting myself from lines PM (though the above diverges a bit from that message):

There exists two coordinate systems: tracker space, and pattern space. In tracker space, index 0 is at the top of the screen. In pattern space, index 0 is at P.START.

The primary quality of tracker space is that values are generally stationary within it.

The vast majority of OPs should use pattern space addressing. Tracker space addressing should be generally reserved for OPs which remap pattern space.

@tehn
Copy link
Member

tehn commented Mar 31, 2021

ok: i think i figured out where the confusion/dissonance is coming from.

LEN currently as designed isn't related to START/END--- it's referring to the tracker/data length. perhaps a better name would be SIZE.

MOVE makes sense as an op to move both START and END at the same time. also a theoretical LENGTH should shift the END position relative to the START.

the problem now is that the START/END don't have any fencing/limiting with regard to the LEN/SIZE, which is confusing.

so, yes, i see a clarification should be made, and some ops revised and docs made more clear along with a tutorial/study revision.

re: your points above

Pattern start is index 0 for all data OPs. Tracker top as index 0 is only used when moving P.START and P.END (or something like a hypothetical P.MOVE OP, or a hypothetical data entry OP which inputs data directly to tracker disregarding pattern length/position).

yes. i don't recall if P.HERE also has a setter, but that i think addresses your last idea

Pattern end preceding pattern start means the pattern wraps off the bottom of the tracker screen. This should be transparent to the data OPs. P.WRAP defines only what happens when indexing past the bottom of pattern end, not tracker end.

START/END should respect LEN/SIZE, and should be sensibly/automatically confined/wrapped to this region.

Length == end - start + 1 (in all cases where the doesn't wrap the tracker)

i attempted to correct this misunderstanding of LEN/SIZE vs. LENGTH (we could totally add a LENGTH/etc or adjust

Adjusting length preserves pattern start and is destructive to pattern end.

yes, if we were to add a new op for LENGTH (as opposed to LEN/SIZE)

Adjusting start preserves length and is destructive to end (moves whole pattern) OR introduce P.MOVE which acts like that and have P.START preserve pattern end and be destructive to length.

i propose adding MOVE

Adjusting end preserves start and is destructive to length.

as above, i propose START/END stay independent, add MOVE and LENGTH to relative adjustment ops


all "data" ops should act relative to index 0 and have nothing to do with the START/END markers.

START/END pertains to HERE, NEXT, (etc) exclusively. we should put the docs into sections to properly reflect this.

@desolationjones
Copy link
Contributor Author

I turn my head and squint, and now this bunny is clearly a duck. Thank you for clearing this up! Later today I think I will pick a few existing OPs and walk through how they might interact within a "start/end are constrained to pattern size" paradigm. On first glance it seems very backwards-compatible.

If we maintain the current P.L as "amount of data" for backwards compatibility, P.SIZE could refer to the distance between start and end. I know this is inverse of your terminology.

This all seems easy to define "at rest", but the behavior of indexed markers HERE/START/END during a P.L change is understandably tricky. There may be room for modal behavior for modulo wrapping vs. saturating.

@tehn
Copy link
Member

tehn commented Mar 31, 2021

glad to hear, again i apologize for the initial confusion.

ahhhh i admit that calling a sequence length "size" really really bugs me. i'd almost suggest LL (loop length, even though it clearly can not be a loop if "wrap" isn't on)

@scanner-darkly
Copy link
Member

so it sounds like the intent behind the existing "length" parameter was for it to serve as the maximum pattern length - this explains why it always starts at 0 and why it's used as another boundary for some of the ops. also why it doesn't get updated when start/end are changed.

is there actually any benefit in being able to limit max pattern length other than automatically constraining start/end values and wrapping? this is not reflected in the UI other than highlighting, for instance - you can still see values beyond length. you can still access values outside of length, which doesn't make sense if length serves as "max pattern length".

if there is no clear benefit to it, what if we just change it as you propose, to be tied to start/end and serve as the loop length? i'm concerned introducing yet another term will just add to the confusion. this does mean introducing a breaking change though.

@scanner-darkly
Copy link
Member

also some findings, i went through the existing ops and identified which ops use which parameters. also identified a few inconsistencies/bugs.. (only listing PN variants for readability)

  • default for new scene is: length 0, start 0, end 63
  • length cannot be negative (will be set to 0)

several ops use function normalise_idx which works like this:

  • if index is negative: add it to length (so, moving backwards relative to length), constrain at 0
  • if beyond max pattern length, set it to max pattern length - 1 (63)

in the documentation it's described like this: "Negative x values are indexed backwards from the end of the pattern length of the working pattern".

ops that do NOT use length

PN.MIN PN.MAX
will use start if start > end

PN.SHUF PN.REV PN.ROT
will do nothing if start > end

P.RND
will return 0 if start > end - a bug, should really return value at start to be consistent with the above

PN.MAP
will do nothing if start >= end - a bug, it should update value at start if start == end.

if we want to support start > end, we'll need to update all of the above.

ops that use length but do not change it

PN.START PN.END PN PN.+ PN.+W PN.- PN.-W
all use normalize_idx

PN.I
uses normalize_idx but also limits to length - 1

ops that use length and possibly change it

PN.INS
uses normalize_idx. if inserting within the length block, shifts values and increases length, otherwise it just sets value at index

PN.REM
uses normalize_idx. if removing within the length block, shifts values and decreases length, otherwise just returns 0

PN.PUSH
if length is less than the max pattern length, inserts value at length and increments length

PN.POP
if length is > 0, decrements length and returns value at length - 1

PN.NEXT
if index == length - 1 or end, and wrap is on, sets it to start, otherwise increments
if new index is greater than length or max pattern length, it's set to 0

PN.PREV
if index != 0 and index != start, decrement
otherwise if wrap is on, set to end if end is less than length, otherwise set to length - 1

other

P.CYC
uses start and end but wraps based on length - and as far as i can tell is not actually exposed as an op!

@scanner-darkly
Copy link
Member

the UI:

you can set start and end using shift-S / shift-E
when setting start/end in the grid control mode, length will be set to end + 1

you can set length with shift-L
it's also changed when:

  • new value is entered (Enter)
  • the last entry is duplicated (shift-Enter)
  • erasing an entry (shift-backspace)
  • cutting an entry (alt-X)
  • inserting a value (shift-alt-V)

@tehn
Copy link
Member

tehn commented Mar 31, 2021

if there is no clear benefit to it, what if we just change it as you propose, to be tied to start/end and serve as the loop length? i'm concerned introducing yet another term will just add to the confusion. this does mean introducing a breaking change though.

yes, on second thought (i'm sorry it's been so long since i've had my head deep in TT space) i think the main issue at hand is documentation, to explain what P.L actually does and is intended for. i'd rather not introduce any breaking changes re: design philosophy, and i'm not sure constraining the START/END with L to be terribly constructive.

but we should address the bugs you list, absolutely. i'm concerned that some OPs got introduced that misunderstood the original intention of LENGTH (now that we have returned to clarify)

i think the UI is still spot-on

@DocPolyester
Copy link

DocPolyester commented Jun 4, 2021

Isn’t in PN.NEXT the „ index == length - 1 or end“ also a bug?
(I guess >= would fit better)

Explanation: if you change p.end to a value below the current index and the length is larger.
Than one cycle get „out of control“ until it’s catched again by the ==.

You can get a similar issue with p.start if it’s higher than the current index. So maybe a constrain within p.next the index to p.start would help too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants