Skip to content

Music: initial progression#50596

Merged
breville merged 32 commits into
stagingfrom
music-initial-progression
Mar 23, 2023
Merged

Music: initial progression#50596
breville merged 32 commits into
stagingfrom
music-initial-progression

Conversation

@breville

@breville breville commented Mar 6, 2023

Copy link
Copy Markdown
Member

This introduces the beginnings of a progression system for Music Lab, allowing us to scaffold the student experience.

Features

  • No page reloads between steps
    • The hope is that we can build new support into the dashboard to progress through green bubbles without reloading the lab.
  • Driven by a single JSON file for all steps
    • The goal is to add levelbuilder support in the future.
  • Each step has a set of validation conditions
    • The level designer writes these in JSON, rather than JS, so we have a clean separation between validation and the lab's implementation.
    • Conditions that aren't recognised are skipped, allowing level designers to add necessary conditions while we will later add support for them.
    • Can specify a variety of feedback messages for specific conditions.
    • Essentially the same system as I built for Star Wars in 2015 here, and AI for Oceans in 2019 here.
  • The Toolbox and available set of sounds can be dynamically configured for each step
  • The core progression system is lab-agnostic, and can be reused by other labs

Video

music-progression-1.mov

Architecture

The initial implementation was specific to Music Lab, but @sanchitmalhotra126 had good feedback that we could make it more generic, and proposed an architecture which is now in place:

  • ProgressManager manages progress, and is lab-agnostic.
  • MusicValidator does Music Lab-specific evaluation of progress. It implements the abstract Validator class, and is passed into ProgressManager, which knows of nothing more than Validator.
  • ConditionsChecker is a helper class which accumulates satisfied conditions, and in this case is used by MusicValidator. Other labs might benefit from it, though there are alternate techniques to validate code, such as direct code examination, which doesn't really need to accumulate satisfied conditions over a period of time.

For now, MusicView loads the progression data and passes it into ProgressManager when it instantiates that class. MusicView also instantiates MusicValidator and gives it access to the components it needs to examine progress.
Also for now,Instructions are aware of the progression, though we might make them agnostic later.

Viewing

The progression isn't enabled by default, but can be seen with the load-progression=true URL parameter.

It does support loading a progression file from S3, but since we haven't put one on there yet, the local-progression=true URL parameter will load the built-in file from this commit. Once a file is on S3, specifically https://curriculum.code.org/media/musiclab/music-progression.json (in cdo-curriculum/media/musiclab), this option can be omitted.

It is also possible to specify an alternate progression, e.g. ?progression=variant, and that variant will be loaded from https://curriculum.code.org/media/musiclab/music-progression-variant.json, allowing us to quickly develop some alternate progressions in parallel.

These three new options have also been added to the menu at https://studio.code.org/musiclab/menu.

All that said, the way to see the progression for now is by visiting https://studio.code.org/projectbeats?load-progression=true&local-progression=true.

Very rough initial work, but it does work.
@breville breville marked this pull request as draft March 6, 2023 00:59
@breville breville marked this pull request as ready for review March 12, 2023 04:55
@breville breville requested review from a team and moneppo March 12, 2023 06:03

@sanchitmalhotra126 sanchitmalhotra126 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! Some comments but nothing major.

Comment thread apps/src/music/progress/MusicValidator.ts Outdated
Comment thread apps/src/music/progress/ProgressManager.ts Outdated
Comment thread apps/src/music/progress/ProgressManager.ts Outdated
Comment thread apps/src/music/player/MusicLibrary.ts Outdated

// A sound picker might want to show the subset of sounds permitted by the
// progression's currently allowed sounds.
getAllowedSounds(folderType: string) : Sounds {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should our components be allowed to decide whether to use allowed sounds or not? I wonder if maybe we should just modify the model in place and mark certain sounds/folders allowed: true/false, and use those flags in the other functions here...not sure.

Also should we be calling this in PatternPanel and ChordPanel too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the idea of having an immutable library that we initially load, and then being able to dynamically set the allowed sound list as we transition levels. As part of that "functional" philosophy, I like having this transformation function which leaves the library unchanged but still retrieves the filtered set.

I suspect we might end up with places in our code that want access to the unfiltered library, and I think we trust our components to use the allowed set via this function when they should.

It seems most likely we'll want to expand this to patterns and chords too, but I figured we could add them in a follow-up if/when we get the ask. :)

// Find out from the lab-specific code whether we should be trying to
// check conditions at the moment. Otherwise, we might get a fail
// when we shouldn't have even been checking.
if (!this.validator.shouldCheckConditions()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious about this - if the lab itself is calling updateProgress, can we trust that the lab will only call it when it's appropriate to check conditions?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a great question, and something to keep in mind as Music Lab gets more states, especially for things like loading data, transitioning levels, etc. We could already add a bit of nuance to Music Lab, so that it only calls this when playing, for example, but I think what we have is alright for a first pass.

It seems that if ProgressManager is to remain lab agnostic, we need to ultimately place that responsibility on the caller. I guess we could add some more states to ProgressManager, allowing the caller to give it some context as to when to check state, but I'm not quite sure what they would be yet.

Comment thread apps/src/music/progress/ProgressManager.ts Outdated
Comment thread apps/src/music/progress/ProgressManager.ts Outdated
Comment thread apps/src/music/player/MusicLibrary.ts Outdated

@sanchitmalhotra126 sanchitmalhotra126 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing all the feedback! Just one other question I missed from last time, and a few small nits

Comment thread apps/src/music/player/MusicLibrary.ts Outdated
Comment thread apps/src/music/progress/ConditionsChecker.ts Outdated
Comment thread apps/src/music/progress/MusicValidator.ts Outdated
Comment thread apps/src/music/progress/MusicValidator.ts Outdated
Comment thread apps/src/music/views/MusicView.jsx Outdated
});
}

this.progressManager?.updateProgress();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to be checking this constantly? Could just this happen onBlockSpaceChange and/or on play?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll adjust it so that it only checks while we are playing, but we need it to check frequently while playing, because the current success criteria are for things actually happening in realtime while the program is running (like, are three sounds playing simultaneously). We could evaluate them in other ways, like examining the program, or examining the timeline, but for tasks such as "trigger a sound using the Beatpad" we'd need to be doing this kind of realtime checking anyway. This is the approach we took for validation in Star Wars & AI for Oceans, too.

@sanchitmalhotra126 sanchitmalhotra126 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@breville breville merged commit 2014930 into staging Mar 23, 2023
@breville breville deleted the music-initial-progression branch March 23, 2023 04:17
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

Successfully merging this pull request may close these issues.

2 participants