Skip to content

Commit 3a48de1

Browse files
committed
test-1
1 parent 2c71481 commit 3a48de1

File tree

10 files changed

+2400
-1
lines changed

10 files changed

+2400
-1
lines changed

css/activities.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,3 +2020,15 @@ table {
20202020
min-width: 250px;
20212021
max-width: 80%;
20222022
}
2023+
2024+
.lego-brick {
2025+
display: inline-block;
2026+
background-color: #FF0000;
2027+
border: 1px solid #880000;
2028+
margin: 2px;
2029+
}
2030+
2031+
.lego-size-1 { width: 20px; height: 10px; }
2032+
.lego-size-2 { width: 40px; height: 10px; }
2033+
/* ... more sizes ... */
2034+

css/style.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,15 @@ input[type="range"]:focus::-ms-fill-lower {
9999
input[type="range"]:focus::-ms-fill-upper {
100100
background: #90c100;
101101
}
102+
103+
.lego-brick {
104+
display: inline-block;
105+
background-color: #FF0000;
106+
border: 1px solid #880000;
107+
margin: 2px;
108+
}
109+
110+
.lego-size-1 { width: 20px; height: 10px; }
111+
.lego-size-2 { width: 40px; height: 10px; }
112+
/* ... more sizes ... */
113+

js/activity.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ if (_THIS_IS_MUSIC_BLOCKS_) {
172172
"widgets/timbre",
173173
"widgets/oscilloscope",
174174
"widgets/sampler",
175+
"widgets/legobricks",
175176
"activity/lilypond",
176177
"activity/abc",
177178
"activity/midi",

js/block.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4244,6 +4244,7 @@ class Block {
42444244
case "pitch staircase":
42454245
case "status":
42464246
case "phrase maker":
4247+
case "lego bricks":
42474248
case "custom mode":
42484249
case "music keyboard":
42494250
case "pitch drum":

js/blocks.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,7 @@ class Blocks {
15791579
case "pitch staircase":
15801580
case "status":
15811581
case "phrase maker":
1582+
case "lego bricks":
15821583
case "custom mode":
15831584
case "music keyboard":
15841585
case "pitch drum":
@@ -2035,6 +2036,7 @@ class Blocks {
20352036
case "pitch staircase":
20362037
case "status":
20372038
case "phrase maker":
2039+
case "lego bricks":
20382040
case "custom mode":
20392041
case "music keyboard":
20402042
case "pitch drum":

js/blocks/PitchBlocks.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,17 @@ function setupPitchBlocks(activity) {
16141614
// convert hertz to note/octave
16151615
const note = obj;
16161616
tur.singer.lastNotePlayed = [note[0] + note[1], 4];
1617+
} else if (logo.inLegoWidget) {
1618+
logo.legoWidget.addRowBlock(blk);
1619+
if (!logo.pitchBlocks.includes(blk)) {
1620+
logo.pitchBlocks.push(blk);
1621+
}
1622+
1623+
logo.legoWidget.rowLabels.push(activity.blocks.blockList[blk].name);
1624+
logo.legoWidget.rowArgs.push(arg.toFixed(0));
1625+
// convert hertz to note/octave
1626+
const note = obj;
1627+
tur.singer.lastNotePlayed = [note[0] + note[1], 4];
16171628
} else if (logo.inMusicKeyboard) {
16181629
logo.musicKeyboard.instruments.push(last(tur.singer.instrumentNames));
16191630
logo.musicKeyboard.noteNames.push("hertz");

js/blocks/WidgetBlocks.js

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
RhythmRuler, FILTERTYPES, instrumentsFilters, DEFAULTFILTERTYPE,
2020
TemperamentWidget, TimbreWidget, ModeWidget, PitchSlider,
2121
MusicKeyboard, PitchStaircase, SampleWidget, _THIS_IS_MUSIC_BLOCKS_,
22-
Arpeggio
22+
Arpeggio, LegoWidget
2323
*/
2424

2525
/*
@@ -60,6 +60,8 @@
6060
MusicKeyboard
6161
- js/widgets/pitchstaircase.js
6262
PitchStaircase
63+
- js/widgets/legobricks.js
64+
LegoWidget
6365
*/
6466

6567
/* exported setupWidgetBlocks */
@@ -1652,6 +1654,91 @@ function setupWidgetBlocks(activity) {
16521654
return [args[0], 1];
16531655
}
16541656
}
1657+
1658+
/**
1659+
* Represents a block for controlling LEGO brick parameters and visualization.
1660+
* @extends StackClampBlock
1661+
*/
1662+
class LegoBricksBlock extends StackClampBlock {
1663+
constructor() {
1664+
super("legobricks");
1665+
this.setPalette("widgets", activity);
1666+
this.parameter = true;
1667+
this.beginnerBlock(true);
1668+
1669+
this.setHelpString([
1670+
_("The LEGO Bricks block opens a widget for designing virtual LEGO creations."),
1671+
"documentation",
1672+
null,
1673+
"legobricks"
1674+
]);
1675+
1676+
//.TRANS: LEGO bricks designer
1677+
this.formBlock({ name: _("LEGO Bricks"), canCollapse: true });
1678+
this.makeMacro((x, y) => [
1679+
[0, "legobricks", x, y, [null, 1, 18]],
1680+
[1, "pitch", 0, 0, [0, 2, 3, 4]],
1681+
[2, ["solfege", { value: "do" }], 0, 0, [1]],
1682+
[3, ["number", { value: 4 }], 0, 0, [1]],
1683+
[4, "pitch", 0, 0, [1, 5, 6, 7]],
1684+
[5, ["solfege", { value: "re" }], 0, 0, [4]],
1685+
[6, ["number", { value: 4 }], 0, 0, [4]],
1686+
[7, "pitch", 0, 0, [4, 8, 9, 10]],
1687+
[8, ["solfege", { value: "mi" }], 0, 0, [7]],
1688+
[9, ["number", { value: 4 }], 0, 0, [7]],
1689+
[10, "pitch", 0, 0, [7, 11, 12, 13]],
1690+
[11, ["solfege", { value: "fa" }], 0, 0, [10]],
1691+
[12, ["number", { value: 4 }], 0, 0, [10]],
1692+
[13, "pitch", 0, 0, [10, 14, 15, 16]],
1693+
[14, ["solfege", { value: "sol" }], 0, 0, [13]],
1694+
[15, ["number", { value: 4 }], 0, 0, [13]],
1695+
[16, "playdrum", 0, 0, [13, 17, null]],
1696+
[17, ["drumname", { value: "kick drum" }], 0, 0, [16]],
1697+
[18, "hiddennoflow", 0, 0, [0, null]]
1698+
]);
1699+
}
1700+
1701+
/**
1702+
* Handles the flow of data for the LEGO bricks block.
1703+
* @param {any[]} args - The arguments passed to the block.
1704+
* @param {object} logo - The logo object.
1705+
* @param {object} turtle - The turtle object.
1706+
* @param {object} blk - The block object.
1707+
* @returns {number[]} - The output values.
1708+
*/
1709+
flow(args, logo, turtle, blk) {
1710+
logo.inLegoWidget = true;
1711+
1712+
if (logo.legoWidget === null) {
1713+
logo.legoWidget = new LegoWidget();
1714+
}
1715+
logo.legoWidget.blockNo = blk;
1716+
1717+
logo.legoWidget.rowLabels = [];
1718+
logo.legoWidget.rowArgs = [];
1719+
logo.legoWidget.clearBlocks();
1720+
1721+
const listenerName = "_legobricks_" + turtle;
1722+
logo.setDispatchBlock(blk, turtle, listenerName);
1723+
1724+
const __listener = () => {
1725+
if (logo.legoWidget.rowLabels.length === 0) {
1726+
activity.errorMsg(
1727+
_("You must have at least one pitch block in the LEGO bricks widget."),
1728+
blk
1729+
);
1730+
} else {
1731+
logo.legoWidget.blockNo = blk;
1732+
logo.legoWidget.init(activity);
1733+
}
1734+
logo.inLegoWidget = false;
1735+
};
1736+
1737+
logo.setTurtleListener(turtle, listenerName, __listener);
1738+
1739+
if (args.length === 1) return [args[0], 1];
1740+
}
1741+
}
16551742
// Set up blocks if this is Music Blocks environment
16561743
if (_THIS_IS_MUSIC_BLOCKS_) {
16571744
new EnvelopeBlock().setup(activity);
@@ -1667,6 +1754,7 @@ function setupWidgetBlocks(activity) {
16671754
new oscilloscopeWidgetBlock().setup(activity);
16681755
new PitchSliderBlock().setup(activity);
16691756
new ChromaticBlock().setup(activity);
1757+
new LegoBricksBlock().setup(activity);
16701758
// new AIMusicBlocks().setup(activity);
16711759
new MusicKeyboard2Block().setup(activity);
16721760
new MusicKeyboardBlock().setup(activity);

js/logo.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class Logo {
111111

112112
// Widgets
113113
this.phraseMaker = null;
114+
this.legoWidget = null;
114115
this.pitchDrumMatrix = null;
115116
this.arpeggio = null;
116117
this.rhythmRuler = null;
@@ -125,6 +126,7 @@ class Logo {
125126
this.oscilloscopeTurtles = [];
126127
this.meterWidget = null;
127128
this.statusMatrix = null;
129+
this.legobricks = null;
128130

129131
this.evalFlowDict = {};
130132
this.evalArgDict = {};
@@ -182,6 +184,7 @@ class Logo {
182184

183185
// pitch-rhythm matrix
184186
this.inMatrix = false;
187+
this.inLegoWidget = false;
185188
this.tupletRhythms = [];
186189
this.addingNotesToTuplet = false;
187190
this.drumBlocks = [];
@@ -1062,6 +1065,7 @@ class Logo {
10621065

10631066
this.inPitchDrumMatrix = false;
10641067
this.inMatrix = false;
1068+
this.inLegoWidget = false;
10651069
this.inMusicKeyboard = false;
10661070
this.inTimbre = false;
10671071
this.inArpeggio = false;

js/turtle-singer.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,14 @@ class Singer {
233233

234234
logo.phraseMaker.rowLabels.push(activity.logo.blocks.blockList[blk].name);
235235
logo.phraseMaker.rowArgs.push(args[0]);
236+
} else if (logo.inLegoWidget) {
237+
logo.legoWidget.addRowBlock(blk);
238+
if (!logo.pitchBlocks.includes(blk)) {
239+
logo.pitchBlocks.push(blk);
240+
}
241+
242+
logo.legoWidget.rowLabels.push(activity.logo.blocks.blockList[blk].name);
243+
logo.legoWidget.rowArgs.push(args[0]);
236244
} else if (logo.inPitchSlider) {
237245
logo.pitchSlider.frequency = args[0];
238246
} else {
@@ -910,6 +918,56 @@ class Singer {
910918
activity.logo.phraseMaker.rowArgs.push(noteObj[1]);
911919
}
912920
}
921+
} else if (activity.logo.inLegoWidget) {
922+
if (note.toLowerCase() !== "rest") {
923+
activity.logo.legoWidget.addRowBlock(blk);
924+
if (!activity.logo.pitchBlocks.includes(blk)) {
925+
activity.logo.pitchBlocks.push(blk);
926+
}
927+
}
928+
929+
const duplicateFactor =
930+
tur.singer.duplicateFactor.length > 0 ? tur.singer.duplicateFactor : 1;
931+
932+
for (let i = 0; i < duplicateFactor; i++) {
933+
// Apply transpositions
934+
const transposition = 2 * delta + tur.singer.transposition;
935+
const alen = tur.singer.arpeggio.length;
936+
let atrans = transposition + cents;
937+
if (alen > 0 && i < alen) {
938+
atrans += tur.singer.arpeggio[i];
939+
}
940+
const noteObj = getNote(
941+
note,
942+
octave,
943+
atrans, // transposition,
944+
tur.singer.keySignature,
945+
tur.singer.movable,
946+
null,
947+
activity.errorMsg,
948+
activity.logo.synth.inTemperament
949+
);
950+
tur.singer.previousNotePlayed = tur.singer.lastNotePlayed;
951+
tur.singer.lastNotePlayed = [noteObj[0] + noteObj[1], 4];
952+
953+
if (
954+
tur.singer.keySignature[0] === "C" &&
955+
tur.singer.keySignature[1].toLowerCase() === "major" &&
956+
noteIsSolfege(note)
957+
) {
958+
noteObj[0] = getSolfege(noteObj[0]);
959+
}
960+
961+
// If we are in a setdrum clamp, override the pitch.
962+
if (tur.singer.drumStyle.length > 0) {
963+
activity.logo.legoWidget.rowLabels.push(last(tur.singer.drumStyle));
964+
activity.logo.legoWidget.rowArgs.push(-1);
965+
} else {
966+
// Don't bother with the name conversions.
967+
activity.logo.legoWidget.rowLabels.push(noteObj[0]);
968+
activity.logo.legoWidget.rowArgs.push(noteObj[1]);
969+
}
970+
}
913971
} else if (tur.singer.inNoteBlock.length > 0) {
914972
// maybe of interest
915973
tur.singer.inverted = tur.singer.invertList.length > 0;
@@ -1479,6 +1537,12 @@ class Singer {
14791537
);
14801538
}
14811539
}
1540+
} else if (activity.logo.inLegoWidget) {
1541+
// For LEGO widget, we don't need to handle rhythm blocks currently
1542+
// Just store the note information
1543+
if (tur.singer.inNoteBlock.length > 0) {
1544+
// Could add timing information here if needed in the future
1545+
}
14821546

14831547
noteBeatValue *= tur.singer.beatFactor;
14841548
if (activity.logo.tuplet) {

0 commit comments

Comments
 (0)