Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7a6f873
code and a simple test for basic MIDI notes comparison
ada-jz7125 May 29, 2026
e484d17
add pitch alignment to basic comparison
ada-jz7125 Jun 1, 2026
3c73917
add tests for each case separately
ada-jz7125 Jun 1, 2026
540818c
change the vairables name to match the typical terminology
ada-jz7125 Jun 12, 2026
8e652b6
basic code structure for DTW
ada-jz7125 Jun 12, 2026
f105a1e
working on the backtrack warping path
ada-jz7125 Jun 13, 2026
c4afe54
evaluation after DTW, but there is an unexpected output message.
ada-jz7125 Jun 13, 2026
2a23814
edit distance algorithm
ada-jz7125 Jun 15, 2026
f46612b
edit distance algorithm, feedback to be fixed
ada-jz7125 Jun 15, 2026
0b1941f
fix the typo in generate_feedback
ada-jz7125 Jun 17, 2026
f9ee250
add some visualisation of edit distance result, add an outline for th…
ada-jz7125 Jun 17, 2026
c5a3ef0
modify the visualisation part
ada-jz7125 Jun 18, 2026
6ebef2b
evaluate the start time and duration via relative threshold, update t…
ada-jz7125 Jun 20, 2026
68248f6
fix the logic in feedback, add overview feedback
ada-jz7125 Jun 21, 2026
e42891e
add some test cases
ada-jz7125 Jun 21, 2026
9b86eed
deploy the evaluation functions
ada-jz7125 Jun 23, 2026
8012291
Delete data directory
ada-jz7125 Jun 23, 2026
9133cfe
fix typo
ada-jz7125 Jun 23, 2026
d0debb4
Merge branch 'note_alignment' of https://github.com/lambda-feedback/c…
ada-jz7125 Jun 23, 2026
9f2d9bd
add documentations
ada-jz7125 Jun 23, 2026
3ce7cd6
add tests, tests all passed for now
ada-jz7125 Jun 24, 2026
0e899a5
tidy up the notebook
ada-jz7125 Jun 24, 2026
e9a46d8
fix ModuleNotFoundError
ada-jz7125 Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"EvaluationFunctionName": ""
"EvaluationFunctionName": "compareMusic"
}
95 changes: 81 additions & 14 deletions docs/dev.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,96 @@
# YourFunctionName
*Brief description of what this evaluation function does, from the developer perspective*
# compareMusic

Automated formative feedback on music practice. Compares a student's MIDI performance against a reference MIDI and generates formatve, note-level feedback covering pitch accuracy, timing, and note duration.

## Inputs
*Specific input parameters which can be supplied when the `eval` command is supplied to this function.*
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `gap_penalty` | float | `6` | Alignment cost for a missing or extra note. Increase this if the function incorrectly splits one wrong note into a "missing + extra" pair. |
| `timing_relative_threshold` | float | `0.20` | Timing tolerance as a fraction of the inter-onset interval (IOI). `0.20` means up to 20% of the interval between consecutive notes. |
| `duration_relative_threshold` | float | `0.25` | Duration tolerance as a fraction of the reference note's duration. `0.25` means up to 25%. |
| `global_slow_threshold` | float | `1.15` | If the student's overall tempo scale exceeds this value, the overview reports "your tempo is slower than the reference". |
| `global_fast_threshold` | float | `0.85` | If the student's overall tempo scale falls below this value, the overview reports "your tempo is faster than the reference". |

Both `response` and `answer` (i.e. reference) must be a JSON object with a `notes` array:

```json
{
"notes": [
{"pitch": 60, "start": 0.00, "duration": 0.50},
{"pitch": 62, "start": 0.60, "duration": 0.50}
]
}
```

where `pitch` is an integer representing MIDI note number (e.g. middle C = 60), `start` is float representing note onset time in seconds, and `duration` is float in seconds.

## Outputs
*Output schema/values for this function*

## Examples
*List of example inputs and outputs for this function, each under a different sub-heading*
| Field | Type | Description |
|-------|------|-------------|
| `is_correct` | bool | `true` only when there are no missing notes, no extra notes, all pitches correct, all timing within threshold, and all durations within threshold |
| `feedback` | string | Human-readable feedback string |

The feedback string is divided into two sections:

**Overview** — overall tempo judgement, and counts of pitch errors, missing notes, and extra notes.

**Detail** — note-by-note breakdown of every specific issue found.

### Simple Evaluation

## Examples

### Perfect performance

```python
response = {
"notes": [
{"pitch": 60, "start": 0.00, "duration": 0.50},
{"pitch": 62, "start": 0.60, "duration": 0.50}
]
}
answer = {
"notes": [
{"pitch": 60, "start": 0.00, "duration": 0.50},
{"pitch": 62, "start": 0.60, "duration": 0.50}
]
}
params = {}
```

```python
{
"example": {
"Something": "something"
}
"is_correct": True,
"feedback": "Overview: \nTiming: your overall tempo is within an acceptable range. Good job! ...\n\nGreat performance! No further issues found."
}
```


### Wrong pitch and missing note

```python
response = {
"notes": [
{"pitch": 60, "start": 0.00, "duration": 0.50},
{"pitch": 63, "start": 0.60, "duration": 0.50},
{"pitch": 64, "start": 1.35, "duration": 0.50},
{"pitch": 65, "start": 1.80, "duration": 0.70}
]
}
answer = {
"notes": [
{"pitch": 60, "start": 0.00, "duration": 0.50},
{"pitch": 62, "start": 0.60, "duration": 0.50},
{"pitch": 64, "start": 1.20, "duration": 0.50},
{"pitch": 65, "start": 1.80, "duration": 0.50},
{"pitch": 67, "start": 2.50, "duration": 0.50}
]
}
params = {}
```

```python
{
"example": {
"Something": "something"
}
"is_correct": False,
"feedback": "Overview: \nTiming: your overall tempo is within an acceptable range. ...\nThere is 1 note played with the wrong pitch.\nThere is 1 note you missed from the reference.\nThere are no extra notes. Good job!\n\nDetail: \nNote 5 (pitch 67) is missing in your performance.\nNote 2: wrong pitch -- expected 62, played 63 (1 semitone(s) off)."
}
```
43 changes: 41 additions & 2 deletions docs/user.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
# YourFunctionName
# compareMusic

`compareMusic` automatically evaluates a student's MIDI music performance against a reference MIDI and returns structured, formative feedback on pitch accuracy, timing, and note duration.

## What the student sees

Feedback is returned in two parts:

**Overview** — a summary of overall tempo, and counts of pitch errors, missing notes, and extra notes.

**Detail** — a note-level feedback of every specific issue, including which notes were missed, which had the wrong pitch, and which were played noticeably early, late, or with an incorrect duration. The function separates **global tempo** (playing consistently faster or slower throughout) from **local timing errors** (a single note noticeably early or late relative to surrounding notes), which means student who plays the whole piece at 80% speed will receive one global tempo comment instead of repetitive comments on every note.

## Setting up a question

Set the **Answer** field to a JSON object representing the reference MIDI performance, e.g.:

```json
{
"notes": [
{"pitch": 60, "start": 0.00, "duration": 0.50},
{"pitch": 62, "start": 0.60, "duration": 0.50},
{"pitch": 64, "start": 1.20, "duration": 0.50}
]
}
```

where `pitch` is an integer representing MIDI note number (e.g. middle C = 60), `start` is float representing note onset time in seconds, and `duration` is float in seconds.

The student's **Response** must be in the same format.

## Adjusting strictness

All parameters are adjustable. If not set, the defaults below are used.

| Parameter | Default | What it controls |
|-----------|---------|-----------------|
| `timing_relative_threshold` | `0.20` | How much timing deviation is acceptable, as a fraction of the gap between consecutive notes. Lower = stricter. |
| `duration_relative_threshold` | `0.25` | How much duration deviation is acceptable, as a fraction of the reference note's duration. Lower = stricter. |
| `gap_penalty` | `6` | Controls note alignment. Increase this if the function incorrectly reports a wrong note as "missing + extra". |
| `global_slow_threshold` | `1.15` | Overall tempo more than 15% slower than reference triggers a "too slow" comment. |
| `global_fast_threshold` | `0.85` | Overall tempo more than 15% faster than reference triggers a "too fast" comment. |

Teacher-facing documentation for this function.
Loading
Loading