upgrading music APIs (#12)
This commit is contained in:
		@@ -321,21 +321,30 @@
 | 
				
			|||||||
  "motors.motorCommand": "Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode.",
 | 
					  "motors.motorCommand": "Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode.",
 | 
				
			||||||
  "motors.motorPower": "Turns on the motor at a certain percent of power. Switches to single motor mode!",
 | 
					  "motors.motorPower": "Turns on the motor at a certain percent of power. Switches to single motor mode!",
 | 
				
			||||||
  "motors.motorPower|param|power": "%percent of power sent to the motor. Negative power goes backward. eg: 50",
 | 
					  "motors.motorPower|param|power": "%percent of power sent to the motor. Negative power goes backward. eg: 50",
 | 
				
			||||||
  "music": "Generation of music tones through pin ``P0``.",
 | 
					  "music": "Generation of music tones.",
 | 
				
			||||||
  "music.beat": "Returns the duration of a beat in milli-seconds",
 | 
					  "music.beat": "Returns the duration of a beat in milli-seconds",
 | 
				
			||||||
 | 
					  "music.beginMelody": "Starts playing a melody.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
 | 
				
			||||||
 | 
					  "music.beginMelody|param|melodyArray": "the melody array to play, eg: ['g5:1']",
 | 
				
			||||||
 | 
					  "music.beginMelody|param|options": "melody options, once / forever, in the foreground / background",
 | 
				
			||||||
 | 
					  "music.builtInMelody": "Gets the melody array of a built-in melody.",
 | 
				
			||||||
  "music.changeTempoBy": "Change the tempo by the specified amount",
 | 
					  "music.changeTempoBy": "Change the tempo by the specified amount",
 | 
				
			||||||
  "music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20",
 | 
					  "music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20",
 | 
				
			||||||
  "music.noteFrequency": "Gets the frequency of a note.",
 | 
					  "music.noteFrequency": "Gets the frequency of a note.",
 | 
				
			||||||
  "music.noteFrequency|param|name": "the note name",
 | 
					  "music.noteFrequency|param|name": "the note name, eg: Note.C",
 | 
				
			||||||
  "music.playTone": "Plays a tone through ``speaker`` for the given duration.",
 | 
					  "music.onEvent": "Registers code to run on various melody events",
 | 
				
			||||||
 | 
					  "music.playTone": "Plays a tone through pin ``P0`` for the given duration.",
 | 
				
			||||||
  "music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
 | 
					  "music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
 | 
				
			||||||
  "music.playTone|param|ms": "tone duration in milliseconds (ms)",
 | 
					  "music.playTone|param|ms": "tone duration in milliseconds (ms)",
 | 
				
			||||||
  "music.rest": "Rests (plays nothing) for a specified time through pin ``P0``.",
 | 
					  "music.rest": "Rests (plays nothing) for a specified time through pin ``P0``.",
 | 
				
			||||||
  "music.rest|param|ms": "rest duration in milliseconds (ms)",
 | 
					  "music.rest|param|ms": "rest duration in milliseconds (ms)",
 | 
				
			||||||
  "music.ringTone": "Plays a tone through ``speaker``.",
 | 
					  "music.ringTone": "Plays a tone through pin ``P0``.",
 | 
				
			||||||
  "music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
 | 
					  "music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
 | 
				
			||||||
 | 
					  "music.setPlayTone": "Sets a custom playTone function for playing melodies",
 | 
				
			||||||
  "music.setTempo": "Sets the tempo to the specified amount",
 | 
					  "music.setTempo": "Sets the tempo to the specified amount",
 | 
				
			||||||
  "music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
 | 
					  "music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
 | 
				
			||||||
 | 
					  "music.speakerPlayTone": "Plays a tone through ``speaker`` for the given duration.",
 | 
				
			||||||
 | 
					  "music.speakerPlayTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
 | 
				
			||||||
 | 
					  "music.speakerPlayTone|param|ms": "tone duration in milliseconds (ms)",
 | 
				
			||||||
  "music.tempo": "Returns the tempo in beats per minute. Tempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play.",
 | 
					  "music.tempo": "Returns the tempo in beats per minute. Tempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play.",
 | 
				
			||||||
  "parseInt": "Convert A string to an integer.",
 | 
					  "parseInt": "Convert A string to an integer.",
 | 
				
			||||||
  "pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...",
 | 
					  "pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,8 @@
 | 
				
			|||||||
  "BaudRate.BaudRate115200|block": "115200",
 | 
					  "BaudRate.BaudRate115200|block": "115200",
 | 
				
			||||||
  "BaudRate.BaudRate56700|block": "57600",
 | 
					  "BaudRate.BaudRate56700|block": "57600",
 | 
				
			||||||
  "BaudRate.BaudRate9600|block": "9600",
 | 
					  "BaudRate.BaudRate9600|block": "9600",
 | 
				
			||||||
 | 
					  "BeatFraction.Breve|block": "4",
 | 
				
			||||||
 | 
					  "BeatFraction.Double|block": "2",
 | 
				
			||||||
  "BeatFraction.Eighth|block": "1/8",
 | 
					  "BeatFraction.Eighth|block": "1/8",
 | 
				
			||||||
  "BeatFraction.Half|block": "1/2",
 | 
					  "BeatFraction.Half|block": "1/2",
 | 
				
			||||||
  "BeatFraction.Quarter|block": "1/4",
 | 
					  "BeatFraction.Quarter|block": "1/4",
 | 
				
			||||||
@@ -121,10 +123,44 @@
 | 
				
			|||||||
  "Math.randomBoolean|block": "pick random true or false",
 | 
					  "Math.randomBoolean|block": "pick random true or false",
 | 
				
			||||||
  "Math.random|block": "pick random 0 to %limit",
 | 
					  "Math.random|block": "pick random 0 to %limit",
 | 
				
			||||||
  "Math|block": "Math",
 | 
					  "Math|block": "Math",
 | 
				
			||||||
 | 
					  "Melodies.BaDing|block": "ba ding",
 | 
				
			||||||
 | 
					  "Melodies.Baddy|block": "baddy",
 | 
				
			||||||
 | 
					  "Melodies.Birthday|block": "birthday",
 | 
				
			||||||
 | 
					  "Melodies.Blues|block": "blues",
 | 
				
			||||||
 | 
					  "Melodies.Chase|block": "chase",
 | 
				
			||||||
 | 
					  "Melodies.Dadadadum|block": "dadadum",
 | 
				
			||||||
 | 
					  "Melodies.Entertainer|block": "entertainer",
 | 
				
			||||||
 | 
					  "Melodies.Funeral|block": "funereal",
 | 
				
			||||||
 | 
					  "Melodies.Funk|block": "funk",
 | 
				
			||||||
 | 
					  "Melodies.JumpDown|block": "jump down",
 | 
				
			||||||
 | 
					  "Melodies.JumpUp|block": "jump up",
 | 
				
			||||||
 | 
					  "Melodies.Nyan|block": "nyan",
 | 
				
			||||||
 | 
					  "Melodies.Ode|block": "ode",
 | 
				
			||||||
 | 
					  "Melodies.PowerDown|block": "power down",
 | 
				
			||||||
 | 
					  "Melodies.PowerUp|block": "power up",
 | 
				
			||||||
 | 
					  "Melodies.Prelude|block": "prelude",
 | 
				
			||||||
 | 
					  "Melodies.Punchline|block": "punchline",
 | 
				
			||||||
 | 
					  "Melodies.Ringtone|block": "ringtone",
 | 
				
			||||||
 | 
					  "Melodies.Wawawawaa|block": "wawawawaa",
 | 
				
			||||||
 | 
					  "Melodies.Wedding|block": "wedding",
 | 
				
			||||||
 | 
					  "MelodyOptions.ForeverInBackground|block": "forever in background",
 | 
				
			||||||
 | 
					  "MelodyOptions.Forever|block": "forever",
 | 
				
			||||||
 | 
					  "MelodyOptions.OnceInBackground|block": "once in background",
 | 
				
			||||||
 | 
					  "MelodyOptions.Once|block": "once",
 | 
				
			||||||
  "Motor.AB|block": "A and B",
 | 
					  "Motor.AB|block": "A and B",
 | 
				
			||||||
  "MotorCommand.Break|block": "break",
 | 
					  "MotorCommand.Break|block": "break",
 | 
				
			||||||
  "MotorCommand.Coast|block": "coast",
 | 
					  "MotorCommand.Coast|block": "coast",
 | 
				
			||||||
  "MotorCommand.Sleep|block": "sleep",
 | 
					  "MotorCommand.Sleep|block": "sleep",
 | 
				
			||||||
 | 
					  "MusicEvent.BackgroundMelodyEnded|block": "background melody ended",
 | 
				
			||||||
 | 
					  "MusicEvent.BackgroundMelodyNotePlayed|block": "background melody note played",
 | 
				
			||||||
 | 
					  "MusicEvent.BackgroundMelodyPaused|block": "background melody paused",
 | 
				
			||||||
 | 
					  "MusicEvent.BackgroundMelodyRepeated|block": "background melody repeated",
 | 
				
			||||||
 | 
					  "MusicEvent.BackgroundMelodyResumed|block": "background melody resumed",
 | 
				
			||||||
 | 
					  "MusicEvent.BackgroundMelodyStarted|block": "background melody started",
 | 
				
			||||||
 | 
					  "MusicEvent.MelodyEnded|block": "melody ended",
 | 
				
			||||||
 | 
					  "MusicEvent.MelodyNotePlayed|block": "melody note played",
 | 
				
			||||||
 | 
					  "MusicEvent.MelodyRepeated|block": "melody repeated",
 | 
				
			||||||
 | 
					  "MusicEvent.MelodyStarted|block": "melody started",
 | 
				
			||||||
  "Note.CSharp3|block": "C#3",
 | 
					  "Note.CSharp3|block": "C#3",
 | 
				
			||||||
  "Note.CSharp4|block": "C#4",
 | 
					  "Note.CSharp4|block": "C#4",
 | 
				
			||||||
  "Note.CSharp5|block": "C#5",
 | 
					  "Note.CSharp5|block": "C#5",
 | 
				
			||||||
@@ -225,8 +261,11 @@
 | 
				
			|||||||
  "motors.motorPower|block": "motor on at %percent",
 | 
					  "motors.motorPower|block": "motor on at %percent",
 | 
				
			||||||
  "motors|block": "motors",
 | 
					  "motors|block": "motors",
 | 
				
			||||||
  "music.beat|block": "%fraction|beat",
 | 
					  "music.beat|block": "%fraction|beat",
 | 
				
			||||||
 | 
					  "music.beginMelody|block": "start melody %melody=device_builtin_melody| repeating %options",
 | 
				
			||||||
 | 
					  "music.builtInMelody|block": "%melody",
 | 
				
			||||||
  "music.changeTempoBy|block": "change tempo by (bpm)|%value",
 | 
					  "music.changeTempoBy|block": "change tempo by (bpm)|%value",
 | 
				
			||||||
  "music.noteFrequency|block": "%note",
 | 
					  "music.noteFrequency|block": "%note",
 | 
				
			||||||
 | 
					  "music.onEvent|block": "music on %value",
 | 
				
			||||||
  "music.playTone|block": "play|tone %note=device_note|for %duration=device_beat",
 | 
					  "music.playTone|block": "play|tone %note=device_note|for %duration=device_beat",
 | 
				
			||||||
  "music.rest|block": "rest(ms)|%duration=device_beat",
 | 
					  "music.rest|block": "rest(ms)|%duration=device_beat",
 | 
				
			||||||
  "music.ringTone|block": "ring tone (Hz)|%note=device_note",
 | 
					  "music.ringTone|block": "ring tone (Hz)|%note=device_note",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										119
									
								
								libs/core/melodies.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								libs/core/melodies.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers, as listed
 | 
				
			||||||
 | 
					in the accompanying AUTHORS file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in
 | 
				
			||||||
 | 
					all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
				
			||||||
 | 
					THE SOFTWARE.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Melodies from file microbitmusictunes.c https://github.com/bbcmicrobit/MicroPython
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum Melodies {
 | 
				
			||||||
 | 
					    //% block="dadadum" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Dadadadum = 0,
 | 
				
			||||||
 | 
					    //% block="entertainer" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Entertainer,
 | 
				
			||||||
 | 
					    //% block="prelude" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Prelude,
 | 
				
			||||||
 | 
					    //% block="ode" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Ode,
 | 
				
			||||||
 | 
					    //% block="nyan" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Nyan,
 | 
				
			||||||
 | 
					    //% block="ringtone" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Ringtone,
 | 
				
			||||||
 | 
					    //% block="funk" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Funk,
 | 
				
			||||||
 | 
					    //% block="blues" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Blues,
 | 
				
			||||||
 | 
					    //% block="birthday" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Birthday,
 | 
				
			||||||
 | 
					    //% block="wedding" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Wedding,
 | 
				
			||||||
 | 
					    //% block="funereal" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Funeral,
 | 
				
			||||||
 | 
					    //% block="punchline" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Punchline,
 | 
				
			||||||
 | 
					    //% block="baddy" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Baddy,
 | 
				
			||||||
 | 
					    //% block="chase" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Chase,
 | 
				
			||||||
 | 
					    //% block="ba ding" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    BaDing,
 | 
				
			||||||
 | 
					    //% block="wawawawaa" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    Wawawawaa,
 | 
				
			||||||
 | 
					    //% block="jump up" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    JumpUp,
 | 
				
			||||||
 | 
					    //% block="jump down" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    JumpDown,
 | 
				
			||||||
 | 
					    //% block="power up" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    PowerUp,
 | 
				
			||||||
 | 
					    //% block="power down" blockIdentity=music.builtInMelody
 | 
				
			||||||
 | 
					    PowerDown,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace music {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function getMelody(melody: Melodies): string[] {
 | 
				
			||||||
 | 
					        switch (melody) {
 | 
				
			||||||
 | 
					            case Melodies.Dadadadum:
 | 
				
			||||||
 | 
					                return ['r4:2', 'g', 'g', 'g', 'eb:8', 'r:2', 'f', 'f', 'f', 'd:8'];
 | 
				
			||||||
 | 
					            case Melodies.Entertainer:
 | 
				
			||||||
 | 
					                return ['d4:1', 'd#', 'e', 'c5:2', 'e4:1', 'c5:2', 'e4:1', 'c5:3', 'c:1', 'd', 'd#', 'e', 'c', 'd', 'e:2', 'b4:1', 'd5:2', 'c:4'];
 | 
				
			||||||
 | 
					            case Melodies.Prelude:
 | 
				
			||||||
 | 
					                return ['c4:1', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e', 'c4', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e', 'c4', 'd', 'g', 'd5', 'f', 'g4', 'd5', 'f', 'c4', 'd', 'g', 'd5', 'f', 'g4', 'd5', 'f', 'b3', 'd4', 'g', 'd5', 'f', 'g4', 'd5', 'f', 'b3', 'd4', 'g', 'd5', 'f', 'g4', 'd5', 'f', 'c4', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e', 'c4', 'e', 'g', 'c5', 'e', 'g4', 'c5', 'e'];
 | 
				
			||||||
 | 
					            case Melodies.Ode:
 | 
				
			||||||
 | 
					                return ['e4', 'e', 'f', 'g', 'g', 'f', 'e', 'd', 'c', 'c', 'd', 'e', 'e:6', 'd:2', 'd:8', 'e:4', 'e', 'f', 'g', 'g', 'f', 'e', 'd', 'c', 'c', 'd', 'e', 'd:6', 'c:2', 'c:8'];
 | 
				
			||||||
 | 
					            case Melodies.Nyan:
 | 
				
			||||||
 | 
					                return ['f#5:2', 'g#', 'c#:1', 'd#:2', 'b4:1', 'd5:1', 'c#', 'b4:2', 'b', 'c#5', 'd', 'd:1', 'c#', 'b4:1', 'c#5:1', 'd#', 'f#', 'g#', 'd#', 'f#', 'c#', 'd', 'b4', 'c#5', 'b4', 'd#5:2', 'f#', 'g#:1', 'd#', 'f#', 'c#', 'd#', 'b4', 'd5', 'd#', 'd', 'c#', 'b4', 'c#5', 'd:2', 'b4:1', 'c#5', 'd#', 'f#', 'c#', 'd', 'c#', 'b4', 'c#5:2', 'b4', 'c#5', 'b4', 'f#:1', 'g#', 'b:2', 'f#:1', 'g#', 'b', 'c#5', 'd#', 'b4', 'e5', 'd#', 'e', 'f#', 'b4:2', 'b', 'f#:1', 'g#', 'b', 'f#', 'e5', 'd#', 'c#', 'b4', 'f#', 'd#', 'e', 'f#', 'b:2', 'f#:1', 'g#', 'b:2', 'f#:1', 'g#', 'b', 'b', 'c#5', 'd#', 'b4', 'f#', 'g#', 'f#', 'b:2', 'b:1', 'a#', 'b', 'f#', 'g#', 'b', 'e5', 'd#', 'e', 'f#', 'b4:2', 'c#5'];
 | 
				
			||||||
 | 
					            case Melodies.Ringtone:
 | 
				
			||||||
 | 
					                return ['c4:1', 'd', 'e:2', 'g', 'd:1', 'e', 'f:2', 'a', 'e:1', 'f', 'g:2', 'b', 'c5:4'];
 | 
				
			||||||
 | 
					            case Melodies.Funk:
 | 
				
			||||||
 | 
					                return ['c2:2', 'c', 'd#', 'c:1', 'f:2', 'c:1', 'f:2', 'f#', 'g', 'c', 'c', 'g', 'c:1', 'f#:2', 'c:1', 'f#:2', 'f', 'd#'];
 | 
				
			||||||
 | 
					            case Melodies.Blues:
 | 
				
			||||||
 | 
					                return ['c2:2', 'e', 'g', 'a', 'a#', 'a', 'g', 'e', 'c2:2', 'e', 'g', 'a', 'a#', 'a', 'g', 'e', 'f', 'a', 'c3', 'd', 'd#', 'd', 'c', 'a2', 'c2:2', 'e', 'g', 'a', 'a#', 'a', 'g', 'e', 'g', 'b', 'd3', 'f', 'f2', 'a', 'c3', 'd#', 'c2:2', 'e', 'g', 'e', 'g', 'f', 'e', 'd'];
 | 
				
			||||||
 | 
					            case Melodies.Birthday:
 | 
				
			||||||
 | 
					                return ['c4:3', 'c:1', 'd:4', 'c:4', 'f', 'e:8', 'c:3', 'c:1', 'd:4', 'c:4', 'g', 'f:8', 'c:3', 'c:1', 'c5:4', 'a4', 'f', 'e', 'd', 'a#:3', 'a#:1', 'a:4', 'f', 'g', 'f:8'];
 | 
				
			||||||
 | 
					            case Melodies.Wedding:
 | 
				
			||||||
 | 
					                return ['c4:4', 'f:3', 'f:1', 'f:8', 'c:4', 'g:3', 'e:1', 'f:8', 'c:4', 'f:3', 'a:1', 'c5:4', 'a4:3', 'f:1', 'f:4', 'e:3', 'f:1', 'g:8'];
 | 
				
			||||||
 | 
					            case Melodies.Funeral:
 | 
				
			||||||
 | 
					                return ['c3:4', 'c:3', 'c:1', 'c:4', 'd#:3', 'd:1', 'd:3', 'c:1', 'c:3', 'b2:1', 'c3:4'];
 | 
				
			||||||
 | 
					            case Melodies.Punchline:
 | 
				
			||||||
 | 
					                return ['c4:3', 'g3:1', 'f#', 'g', 'g#:3', 'g', 'r', 'b', 'c4'];
 | 
				
			||||||
 | 
					            case Melodies.Baddy:
 | 
				
			||||||
 | 
					                return ['c3:3', 'r', 'd:2', 'd#', 'r', 'c', 'r', 'f#:8'];
 | 
				
			||||||
 | 
					            case Melodies.Chase:
 | 
				
			||||||
 | 
					                return ['a4:1', 'b', 'c5', 'b4', 'a:2', 'r', 'a:1', 'b', 'c5', 'b4', 'a:2', 'r', 'a:2', 'e5', 'd#', 'e', 'f', 'e', 'd#', 'e', 'b4:1', 'c5', 'd', 'c', 'b4:2', 'r', 'b:1', 'c5', 'd', 'c', 'b4:2', 'r', 'b:2', 'e5', 'd#', 'e', 'f', 'e', 'd#', 'e'];
 | 
				
			||||||
 | 
					            case Melodies.BaDing:
 | 
				
			||||||
 | 
					                return ['b5:1', 'e6:3'];
 | 
				
			||||||
 | 
					            case Melodies.Wawawawaa:
 | 
				
			||||||
 | 
					                return ['e3:3', 'r:1', 'd#:3', 'r:1', 'd:4', 'r:1', 'c#:8'];
 | 
				
			||||||
 | 
					            case Melodies.JumpUp:
 | 
				
			||||||
 | 
					                return ['c5:1', 'd', 'e', 'f', 'g'];
 | 
				
			||||||
 | 
					            case Melodies.JumpDown:
 | 
				
			||||||
 | 
					                return ['g5:1', 'f', 'e', 'd', 'c'];
 | 
				
			||||||
 | 
					            case Melodies.PowerUp:
 | 
				
			||||||
 | 
					                return ['g4:1', 'c5', 'e', 'g:2', 'e:1', 'g:3'];
 | 
				
			||||||
 | 
					            case Melodies.PowerDown:
 | 
				
			||||||
 | 
					                return ['g5:1', 'd#', 'c', 'g4:2', 'b:1', 'c5:3'];
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,10 +6,9 @@ namespace music {
 | 
				
			|||||||
     * @param frequency pitch of the tone to play in Hertz (Hz)
 | 
					     * @param frequency pitch of the tone to play in Hertz (Hz)
 | 
				
			||||||
     * @param ms tone duration in milliseconds (ms)
 | 
					     * @param ms tone duration in milliseconds (ms)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=music/play-tone weight=90
 | 
					    //%
 | 
				
			||||||
    //% blockId=device_play_note block="play|tone %note=device_note|for %duration=device_beat" icon="\uf025" blockGap=8
 | 
					 | 
				
			||||||
    //% parts="speaker" async useEnumVal=1
 | 
					    //% parts="speaker" async useEnumVal=1
 | 
				
			||||||
    void playTone(int frequency, int ms) {
 | 
					    void speakerPlayTone(int frequency, int ms) {
 | 
				
			||||||
        if(frequency > 0) uBit.soundmotor.soundOn(frequency);
 | 
					        if(frequency > 0) uBit.soundmotor.soundOn(frequency);
 | 
				
			||||||
        else uBit.soundmotor.soundOff();
 | 
					        else uBit.soundmotor.soundOff();
 | 
				
			||||||
        if(ms > 0) {
 | 
					        if(ms > 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -119,15 +119,82 @@ enum BeatFraction {
 | 
				
			|||||||
    //% block="1/8"
 | 
					    //% block="1/8"
 | 
				
			||||||
    Eighth = 8,
 | 
					    Eighth = 8,
 | 
				
			||||||
    //% block="1/16"
 | 
					    //% block="1/16"
 | 
				
			||||||
    Sixteenth = 16
 | 
					    Sixteenth = 16,
 | 
				
			||||||
 | 
					    //% block="2"
 | 
				
			||||||
 | 
					    Double = 32,
 | 
				
			||||||
 | 
					    //% block="4",
 | 
				
			||||||
 | 
					    Breve = 64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum MelodyOptions {
 | 
				
			||||||
 | 
					    //% block="once""
 | 
				
			||||||
 | 
					    Once = 1,
 | 
				
			||||||
 | 
					    //% block="forever"
 | 
				
			||||||
 | 
					    Forever = 2,
 | 
				
			||||||
 | 
					    //% block="once in background"
 | 
				
			||||||
 | 
					    OnceInBackground = 4,
 | 
				
			||||||
 | 
					    //% block="forever in background"
 | 
				
			||||||
 | 
					    ForeverInBackground = 8
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum MusicEvent {
 | 
				
			||||||
 | 
					    //% block="melody note played"
 | 
				
			||||||
 | 
					    MelodyNotePlayed = 1,
 | 
				
			||||||
 | 
					    //% block="melody started"
 | 
				
			||||||
 | 
					    MelodyStarted = 2,
 | 
				
			||||||
 | 
					    //% block="melody ended"
 | 
				
			||||||
 | 
					    MelodyEnded = 3,
 | 
				
			||||||
 | 
					    //% block="melody repeated"
 | 
				
			||||||
 | 
					    MelodyRepeated = 4,
 | 
				
			||||||
 | 
					    //% block="background melody note played"
 | 
				
			||||||
 | 
					    BackgroundMelodyNotePlayed = MelodyNotePlayed | 0xf0,
 | 
				
			||||||
 | 
					    //% block="background melody started"
 | 
				
			||||||
 | 
					    BackgroundMelodyStarted = MelodyStarted | 0xf0,
 | 
				
			||||||
 | 
					    //% block="background melody ended"
 | 
				
			||||||
 | 
					    BackgroundMelodyEnded = MelodyEnded | 0xf0,
 | 
				
			||||||
 | 
					    //% block="background melody repeated"
 | 
				
			||||||
 | 
					    BackgroundMelodyRepeated = MelodyRepeated | 0xf0,
 | 
				
			||||||
 | 
					    //% block="background melody paused"
 | 
				
			||||||
 | 
					    BackgroundMelodyPaused = 5 | 0xf0,
 | 
				
			||||||
 | 
					    //% block="background melody resumed"
 | 
				
			||||||
 | 
					    BackgroundMelodyResumed = 6 | 0xf0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Generation of music tones through pin ``P0``.
 | 
					 * Generation of music tones.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
//% color=#DF4600 weight=98 icon="\uf025"
 | 
					//% color=#DF4600 weight=98 icon="\uf025"
 | 
				
			||||||
namespace music {
 | 
					namespace music {
 | 
				
			||||||
    let beatsPerMinute: number = 120;
 | 
					    let beatsPerMinute: number = 120;
 | 
				
			||||||
 | 
					    let freqTable: number[] = [];
 | 
				
			||||||
 | 
					    let _playTone: (frequency: number, duration: number) => void;
 | 
				
			||||||
 | 
					    const MICROBIT_MELODY_ID = 2000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Plays a tone through pin ``P0`` for the given duration.
 | 
				
			||||||
 | 
					     * @param frequency pitch of the tone to play in Hertz (Hz)
 | 
				
			||||||
 | 
					     * @param ms tone duration in milliseconds (ms)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=music/play-tone weight=90
 | 
				
			||||||
 | 
					    //% blockId=device_play_note block="play|tone %note=device_note|for %duration=device_beat" blockGap=8
 | 
				
			||||||
 | 
					    //% parts="headphone"
 | 
				
			||||||
 | 
					    //% useEnumVal=1
 | 
				
			||||||
 | 
					    export function playTone(frequency: number, ms: number): void {
 | 
				
			||||||
 | 
					        if (_playTone) _playTone(frequency, ms);
 | 
				
			||||||
 | 
					        else speakerPlayTone(frequency, ms);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Plays a tone through pin ``P0``.
 | 
				
			||||||
 | 
					     * @param frequency pitch of the tone to play in Hertz (Hz)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=music/ring-tone weight=80
 | 
				
			||||||
 | 
					    //% blockId=device_ring block="ring tone (Hz)|%note=device_note" blockGap=8
 | 
				
			||||||
 | 
					    //% parts="headphone"
 | 
				
			||||||
 | 
					    //% useEnumVal=1
 | 
				
			||||||
 | 
					    export function ringTone(frequency: number): void {
 | 
				
			||||||
 | 
					        playTone(frequency, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Rests (plays nothing) for a specified time through pin ``P0``.
 | 
					     * Rests (plays nothing) for a specified time through pin ``P0``.
 | 
				
			||||||
@@ -135,38 +202,28 @@ namespace music {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=music/rest weight=79
 | 
					    //% help=music/rest weight=79
 | 
				
			||||||
    //% blockId=device_rest block="rest(ms)|%duration=device_beat"
 | 
					    //% blockId=device_rest block="rest(ms)|%duration=device_beat"
 | 
				
			||||||
    //% parts="speaker"
 | 
					    //% parts="headphone"
 | 
				
			||||||
    export function rest(ms: number): void {
 | 
					    export function rest(ms: number): void {
 | 
				
			||||||
        playTone(0, ms);
 | 
					        playTone(0, ms);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Plays a tone through ``speaker``.
 | 
					 | 
				
			||||||
     * @param frequency pitch of the tone to play in Hertz (Hz)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=music/ring-tone weight=80
 | 
					 | 
				
			||||||
    //% blockId=device_ring block="ring tone (Hz)|%note=device_note" blockGap=8
 | 
					 | 
				
			||||||
    //% parts="speaker" async
 | 
					 | 
				
			||||||
    //% useEnumVal=1
 | 
					 | 
				
			||||||
    export function ringTone(frequency: number) {
 | 
					 | 
				
			||||||
        playTone(frequency, 0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets the frequency of a note.
 | 
					     * Gets the frequency of a note.
 | 
				
			||||||
     * @param name the note name
 | 
					     * @param name the note name, eg: Note.C
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% weight=50 help=music/note-frequency
 | 
					    //% weight=50 help=music/note-frequency
 | 
				
			||||||
    //% blockId=device_note block="%note"
 | 
					    //% blockId=device_note block="%note"
 | 
				
			||||||
    //% shim=TD_ID blockHidden=true
 | 
					    //% shim=TD_ID
 | 
				
			||||||
    //% blockFieldEditor="note_editor"
 | 
					    //% note.fieldEditor="note" note.defl="262"
 | 
				
			||||||
    //% useEnumVal = 1
 | 
					    //% useEnumVal=1
 | 
				
			||||||
    export function noteFrequency(name: Note): number {
 | 
					    export function noteFrequency(name: Note): number {
 | 
				
			||||||
        return name;
 | 
					        return name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function init() {
 | 
					    function init() {
 | 
				
			||||||
        if (beatsPerMinute <= 0) beatsPerMinute = 120;
 | 
					        if (beatsPerMinute <= 0) beatsPerMinute = 120;
 | 
				
			||||||
 | 
					        if (freqTable.length == 0) freqTable = [31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62, 65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 117, 123, 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 4186]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -178,11 +235,15 @@ namespace music {
 | 
				
			|||||||
        init();
 | 
					        init();
 | 
				
			||||||
        if (fraction == null) fraction = BeatFraction.Whole;
 | 
					        if (fraction == null) fraction = BeatFraction.Whole;
 | 
				
			||||||
        let beat = 60000 / beatsPerMinute;
 | 
					        let beat = 60000 / beatsPerMinute;
 | 
				
			||||||
        if (fraction == BeatFraction.Whole) return beat;
 | 
					        switch (fraction) {
 | 
				
			||||||
        else if (fraction == BeatFraction.Half) return beat / 2;
 | 
					            case BeatFraction.Half: return beat / 2;
 | 
				
			||||||
        else if (fraction == BeatFraction.Quarter) return beat / 4;
 | 
					            case BeatFraction.Quarter: return beat / 4;
 | 
				
			||||||
        else if (fraction == BeatFraction.Eighth) return beat / 8;
 | 
					            case BeatFraction.Eighth: return beat / 8;
 | 
				
			||||||
        else return beat / 16;
 | 
					            case BeatFraction.Sixteenth: return beat / 16;
 | 
				
			||||||
 | 
					            case BeatFraction.Double: return beat * 2;
 | 
				
			||||||
 | 
					            case BeatFraction.Breve: return beat * 4;
 | 
				
			||||||
 | 
					            default: return beat;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -212,10 +273,166 @@ namespace music {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=music/set-tempo weight=38
 | 
					    //% help=music/set-tempo weight=38
 | 
				
			||||||
    //% blockId=device_set_tempo block="set tempo to (bpm)|%value"
 | 
					    //% blockId=device_set_tempo block="set tempo to (bpm)|%value"
 | 
				
			||||||
 | 
					    //% bpm.min=4 bpm.max=400
 | 
				
			||||||
    export function setTempo(bpm: number): void {
 | 
					    export function setTempo(bpm: number): void {
 | 
				
			||||||
        init();
 | 
					        init();
 | 
				
			||||||
        if (bpm > 0) {
 | 
					        if (bpm > 0) {
 | 
				
			||||||
            beatsPerMinute = Math.max(1, bpm);
 | 
					            beatsPerMinute = Math.max(1, bpm);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let currentMelody: Melody;
 | 
				
			||||||
 | 
					    let currentBackgroundMelody: Melody;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the melody array of a built-in melody.
 | 
				
			||||||
 | 
					     * @param name the note name, eg: Note.C
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% weight=50 help=music/builtin-melody
 | 
				
			||||||
 | 
					    //% blockId=device_builtin_melody block="%melody"
 | 
				
			||||||
 | 
					    //% blockHidden=true
 | 
				
			||||||
 | 
					    export function builtInMelody(melody: Melodies): string[] {
 | 
				
			||||||
 | 
					        return getMelody(melody);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Registers code to run on various melody events
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% blockId=melody_on_event block="music on %value"
 | 
				
			||||||
 | 
					    //% help=music/on-event weight=59
 | 
				
			||||||
 | 
					    export function onEvent(value: MusicEvent, handler: Action) {
 | 
				
			||||||
 | 
					        control.onEvent(MICROBIT_MELODY_ID, value, handler);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Starts playing a melody.
 | 
				
			||||||
 | 
					     * Notes are expressed as a string of characters with this format: NOTE[octave][:duration]
 | 
				
			||||||
 | 
					     * @param melodyArray the melody array to play, eg: ['g5:1']
 | 
				
			||||||
 | 
					     * @param options melody options, once / forever, in the foreground / background
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=music/begin-melody weight=60 blockGap=8
 | 
				
			||||||
 | 
					    //% blockId=device_start_melody block="start melody %melody=device_builtin_melody| repeating %options"
 | 
				
			||||||
 | 
					    //% parts="headphone"
 | 
				
			||||||
 | 
					    export function beginMelody(melodyArray: string[], options: MelodyOptions = 1) {
 | 
				
			||||||
 | 
					        init();
 | 
				
			||||||
 | 
					        if (currentMelody != undefined) {
 | 
				
			||||||
 | 
					            if (((options & MelodyOptions.OnceInBackground) == 0)
 | 
				
			||||||
 | 
					                && ((options & MelodyOptions.ForeverInBackground) == 0)
 | 
				
			||||||
 | 
					                && currentMelody.background) {
 | 
				
			||||||
 | 
					                currentBackgroundMelody = currentMelody;
 | 
				
			||||||
 | 
					                currentMelody = null;
 | 
				
			||||||
 | 
					                control.raiseEvent(MICROBIT_MELODY_ID, MusicEvent.BackgroundMelodyPaused);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (currentMelody)
 | 
				
			||||||
 | 
					                control.raiseEvent(MICROBIT_MELODY_ID, currentMelody.background ? MusicEvent.BackgroundMelodyEnded : MusicEvent.MelodyEnded);
 | 
				
			||||||
 | 
					            currentMelody = new Melody(melodyArray, options);
 | 
				
			||||||
 | 
					            control.raiseEvent(MICROBIT_MELODY_ID, currentMelody.background ? MusicEvent.BackgroundMelodyStarted : MusicEvent.MelodyStarted);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            currentMelody = new Melody(melodyArray, options);
 | 
				
			||||||
 | 
					            control.raiseEvent(MICROBIT_MELODY_ID, currentMelody.background ? MusicEvent.BackgroundMelodyStarted : MusicEvent.MelodyStarted);
 | 
				
			||||||
 | 
					            // Only start the fiber once
 | 
				
			||||||
 | 
					            control.inBackground(() => {
 | 
				
			||||||
 | 
					                while (currentMelody.hasNextNote()) {
 | 
				
			||||||
 | 
					                    playNextNote(currentMelody);
 | 
				
			||||||
 | 
					                    if (!currentMelody.hasNextNote() && currentBackgroundMelody) {
 | 
				
			||||||
 | 
					                        // Swap the background melody back
 | 
				
			||||||
 | 
					                        currentMelody = currentBackgroundMelody;
 | 
				
			||||||
 | 
					                        currentBackgroundMelody = null;
 | 
				
			||||||
 | 
					                        control.raiseEvent(MICROBIT_MELODY_ID, MusicEvent.MelodyEnded);
 | 
				
			||||||
 | 
					                        control.raiseEvent(MICROBIT_MELODY_ID, MusicEvent.BackgroundMelodyResumed);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                control.raiseEvent(MICROBIT_MELODY_ID, currentMelody.background ? MusicEvent.BackgroundMelodyEnded : MusicEvent.MelodyEnded);
 | 
				
			||||||
 | 
					                currentMelody = null;
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sets a custom playTone function for playing melodies
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=music/set-play-tone
 | 
				
			||||||
 | 
					    //% advanced=true
 | 
				
			||||||
 | 
					    export function setPlayTone(f: (frequency: number, duration: number) => void) {
 | 
				
			||||||
 | 
					        _playTone = f;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function playNextNote(melody: Melody): void {
 | 
				
			||||||
 | 
					        // cache elements
 | 
				
			||||||
 | 
					        let currNote = melody.nextNote();
 | 
				
			||||||
 | 
					        let currentPos = melody.currentPos;
 | 
				
			||||||
 | 
					        let currentDuration = melody.currentDuration;
 | 
				
			||||||
 | 
					        let currentOctave = melody.currentOctave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let note: number;
 | 
				
			||||||
 | 
					        let isrest: boolean = false;
 | 
				
			||||||
 | 
					        let beatPos: number;
 | 
				
			||||||
 | 
					        let parsingOctave: boolean = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let pos = 0; pos < currNote.length; pos++) {
 | 
				
			||||||
 | 
					            let noteChar = currNote.charAt(pos);
 | 
				
			||||||
 | 
					            switch (noteChar) {
 | 
				
			||||||
 | 
					                case 'c': case 'C': note = 1; break;
 | 
				
			||||||
 | 
					                case 'd': case 'D': note = 3; break;
 | 
				
			||||||
 | 
					                case 'e': case 'E': note = 5; break;
 | 
				
			||||||
 | 
					                case 'f': case 'F': note = 6; break;
 | 
				
			||||||
 | 
					                case 'g': case 'G': note = 8; break;
 | 
				
			||||||
 | 
					                case 'a': case 'A': note = 10; break;
 | 
				
			||||||
 | 
					                case 'b': case 'B': note = 12; break;
 | 
				
			||||||
 | 
					                case 'r': case 'R': isrest = true; break;
 | 
				
			||||||
 | 
					                case '#': note++; break;
 | 
				
			||||||
 | 
					                case 'b': note--; break;
 | 
				
			||||||
 | 
					                case ':': parsingOctave = false; beatPos = pos; break;
 | 
				
			||||||
 | 
					                default: if (parsingOctave) currentOctave = parseInt(noteChar);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!parsingOctave) {
 | 
				
			||||||
 | 
					            currentDuration = parseInt(currNote.substr(beatPos + 1, currNote.length - beatPos));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let beat = (60000 / beatsPerMinute) / 4;
 | 
				
			||||||
 | 
					        if (isrest) {
 | 
				
			||||||
 | 
					            music.rest(currentDuration * beat)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let keyNumber = note + (12 * (currentOctave - 1));
 | 
				
			||||||
 | 
					            let frequency = keyNumber >= 0 && keyNumber < freqTable.length ? freqTable[keyNumber] : 0;
 | 
				
			||||||
 | 
					            music.playTone(frequency, currentDuration * beat);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        melody.currentDuration = currentDuration;
 | 
				
			||||||
 | 
					        melody.currentOctave = currentOctave;
 | 
				
			||||||
 | 
					        const repeating = melody.repeating && currentPos == melody.melodyArray.length - 1;
 | 
				
			||||||
 | 
					        melody.currentPos = repeating ? 0 : currentPos + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        control.raiseEvent(MICROBIT_MELODY_ID, melody.background ? MusicEvent.BackgroundMelodyNotePlayed : MusicEvent.MelodyNotePlayed);
 | 
				
			||||||
 | 
					        if (repeating)
 | 
				
			||||||
 | 
					            control.raiseEvent(MICROBIT_MELODY_ID, melody.background ? MusicEvent.BackgroundMelodyRepeated : MusicEvent.MelodyRepeated);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Melody {
 | 
				
			||||||
 | 
					        public melodyArray: string[];
 | 
				
			||||||
 | 
					        public currentDuration: number;
 | 
				
			||||||
 | 
					        public currentOctave: number;
 | 
				
			||||||
 | 
					        public currentPos: number;
 | 
				
			||||||
 | 
					        public repeating: boolean;
 | 
				
			||||||
 | 
					        public background: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constructor(melodyArray: string[], options: MelodyOptions) {
 | 
				
			||||||
 | 
					            this.melodyArray = melodyArray;
 | 
				
			||||||
 | 
					            this.repeating = ((options & MelodyOptions.Forever) != 0);
 | 
				
			||||||
 | 
					            this.repeating = this.repeating ? true : ((options & MelodyOptions.ForeverInBackground) != 0)
 | 
				
			||||||
 | 
					            this.background = ((options & MelodyOptions.OnceInBackground) != 0);
 | 
				
			||||||
 | 
					            this.background = this.background ? true : ((options & MelodyOptions.ForeverInBackground) != 0);
 | 
				
			||||||
 | 
					            this.currentDuration = 4; //Default duration (Crotchet)
 | 
				
			||||||
 | 
					            this.currentOctave = 4; //Middle octave
 | 
				
			||||||
 | 
					            this.currentPos = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hasNextNote() {
 | 
				
			||||||
 | 
					            return this.repeating || this.currentPos < this.melodyArray.length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nextNote(): string {
 | 
				
			||||||
 | 
					            const currentNote = this.melodyArray[this.currentPos];
 | 
				
			||||||
 | 
					            return currentNote;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@
 | 
				
			|||||||
        "led.ts",
 | 
					        "led.ts",
 | 
				
			||||||
        "motors.cpp",
 | 
					        "motors.cpp",
 | 
				
			||||||
        "music.cpp",
 | 
					        "music.cpp",
 | 
				
			||||||
 | 
					        "melodies.ts",
 | 
				
			||||||
        "music.ts",
 | 
					        "music.ts",
 | 
				
			||||||
        "pins.cpp",
 | 
					        "pins.cpp",
 | 
				
			||||||
        "pins.ts",
 | 
					        "pins.ts",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -552,10 +552,9 @@ declare namespace music {
 | 
				
			|||||||
     * @param frequency pitch of the tone to play in Hertz (Hz)
 | 
					     * @param frequency pitch of the tone to play in Hertz (Hz)
 | 
				
			||||||
     * @param ms tone duration in milliseconds (ms)
 | 
					     * @param ms tone duration in milliseconds (ms)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=music/play-tone weight=90
 | 
					    //%
 | 
				
			||||||
    //% blockId=device_play_note block="play|tone %note=device_note|for %duration=device_beat" icon="\uf025" blockGap=8
 | 
					    //% parts="speaker" async useEnumVal=1 shim=music::speakerPlayTone
 | 
				
			||||||
    //% parts="speaker" async useEnumVal=1 shim=music::playTone
 | 
					    function speakerPlayTone(frequency: number, ms: number): void;
 | 
				
			||||||
    function playTone(frequency: number, ms: number): void;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
declare namespace pins {
 | 
					declare namespace pins {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,8 @@
 | 
				
			|||||||
        "listsBlocks": true,
 | 
					        "listsBlocks": true,
 | 
				
			||||||
        "functionBlocks": true,        
 | 
					        "functionBlocks": true,        
 | 
				
			||||||
        "onStartColor": "#54C9C9",
 | 
					        "onStartColor": "#54C9C9",
 | 
				
			||||||
        "onStartNamespace": "basic"
 | 
					        "onStartNamespace": "basic",
 | 
				
			||||||
 | 
					        "onStartWeight": 54
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "simulator": {
 | 
					    "simulator": {
 | 
				
			||||||
        "autoRun": true,
 | 
					        "autoRun": true,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ namespace pxsim {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
namespace pxsim.music {
 | 
					namespace pxsim.music {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    export function playTone(frequency: number, ms: number) {
 | 
					    export function speakerPlayTone(frequency: number, ms: number) {
 | 
				
			||||||
        const b = board();
 | 
					        const b = board();
 | 
				
			||||||
        b.speakerState.frequency = frequency;
 | 
					        b.speakerState.frequency = frequency;
 | 
				
			||||||
        b.speakerState.ms = ms;
 | 
					        b.speakerState.ms = ms;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user