Musical scale: Difference between revisions
→{{header|AutoHotkey}}: Created entry |
|||
(109 intermediate revisions by 46 users not shown) | |||
Line 1: | Line 1: | ||
{{ |
{{task}} |
||
[[Category:Temporal media]] |
[[Category:Temporal media]] |
||
{{omit from|BASIC}} |
|||
Output 8 notes of the C major natural diatonic music scale (These are the notes C,D,E,F,G,A,B,c or Do, Ra, Me, Fa, So, La, Te, do on the solfa) to the default musical sound device on the system. For the purpose of this task, middle C should be used as the starting note, and crotchet notes should be used. |
|||
{{omit from|Blast}} |
|||
{{omit from|Brlcad}} |
|||
{{omit from|Openscad}} |
|||
;Task: |
|||
For languages that cannot utilize a sound device, it is permissible to output to a musical score sheet or midi file or the task can be omitted. |
|||
Output the 8 notes of the <b>C major</b> diatonic scale to the default musical sound device on the system. Specifically, pitch must be tuned to 12-tone equal temperament (12TET) with the modern standard A=440Hz. |
|||
These are the notes "C, D, E, F, G, A, B, C(1 octave higher)", or "Do, Re, Mi, Fa, Sol, La, Si/Ti, Do(1 octave higher)" on <i>Fixed do Solfège</i>. |
|||
For the purpose of this task, <b>Middle C</b> (in the case of the above tuning, around 261.63 Hz) should be used as the starting note, and any note duration is allowed. |
|||
For languages that cannot utilize a sound device, it is permissible to output to a musical score sheet (or midi file), or the task can be omitted. |
|||
=={{header|Action!}}== |
|||
<syntaxhighlight lang="action!">DEFINE PTR="CARD" |
|||
PROC Wait(BYTE frames) |
|||
BYTE RTCLOK=$14 |
|||
frames==+RTCLOK |
|||
WHILE frames#RTCLOK DO OD |
|||
RETURN |
|||
PROC Main() |
|||
BYTE AUDCTL=$D208,AUDF1=$D200,AUDC1=$D201,AUDF2=$D202,AUDC2=$D203 |
|||
PTR ARRAY notes(8) |
|||
BYTE ARRAY pitch8=[60 53 47 45 40 35 31 30] |
|||
CARD ARRAY pitch16=[1703 1517 1350 1274 1134 1010 899 848] |
|||
BYTE i |
|||
CARD p |
|||
notes(0)="Do" notes(1)="Re" notes(2)="Mi" notes(3)="Fa" |
|||
notes(4)="Sol" notes(5)="La" notes(6)="Si" notes(7)="Do" |
|||
PrintE("8-bit precision pitch values:") |
|||
FOR i=0 TO 7 |
|||
DO |
|||
PrintF("%S-%B ",notes(i),pitch8(i)) |
|||
Sound(0,pitch8(i),10,10) |
|||
Wait(20) |
|||
OD |
|||
SndRst() |
|||
Wait(20) |
|||
PutE() PutE() |
|||
AUDCTL=$50 ;join channel 1 and 2 to get 16-bit |
|||
AUDC1=$A0 ;turn off channel 1 |
|||
AUDC2=$AA ;turn on channel 2 |
|||
PrintE("16-bit precision pitch values:") |
|||
FOR i=0 TO 7 |
|||
DO |
|||
PrintF("%S-%U ",notes(i),pitch16(i)) |
|||
p=pitch16(i) |
|||
AUDF2=p RSH 8 |
|||
AUDF1=p&$FF |
|||
Wait(20) |
|||
OD |
|||
SndRst() |
|||
AUDCTL=$00 ;restore default configuration |
|||
Wait(20) |
|||
RETURN</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Musical_scale.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
8-bit precision pitch values: |
|||
Do-60 Re-53 Mi-47 Fa-45 Sol-40 La-35 Si-31 Do-30 |
|||
16-bit precision pitch values: |
|||
Do-1703 Re-1517 Mi-1350 Fa-1274 Sol-1134 La-1010 Si-899 Do-848 |
|||
</pre> |
|||
=={{header|Ada}}== |
|||
{{works with|GNAT Ada 2022}} |
|||
Ada runs everywhere, so we can't assume a sound device. This program outputs both a MIDI and a WAV audio file. |
|||
<syntaxhighlight lang="ada"> |
|||
pragma Ada_2022; |
|||
with Ada.Numerics; use Ada.Numerics; |
|||
with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions; |
|||
with Ada.Sequential_IO; |
|||
with Interfaces; use Interfaces; |
|||
procedure Musical_Scale is |
|||
package Byte_IO is new Ada.Sequential_IO (Unsigned_8); use Byte_IO; |
|||
SAMPLE_RATE : constant Unsigned_32 := 44100; |
|||
DURATION : constant Unsigned_32 := 8; |
|||
DATA_LENGTH : constant Unsigned_32 := SAMPLE_RATE * DURATION; |
|||
WAV_HDR_LEN : constant Integer := 44; |
|||
FILE_SIZE_8 : constant Unsigned_32 := Unsigned_32 (WAV_HDR_LEN) + DATA_LENGTH + 4; |
|||
type Byte_Arr is array (Positive range <>) of Unsigned_8; |
|||
Wav_Header : constant Byte_Arr (1 .. WAV_HDR_LEN) := [ |
|||
Character'Pos ('R'), Character'Pos ('I'), Character'Pos ('F'), Character'Pos ('F'), |
|||
Unsigned_8 (FILE_SIZE_8 and 16#ff#), |
|||
Unsigned_8 (Shift_Right (FILE_SIZE_8, 8) and 16#ff#), |
|||
Unsigned_8 (Shift_Right (FILE_SIZE_8, 16) and 16#ff#), |
|||
Unsigned_8 (Shift_Right (FILE_SIZE_8, 24) and 16#ff#), |
|||
Character'Pos ('W'), Character'Pos ('A'), Character'Pos ('V'), Character'Pos ('E'), |
|||
Character'Pos ('f'), Character'Pos ('m'), Character'Pos ('t'), Character'Pos (' '), |
|||
16#10#, 0, 0, 0, 1, 0, 1, 0, 16#44#, 16#ac#, 0, 0, 16#44#, 16#ac#, 0, 0, 1, 0, 8, 0, |
|||
Character'Pos ('d'), Character'Pos ('a'), Character'Pos ('t'), Character'Pos ('a'), |
|||
Unsigned_8 (DATA_LENGTH and 16#ff#), |
|||
Unsigned_8 (Shift_Right (DATA_LENGTH, 8) and 16#ff#), |
|||
Unsigned_8 (Shift_Right (DATA_LENGTH, 16) and 16#ff#), |
|||
Unsigned_8 (Shift_Right (DATA_LENGTH, 24) and 16#ff#) |
|||
]; |
|||
MIDI_Header : constant Byte_Arr (1 .. 22) := [ |
|||
Character'Pos ('M'), Character'Pos ('T'), Character'Pos ('h'), Character'Pos ('d'), |
|||
0, 0, 0, 6, 0, 0, 0, 1, 0, 96, -- File header |
|||
Character'Pos ('M'), Character'Pos ('T'), Character'Pos ('r'), Character'Pos ('k'), |
|||
0, 0, 0, 8 * 8 + 4 -- Track header |
|||
]; |
|||
MIDI_Trailer : constant Byte_Arr := [0, 16#ff#, 16#2f#, 0]; |
|||
type Freq_Arr is array (Positive range <>) of Float; |
|||
Freqs : constant Freq_Arr := [261.63, 293.67, 329.63, 349.23, 392.0, 440.0, 493.88, 523.25]; |
|||
Notes : constant Byte_Arr := [60, 62, 64, 65, 67, 69, 71, 72]; |
|||
Note_On_Off : Byte_Arr := [0, 16#90#, 0, 16#40#, 16#60#, 16#80#, 0, 0]; |
|||
Wav_File, MIDI_File : File_Type; |
|||
Omega : Float; |
|||
procedure Write_Arr (File : File_Type; Arr : Byte_Arr) is |
|||
begin |
|||
for B of Arr loop |
|||
Write (File, B); |
|||
end loop; |
|||
end Write_Arr; |
|||
begin |
|||
Create (Wav_File, Out_File, "scale.wav"); |
|||
Write_Arr (Wav_File, Wav_Header); |
|||
for Freq of Freqs loop |
|||
Omega := 2.0 * Pi * Freq; |
|||
for Tick in 0 .. Integer (DATA_LENGTH) / 8 loop |
|||
Write (Wav_File, Unsigned_8 (32.0 * (Sin (Omega * Float (Tick) / Float (SAMPLE_RATE)) + 1.0))); |
|||
end loop; |
|||
end loop; |
|||
Close (Wav_File); |
|||
Create (MIDI_File, Out_File, "scale.mid"); |
|||
Write_Arr (MIDI_File, MIDI_Header); |
|||
for Note of Notes loop |
|||
Note_On_Off (3) := Note; |
|||
Note_On_Off (7) := Note; |
|||
Write_Arr (MIDI_File, Note_On_Off); |
|||
end loop; |
|||
Write_Arr (MIDI_File, MIDI_Trailer); |
|||
Close (MIDI_File); |
|||
end Musical_Scale; |
|||
</syntaxhighlight> |
|||
=={{header|AmigaBASIC}}== |
|||
<syntaxhighlight lang="qbasic">FOR i=1 to 8 |
|||
READ f |
|||
SOUND f,10 |
|||
NEXT |
|||
DATA 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25</syntaxhighlight> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
{{works with| |
{{works with|AutoHotkey 1.1}} |
||
< |
<syntaxhighlight lang="autohotkey">for key, val in [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25] |
||
SoundBeep, % val, 500</ |
SoundBeep, % val, 500</syntaxhighlight> |
||
=={{header|BASIC256}}== |
|||
<syntaxhighlight lang="basic256">sound {261.63, 500, 293.66, 500, 329.63, 500, 349.23, 500, 392, 500, 440, 500, 493.88, 500, 523.25, 500}</syntaxhighlight> |
|||
=={{header|Befunge}}== |
|||
Befunge has no sound support, so this example generates a MIDI file that plays the sequence of notes. The file is written to stdout, so requires an interpreter that can cleanly redirect its output to a file (for example the [[bef]] reference implementation requires the ''-q'' option to suppress its version banner). |
|||
The tune to be played is specified on the first line of the code. The notes are specified as MIDI note numbers in reverse order in a Befunge string (for example, ''Middle C'' is note number 60, which is the character "<"). This is followed by the count of notes in the string - 8 in this example. |
|||
<syntaxhighlight lang="befunge">> "HGECA@><"8: v |
|||
v0*73"MThd"0006010101"MTrk"000< |
|||
>>#1-#,:#\_$8*74++,0,28*"'"039v |
|||
v,:,\,*2,1"Hd":\<,,,,,,*3"U"*9< |
|||
>"@1",2*,\,,1-:#^_"/3d",5*,,, @</syntaxhighlight> |
|||
=={{header|C}}== |
=={{header|C}}== |
||
Although C provides low level access to devices, there is no standardized way |
Although C provides low level access to devices, there is no standardized way. |
||
Here are illustrated two approaches. |
|||
=== |
===Borland's Turbo C=== |
||
Borland's Turbo C system has the dos.h header file which contains the functions sound() and nosound(). |
Borland's Turbo C system has the dos.h header file which contains the functions sound() and nosound(). |
||
sound() takes an argument which is the frequency of the note to be played through the device speaker. |
|||
delay(), also part of dos.h tells the code how long to suspend execution. |
|||
The sound will however still be playing. |
|||
It is therefore essential to call nosound() at the end which ends the speaker output, otherwise the Turbo C (DOS) session will have to be ended. |
|||
<syntaxhighlight lang="c"> |
|||
<lang C> |
|||
/*Abhishek Ghosh, 6th November 2013, Rotterdam*/ |
|||
#include<stdio.h> |
#include<stdio.h> |
||
#include<conio.h> |
#include<conio.h> |
||
Line 30: | Line 204: | ||
note sequence[] = {{"Do",0},{"Re",2},{"Mi",4},{"Fa",5},{"So",7},{"La",9},{"Ti",11},{"Do",12}}; |
note sequence[] = {{"Do",0},{"Re",2},{"Mi",4},{"Fa",5},{"So",7},{"La",9},{"Ti",11},{"Do",12}}; |
||
int main() |
int main(void) |
||
{ |
{ |
||
int i=0; |
int i=0; |
||
Line 44: | Line 218: | ||
nosound(); |
nosound(); |
||
return 0; |
return 0; |
||
}</syntaxhighlight> |
|||
} |
|||
</lang> |
|||
=== |
===Windows C=== |
||
I named it Windows C for want of a better name. |
|||
I named it Windows C for want of a better name. This is actually more constrained than the above example since although it will run on any Windows machine, Beep can only play integer frequencies and thus the tones are noticeably lower than the ones played by sound() above. |
|||
This is actually more constrained than the above example, |
|||
since although it will run on any Windows machine, |
|||
Beep() can only play integer frequencies and thus the tones are noticeably lower than the ones played by sound() above. |
|||
<syntaxhighlight lang="c"> |
|||
<lang C> |
|||
/*Abhishek Ghosh, 6th November 2013, Rotterdam*/ |
|||
#include<windows.h> |
#include<windows.h> |
||
#include<stdio.h> |
#include<stdio.h> |
||
Line 63: | Line 238: | ||
note sequence[] = {{"Do",0},{"Re",2},{"Mi",4},{"Fa",5},{"So",7},{"La",9},{"Ti",11},{"Do",12}}; |
note sequence[] = {{"Do",0},{"Re",2},{"Mi",4},{"Fa",5},{"So",7},{"La",9},{"Ti",11},{"Do",12}}; |
||
int main() |
int main(void) |
||
{ |
{ |
||
int i=0; |
int i=0; |
||
Line 75: | Line 250: | ||
} |
} |
||
return 0; |
return 0; |
||
}</syntaxhighlight> |
|||
=={{header|C++}}== |
|||
Uses Windows MIDI device |
|||
<syntaxhighlight lang="cpp"> |
|||
#include <iostream> |
|||
#include <windows.h> |
|||
#include <mmsystem.h> |
|||
#pragma comment ( lib, "winmm.lib" ) |
|||
typedef unsigned char byte; |
|||
typedef union |
|||
{ |
|||
unsigned long word; |
|||
unsigned char data[4]; |
|||
} |
} |
||
midi_msg; |
|||
</lang> |
|||
class midi |
|||
{ |
|||
public: |
|||
midi() |
|||
{ |
|||
if( midiOutOpen( &device, 0, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR ) |
|||
{ |
|||
std::cout << "Error opening MIDI Output..." << std::endl; |
|||
device = 0; |
|||
} |
|||
} |
|||
~midi() |
|||
{ |
|||
midiOutReset( device ); |
|||
midiOutClose( device ); |
|||
} |
|||
bool isOpen() { return device != 0; } |
|||
void setInstrument( byte i ) |
|||
{ |
|||
message.data[0] = 0xc0; message.data[1] = i; |
|||
message.data[2] = 0; message.data[3] = 0; |
|||
midiOutShortMsg( device, message.word ); |
|||
} |
|||
void playNote( byte n, unsigned i ) |
|||
{ |
|||
playNote( n ); Sleep( i ); stopNote( n ); |
|||
} |
|||
private: |
|||
void playNote( byte n ) |
|||
{ |
|||
message.data[0] = 0x90; message.data[1] = n; |
|||
message.data[2] = 127; message.data[3] = 0; |
|||
midiOutShortMsg( device, message.word ); |
|||
} |
|||
void stopNote( byte n ) |
|||
{ |
|||
message.data[0] = 0x90; message.data[1] = n; |
|||
message.data[2] = 0; message.data[3] = 0; |
|||
midiOutShortMsg( device, message.word ); |
|||
} |
|||
HMIDIOUT device; |
|||
midi_msg message; |
|||
}; |
|||
int main( int argc, char* argv[] ) |
|||
{ |
|||
midi m; |
|||
if( m.isOpen() ) |
|||
{ |
|||
byte notes[] = { 60, 62, 64, 65, 67, 69, 71, 72 }; |
|||
m.setInstrument( 42 ); |
|||
for( int x = 0; x < 8; x++ ) |
|||
m.playNote( notes[x], rand() % 100 + 158 ); |
|||
Sleep( 1000 ); |
|||
} |
|||
return 0; |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Clojure}}== |
|||
{{libheader|Overtone}} |
|||
<syntaxhighlight lang="clojure">(use 'overtone.live) |
|||
; Define your desired instrument |
|||
; Using saw-wave from: https://github.com/overtone/overtone/wiki/Chords-and-scales |
|||
(definst saw-wave [freq 440 attack 0.01 sustain 0.4 release 0.1 vol 0.4] |
|||
(* (env-gen (env-lin attack sustain release) 1 1 0 1 FREE) |
|||
(saw freq) |
|||
vol)) |
|||
(defn play [note ms] |
|||
(saw-wave (midi->hz note)) |
|||
(Thread/sleep ms)) |
|||
(doseq [note (scale :c4 :major)] (play note 500))</syntaxhighlight> |
|||
=={{header|Commodore BASIC}}== |
|||
The Commodore 128 has available the PLAY command to make quick work of this task. The Commodore 64 lacks this command, so work must be done to initialize the SID chip and play the appropriate frequencies. The DATA statements in the Commodore 64 version are provided in hertz to show direct correlation to the appropriate musical notes (C4 through C5), and are converted to a 16-bit integer in lines 60-65 for output. |
|||
'''Commodore 64''' |
|||
<syntaxhighlight lang="commodorebasic">10 rem musical scale |
|||
15 rem rosetta code |
|||
20 print chr$(147) |
|||
25 s=54272 |
|||
30 for l=s to s+23:poke l,0:next |
|||
35 poke s+5,9:poke s+6,0 |
|||
40 poke s+24,15 |
|||
45 for i=1 to 8 |
|||
50 read fq |
|||
60 ff=int(fq/.06097) |
|||
65 fh=int(ff/256):fl=ff-(256*fh) |
|||
70 poke s+1,fh:poke s,fl |
|||
75 poke s+4,17 |
|||
80 for d=1 to 350:next |
|||
85 poke s+4,16 |
|||
90 for d=1 to 25:next |
|||
95 next i |
|||
500 data 261.63,293.66,329.63,349.23,392,440,493.88,523.25</syntaxhighlight> |
|||
'''Commodore 128''' |
|||
<syntaxhighlight lang="commodorebasic">10 print chr$(147) |
|||
20 play "o4 cdefgab o5 c"</syntaxhighlight> |
|||
=={{header|Delphi}}== |
|||
{{libheader| Winapi.Windows}} |
|||
<syntaxhighlight lang="delphi"> |
|||
program Musical_scale; |
|||
{$APPTYPE CONSOLE} |
|||
uses |
|||
Winapi.Windows; |
|||
var |
|||
notes: TArray<Double> = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, |
|||
493.88, 523.25]; |
|||
begin |
|||
for var note in notes do |
|||
Beep(Round(note), 500); |
|||
readln; |
|||
end.</syntaxhighlight> |
|||
=={{header|EasyLang}}== |
|||
<syntaxhighlight lang="text"> |
|||
n[] = [ 262 294 330 349 392 440 494 523 ] |
|||
for t in n[] |
|||
sound [ t 0.5 ] |
|||
sleep 0.6 |
|||
. |
|||
</syntaxhighlight> |
|||
=={{header|Emacs Lisp}}== |
|||
(Slightly reworked code from [[Sine wave#Emacs Lisp]]) |
|||
Does not work with the Windows version of Emacs. |
|||
<syntaxhighlight lang="lisp">(defun play-scale (freq-list dur) |
|||
"Play a list of frequencies." |
|||
(setq header (unibyte-string ; AU header: |
|||
46 115 110 100 ; ".snd" magic number |
|||
0 0 0 24 ; start of data bytes |
|||
255 255 255 255 ; file size is unknown |
|||
0 0 0 3 ; 16 bit PCM samples |
|||
0 0 172 68 ; 44,100 samples/s |
|||
0 0 0 1)) ; mono |
|||
(setq s nil) |
|||
(dolist (freq freq-list) |
|||
(setq v (mapcar (lambda (x) |
|||
(mod (round (* 32000 (sin (* 2 pi freq x (/ 44100.0))))) 65536)) |
|||
(number-sequence 0 (* dur 44100)))) |
|||
(setq s (apply #'concat s (flatten-list (mapcar (lambda (x) |
|||
(list (unibyte-string (ash x -8)) |
|||
(unibyte-string (mod x 256)))) |
|||
v))))) |
|||
(setq s (concat header s)) |
|||
(play-sound `(sound :data ,s))) |
|||
(play-scale '(261.63 293.66 329.63 349.23 392.00 440.00 493.88 523.25) .5)</syntaxhighlight> |
|||
=={{header|Forth}}== |
|||
As a low level stack language Forth programming methodology prefers short simple definitions that extend the language in the direction that allows you to solve the problem. The creation of application specific language is common in Forth. |
|||
This demonstration code uses the PC speaker to generate musical tones. A simple device driver is created for hardware control via PORT I/O. A set of primitive operations are created to control the on:off times of the sounds. Then a small MUSIC language is created to create notes of different types. Finally 2 scales are created using "crotcheted notes" as they are called. We chose 1/8 notes. For fun we added the ability to change the expression of the notes using Italian musical terms. |
|||
<syntaxhighlight lang="text">HEX |
|||
\ PC speaker hardware control (requires giveio or DOSBOX for windows operation) |
|||
042 constant fctrl 061 constant sctrl |
|||
0FC constant smask 043 constant tctrl |
|||
0B6 constant spkr |
|||
: sing ( -- ) sctrl pc@ 03 or sctrl pc! ; |
|||
: silence ( -- ) sctrl pc@ smask and 01 or sctrl pc! ; |
|||
: tone ( divisor -- ) |
|||
?dup \ check for non-zero input |
|||
if spkr tctrl pc! \ enable PC speaker |
|||
dup fctrl pc! \ load low byte |
|||
8 rshift fctrl pc! \ load high byte |
|||
sing |
|||
else silence |
|||
then ; |
|||
DECIMAL |
|||
1193181. 2constant clock \ internal oscillator freq. MHz x 10 |
|||
: Hz ( freq -- divisor) clock rot um/mod nip ; \ convert Freq to osc. divisor |
|||
\ duration control variables and values |
|||
variable on_time |
|||
variable off_time |
|||
variable feel \ controls the on/off time ratio |
|||
60 value tempo |
|||
4000 tempo um* 2constant timebase \ 1 whole note=4000 ms @ 60 Beats/min |
|||
: bpm>ms ( bpm -- ms) timebase rot um/mod nip ; \ convert beats per minute to milliseconds |
|||
: wholenote ( -- ms ) tempo bpm>ms ; \ using tempo set the BPM |
|||
: play ( divisor -- ) |
|||
tone on_time @ ms silence off_time @ ms ; |
|||
: expression ( ms n --) \ adjust the on:off ratio using n |
|||
over swap - tuck - ( -- on-mS off-mS ) |
|||
off_time ! on_time ! ; \ store times in variables |
|||
: note ( -- ms ) on_time @ off_time @ + ; \ returns duration of current note |
|||
: duration! ( ms -- ) feel @ expression ; |
|||
: 50% ( n -- n/2) 2/ ; |
|||
: % ( n n2 -- n%) 100 */ ; \ calculate n2% of n |
|||
: 50%+ ( n -- n+50%) dup 50% + ; \ dotted notes have 50% more time |
|||
VOCABULARY MUSIC |
|||
MUSIC DEFINITIONS |
|||
: BPM ( bpm -- ) \ set tempo in beats per minute |
|||
to tempo |
|||
wholenote duration! ; |
|||
: legato 0 feel ! ; |
|||
: staccatto note 8 % feel ! ; |
|||
: Marcato note 3 % feel ! ; |
|||
: 1/1 wholenote duration! ; |
|||
: 1/2 wholenote 50% duration! ; |
|||
: 1/2. 1/2 note 50%+ duration! ; |
|||
: 1/4 1/2 note 50% duration! ; |
|||
: 1/4. 1/4 note 50%+ duration! ; |
|||
: 1/8 1/4 note 50% duration! ; |
|||
: 1/8. 1/8 note 50%+ duration! ; |
|||
: 1/16 1/8 note 50% duration! ; |
|||
: 1/32 1/16 note 50% duration! ; |
|||
: rest note ms ; |
|||
\ note object creator |
|||
: note: create hz , \ compile time: compile divisor into the note |
|||
does> @ play ; \ run time: fetch the value and play the tone |
|||
\ freq Natural Freq Accidental En-harmonic |
|||
\ ------------- ---------------- ---------------- |
|||
131 note: C3 139 note: C#3 synonym Db3 C#3 |
|||
147 note: D3 156 note: D#3 synonym Eb3 D#3 |
|||
165 note: E3 |
|||
175 note: F3 185 note: F#3 synonym Gb3 F#3 |
|||
196 note: G3 208 note: G#3 synonym Ab3 G#3 |
|||
220 note: A3 233 note: A#3 synonym Bb3 A#3 |
|||
247 note: B3 |
|||
262 note: C4 277 note: C#4 synonym Db4 C#4 |
|||
: Cmajor 1/8 C3 D3 E3 F3 G3 A3 B3 C4 ; |
|||
: Chromatic 1/8 C3 C#3 D3 D#3 E3 F3 F#3 G3 G#3 A3 A#3 B3 C4 ; |
|||
</syntaxhighlight> |
|||
Interactive test at the Console |
|||
<pre>music ok |
|||
120 bpm legato cmajor ok |
|||
200 bpm marcato chromatic ok |
|||
72 bpm legato c3 eb3 g3 c4 ok |
|||
</pre> |
|||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="freebasic">REM FreeBASIC no tiene la capacidad de emitir sonido de forma nativa. |
|||
REM La función Sound no es mía, incluyo los créditos correspondientes. |
|||
' Sound Function v0.3 For DOS/Linux/Win by yetifoot |
|||
' Credits: |
|||
' http://www.frontiernet.net/~fys/snd.htm |
|||
' http://delphi.about.com/cs/adptips2003/a/bltip0303_3.htm |
|||
#ifdef __FB_WIN32__ |
|||
#include Once "windows.bi" |
|||
#endif |
|||
Sub Sound_DOS_LIN(Byval freq As Uinteger, dur As Uinteger) |
|||
Dim t As Double |
|||
Dim As Ushort fixed_freq = 1193181 \ freq |
|||
Asm |
|||
mov dx, &H61 ' turn speaker on |
|||
in al, dx |
|||
or al, &H03 |
|||
out dx, al |
|||
mov dx, &H43 ' get the timer ready |
|||
mov al, &HB6 |
|||
out dx, al |
|||
mov ax, word Ptr [fixed_freq] ' move freq to ax |
|||
mov dx, &H42 ' port to out |
|||
out dx, al ' out low order |
|||
xchg ah, al |
|||
out dx, al ' out high order |
|||
End Asm |
|||
t = Timer |
|||
While ((Timer - t) * 1000) < dur ' wait for out specified duration |
|||
Sleep(1) |
|||
Wend |
|||
Asm |
|||
mov dx, &H61 ' turn speaker off |
|||
in al, dx |
|||
and al, &HFC |
|||
out dx, al |
|||
End Asm |
|||
End Sub |
|||
Sub Sound(Byval freq As Uinteger, dur As Uinteger) |
|||
#ifndef __fb_win32__ |
|||
' If not windows Then call the asm version. |
|||
Sound_DOS_LIN(freq, dur) |
|||
#Else |
|||
' If Windows |
|||
Dim osv As OSVERSIONINFO |
|||
osv.dwOSVersionInfoSize = Sizeof(OSVERSIONINFO) |
|||
GetVersionEx(@osv) |
|||
Select Case osv.dwPlatformId |
|||
Case VER_PLATFORM_WIN32_NT |
|||
' If NT then use Beep from API |
|||
Beep_(freq, dur) |
|||
Case Else |
|||
' If not on NT then use the same as DOS/Linux |
|||
Sound_DOS_LIN(freq, dur) |
|||
End Select |
|||
#endif |
|||
End Sub |
|||
'---------- |
|||
Sound(262, 250) 'C4 |
|||
Sound(294, 250) 'D4 |
|||
Sound(330, 250) 'E4 |
|||
Sound(349, 250) 'F4 |
|||
Sound(392, 250) 'G4 |
|||
Sound(440, 250) 'A4 |
|||
Sound(494, 250) 'B4 |
|||
Sound(523, 250) 'C5 |
|||
Sleep</syntaxhighlight> |
|||
=={{header|FreePascal}}== |
|||
<syntaxhighlight lang="pascal">{$mode objfpc} |
|||
uses windows,math;{ windows only } |
|||
var |
|||
Interval:Double = 1.0594630943592953; |
|||
i:integer; |
|||
begin |
|||
for i:= 0 to 11 do |
|||
beep(Round(440.0*interval**i),500); |
|||
end.</syntaxhighlight> |
|||
=={{header|FutureBasic}}== |
|||
This code generates a fully playable 3-ocatave piano keyboard with Middle C on the eighth white key. |
|||
<syntaxhighlight lang="futurebasic"> |
|||
output file "FB Piano Keyboard" |
|||
include "Tlbx AudioToolbox.incl" |
|||
_window = 1 |
|||
begin enum output 1 |
|||
_whiteKey01 |
|||
_whiteKey02 |
|||
_whiteKey03 |
|||
_whiteKey04 |
|||
_whiteKey05 |
|||
_whiteKey06 |
|||
_whiteKey07 |
|||
_whiteKey08 |
|||
_whiteKey09 |
|||
_whiteKey10 |
|||
_whiteKey11 |
|||
_whiteKey12 |
|||
_whiteKey13 |
|||
_whiteKey14 |
|||
_whiteKey15 |
|||
_whiteKey16 |
|||
_whiteKey17 |
|||
_whiteKey18 |
|||
_whiteKey19 |
|||
_whiteKey20 |
|||
_whiteKey21 |
|||
_whiteKey22 |
|||
_blackKey23 |
|||
_blackKey24 |
|||
_blackKey25 |
|||
_blackKey26 |
|||
_blackKey27 |
|||
_blackKey28 |
|||
_blackKey29 |
|||
_blackKey30 |
|||
_blackKey31 |
|||
_blackKey32 |
|||
_blackKey33 |
|||
_blackKey34 |
|||
_blackKey35 |
|||
_blackKey36 |
|||
_blackKey37 |
|||
_infoField |
|||
_playBtn |
|||
_note01 |
|||
_note02 |
|||
_note03 |
|||
_note04 |
|||
_note05 |
|||
_note06 |
|||
_note07 |
|||
_note08 |
|||
_note09 |
|||
_note10 |
|||
_note11 |
|||
_note12 |
|||
_note13 |
|||
_note14 |
|||
_note15 |
|||
_note16 |
|||
_note17 |
|||
_note18 |
|||
_note19 |
|||
_note20 |
|||
_note21 |
|||
_note22 |
|||
end enum |
|||
begin enum output |
|||
_kMidiMessageControlChange = 0xB |
|||
_kMidiMessageProgramChange = 0xC |
|||
_kMidiMessageBankMSBControl = 0 |
|||
_kMidiMessageBankLSBControl = 32 |
|||
_kMidiMessageNoteOn = 0x9 |
|||
end enum |
|||
BeginCDeclaration |
|||
AudioUnit synthUnit; |
|||
AUGraph graph; |
|||
EndC |
|||
void local fn PlayNote( noteNum as UInt32 ) |
|||
BeginCCode |
|||
UInt8 midiChannelInUse = 0; |
|||
MusicDeviceMIDIEvent( synthUnit, kMidiMessageControlChange << 4 | midiChannelInUse, kMidiMessageBankMSBControl, 0, 0 ); //2022-Jan-04 Brian |
|||
MusicDeviceMIDIEvent( synthUnit, kMidiMessageProgramChange << 4 | midiChannelInUse, 0, 0, 0 ); |
|||
AUGraphStart( graph ); |
|||
UInt32 onVelocity = 127; |
|||
UInt32 noteOnCommand = kMidiMessageNoteOn << 4 | midiChannelInUse; //2022-Jan-04 Brian |
|||
MusicDeviceMIDIEvent( synthUnit, noteOnCommand, noteNum, onVelocity, 0 ); |
|||
usleep ( 1 * 500 * 600 ); // 0.6 second sleep |
|||
MusicDeviceMIDIEvent( synthUnit, noteOnCommand, noteNum, 0, 0); |
|||
EndC |
|||
end fn |
|||
void local fn InitializeSynth |
|||
BeginCCode |
|||
AUNode synthNode, limiterNode, outNode; |
|||
AudioComponentDescription cd; |
|||
graph = 0; |
|||
synthUnit = 0; |
|||
cd.componentManufacturer = kAudioUnitManufacturer_Apple; |
|||
cd.componentFlags = 0; |
|||
cd.componentFlagsMask = 0; |
|||
NewAUGraph (&graph); |
|||
cd.componentType = kAudioUnitType_MusicDevice; |
|||
cd.componentSubType = kAudioUnitSubType_DLSSynth; |
|||
AUGraphAddNode (graph, &cd, &synthNode); |
|||
cd.componentType = kAudioUnitType_Effect; |
|||
cd.componentSubType = kAudioUnitSubType_PeakLimiter; |
|||
AUGraphAddNode (graph, &cd, &limiterNode); |
|||
cd.componentType = kAudioUnitType_Output; |
|||
cd.componentSubType = kAudioUnitSubType_DefaultOutput; |
|||
AUGraphAddNode (graph, &cd, &outNode); |
|||
AUGraphOpen (graph); |
|||
AUGraphConnectNodeInput (graph, synthNode, 0, limiterNode, 0); |
|||
AUGraphConnectNodeInput (graph, limiterNode, 0, outNode, 0); |
|||
AUGraphNodeInfo ( graph, synthNode, 0, &synthUnit ); |
|||
AUGraphInitialize (graph); |
|||
EndC |
|||
end fn |
|||
local fn CreateKeyImage |
|||
CGRect r = {0,0,28,162} |
|||
ImageRef image = fn ImageWithSize( fn CGSizeMake( 28.0, 162.0 ) ) |
|||
ImageLockFocus( image ) |
|||
BezierPathFillRect( r, fn ColorBlack ) |
|||
ImageUnlockFocus( image ) |
|||
ImageSetName( image, @"KeyImage" ) |
|||
end fn |
|||
void local fn BuildWindow |
|||
NSInteger i, count |
|||
NSInteger wndStyleMask = NSWindowStyleMaskTitled |
|||
wndStyleMask += NSWindowStyleMaskClosable |
|||
wndStyleMask += NSWindowStyleMaskMiniaturizable |
|||
CGRect r = {0,0,850,340} |
|||
window _window, @"FB Piano Keyboard", r, wndStyleMask |
|||
WindowSetBackgroundColor( _window, fn ColorWithRGB( 0.400, 0.400, 0.400, 1.0 ) ) |
|||
// White keys |
|||
r = fn CGRectMake( 30, 30, 38, 250 ) |
|||
for i = _whiteKey01 to _whiteKey22 |
|||
button i,,,@"", r, NSButtonTypeMomentaryLight, NSBezelStyleTexturedSquare, _window |
|||
CALayerRef layer = fn CALayerInit |
|||
CALayerSetBackgroundColor( layer, fn ColorWithRGB( 0.800, 0.800, 0.800, 1.0 ) ) |
|||
ViewSetWantsLayer( i, YES ) |
|||
ViewSetLayer( i, layer ) |
|||
r = fn CGRectOffset( r, 36, 0 ) |
|||
next |
|||
// Black keys |
|||
r = fn CGRectMake( 52, 110, 28, 169 ) |
|||
for i = _blackKey23 to _blackKey37 |
|||
button i,,,@"", r, NSButtonTypeMomentaryLight, NSBezelStyleShadowlessSquare, _window |
|||
ButtonSetImageNamed( i, @"KeyImage" ) |
|||
if ( i == 24 ) or ( i == 27 ) or ( i == 29 ) or ( i == 32 ) or ( i == 34 ) |
|||
r = fn CGRectOffset( r, 72, 0 ) |
|||
else |
|||
r = fn CGRectOffset( r, 36, 0 ) |
|||
end if |
|||
next |
|||
r = fn CGRectMake( 30, 290, 240, 24 ) |
|||
textfield _infoField,,,r, _window |
|||
TextFieldSetEditable( _infoField, NO ) |
|||
TextFieldSetSelectable( _infoField, NO ) |
|||
TextFieldSetDrawsBackground( _infoField, NO ) |
|||
TextFieldSetBordered( _infoField, NO ) |
|||
CFStringRef s = @"C,D,E,F,G,A,B,C,D,E,F,G,A,B,C,D,E,F,G,A,B,C" |
|||
CFArrayRef a = fn StringComponentsSeparatedByString( s, @"," ) |
|||
r = fn CGRectMake( 30, 10, 38, 19 ) |
|||
count = 0 |
|||
for i = _note01 to _note22 |
|||
textfield i,, fn ArrayObjectAtIndex( a, count ), r, _window |
|||
TextFieldSetDrawsBackground( i, NO ) |
|||
TextFieldSetBordered( i, NO ) |
|||
TextFieldSetEditable( i, NO ) |
|||
TextFieldSetSelectable( i, NO ) |
|||
TextSetAlignment( i, NSTextAlignmentCenter ) |
|||
TextSetFontWithName( i, @"Menlo", 14.0 ) |
|||
r = fn CGRectOffset( r, 36, 0 ) |
|||
count++ |
|||
next |
|||
end fn |
|||
local fn DoDialog( ev as NSUInteger, tag as NSUInteger, wnd as NSUInteger ) |
|||
select (ev) |
|||
case _btnClick |
|||
select (tag) |
|||
case 1 : fn PlayNote( 53 ) : ControlSetStringValue( _infoField, @"C, Note 53, White key No. 1" ) |
|||
case 2 : fn PlayNote( 55 ) : ControlSetStringValue( _infoField, @"D, Note 55, White key No. 2" ) |
|||
case 3 : fn PlayNote( 57 ) : ControlSetStringValue( _infoField, @"E, Note 57, White key No. 3" ) |
|||
case 4 : fn PlayNote( 58 ) : ControlSetStringValue( _infoField, @"F, Note 58, White key No. 4" ) |
|||
case 5 : fn PlayNote( 60 ) : ControlSetStringValue( _infoField, @"G, Note 60, White key No. 5" ) |
|||
case 6 : fn PlayNote( 62 ) : ControlSetStringValue( _infoField, @"A, Note 62, White key No. 6" ) |
|||
case 7 : fn PlayNote( 64 ) : ControlSetStringValue( _infoField, @"B, Note 64, White key No. 7" ) |
|||
case 8 : fn PlayNote( 65 ) : ControlSetStringValue( _infoField, @"C, Note 65, White key No. 8" ) |
|||
case 9 : fn PlayNote( 67 ) : ControlSetStringValue( _infoField, @"D, Note 67, White key No. 9" ) |
|||
case 10 : fn PlayNote( 69 ) : ControlSetStringValue( _infoField, @"E, Note 69, White key No. 10" ) |
|||
case 11 : fn PlayNote( 70 ) : ControlSetStringValue( _infoField, @"F, Note 70, White key No. 11" ) |
|||
case 12 : fn PlayNote( 72 ) : ControlSetStringValue( _infoField, @"G, Note 72, White key No. 12" ) |
|||
case 13 : fn PlayNote( 74 ) : ControlSetStringValue( _infoField, @"A, Note 74, White key No. 13" ) |
|||
case 14 : fn PlayNote( 76 ) : ControlSetStringValue( _infoField, @"B, Note 76, White key No. 14" ) |
|||
case 15 : fn PlayNote( 77 ) : ControlSetStringValue( _infoField, @"C, Note 77, White key No. 15" ) |
|||
case 16 : fn PlayNote( 79 ) : ControlSetStringValue( _infoField, @"D, Note 79, White key No. 16" ) |
|||
case 17 : fn PlayNote( 81 ) : ControlSetStringValue( _infoField, @"E, Note 81, White key No. 17" ) |
|||
case 18 : fn PlayNote( 82 ) : ControlSetStringValue( _infoField, @"F, Note 82, White key No. 18" ) |
|||
case 19 : fn PlayNote( 84 ) : ControlSetStringValue( _infoField, @"G, Note 84, White key No. 19" ) |
|||
case 20 : fn PlayNote( 86 ) : ControlSetStringValue( _infoField, @"A, Note 86, White key No. 20" ) |
|||
case 21 : fn PlayNote( 88 ) : ControlSetStringValue( _infoField, @"B, Note 88, White key No. 21" ) |
|||
case 22 : fn PlayNote( 89 ) : ControlSetStringValue( _infoField, @"C, Note 88, White key No. 22" ) |
|||
case 23 : fn PlayNote( 54 ) : ControlSetStringValue( _infoField, @"C#/D\u266D, Note 54, Black key No. 23" ) |
|||
case 24 : fn PlayNote( 56 ) : ControlSetStringValue( _infoField, @"D#/E\u266D, Note 56, Black key No. 24" ) |
|||
case 25 : fn PlayNote( 59 ) : ControlSetStringValue( _infoField, @"F#/G\u266D, Note 59, Black key No. 25" ) |
|||
case 26 : fn PlayNote( 61 ) : ControlSetStringValue( _infoField, @"G#/A\u266D, Note 61, Black key No. 26" ) |
|||
case 27 : fn PlayNote( 63 ) : ControlSetStringValue( _infoField, @"A#/B\u266D, Note 63, Black key No. 27" ) |
|||
case 28 : fn PlayNote( 66 ) : ControlSetStringValue( _infoField, @"C#/D\u266D, Note 66, Black key No. 28" ) |
|||
case 29 : fn PlayNote( 68 ) : ControlSetStringValue( _infoField, @"D#/E\u266D, Note 68, Black key No. 29" ) |
|||
case 30 : fn PlayNote( 71 ) : ControlSetStringValue( _infoField, @"F#/G\u266D, Note 71, Black key No. 30" ) |
|||
case 31 : fn PlayNote( 73 ) : ControlSetStringValue( _infoField, @"G#/A\u266D, Note 73, Black key No. 31" ) |
|||
case 32 : fn PlayNote( 75 ) : ControlSetStringValue( _infoField, @"A#/B\u266D, Note 75, Black key No. 32" ) |
|||
case 33 : fn PlayNote( 78 ) : ControlSetStringValue( _infoField, @"C#/C\u266D, Note 78, Black key No. 33" ) |
|||
case 34 : fn PlayNote( 80 ) : ControlSetStringValue( _infoField, @"D#/E\u266D, Note 80, Black key No. 34" ) |
|||
case 35 : fn PlayNote( 83 ) : ControlSetStringValue( _infoField, @"F#/G\u266D, Note 83, Black key No. 35" ) |
|||
case 36 : fn PlayNote( 85 ) : ControlSetStringValue( _infoField, @"G#/A\u266D, Note 85, Black key No. 36" ) |
|||
case 37 : fn PlayNote( 87 ) : ControlSetStringValue( _infoField, @"A#/B\u266D, Note 87, Black key No. 37" ) |
|||
end select |
|||
case _windowWillClose : end |
|||
end select |
|||
end fn |
|||
void local fn DoAppEvent( ev as long ) |
|||
select (ev) |
|||
case _appWillFinishLaunching |
|||
fn InitializeSynth |
|||
fn CreateKeyImage |
|||
fn BuildWindow |
|||
end select |
|||
end fn |
|||
on appevent fn DoAppEvent |
|||
on dialog fn DoDialog |
|||
HandleEvents |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
[[File:FB Piano Keyboard.png]] |
|||
=={{header|Go}}== |
|||
{{trans|Sparkling}} |
|||
<br> |
|||
As Go doesn't have any audio support in its standard library, we instead build a .wav file which can then be played using a utility such as SoX. |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"encoding/binary" |
|||
"log" |
|||
"math" |
|||
"os" |
|||
"strings" |
|||
) |
|||
func main() { |
|||
const ( |
|||
sampleRate = 44100 |
|||
duration = 8 |
|||
dataLength = sampleRate * duration |
|||
hdrSize = 44 |
|||
fileLen = dataLength + hdrSize - 8 |
|||
) |
|||
// buffers |
|||
buf1 := make([]byte, 1) |
|||
buf2 := make([]byte, 2) |
|||
buf4 := make([]byte, 4) |
|||
// WAV header |
|||
var sb strings.Builder |
|||
sb.WriteString("RIFF") |
|||
binary.LittleEndian.PutUint32(buf4, fileLen) |
|||
sb.Write(buf4) // file size - 8 |
|||
sb.WriteString("WAVE") |
|||
sb.WriteString("fmt ") |
|||
binary.LittleEndian.PutUint32(buf4, 16) |
|||
sb.Write(buf4) // length of format data (= 16) |
|||
binary.LittleEndian.PutUint16(buf2, 1) |
|||
sb.Write(buf2) // type of format (= 1 (PCM)) |
|||
sb.Write(buf2) // number of channels (= 1) |
|||
binary.LittleEndian.PutUint32(buf4, sampleRate) |
|||
sb.Write(buf4) // sample rate |
|||
sb.Write(buf4) // sample rate * bps(8) * channels(1) / 8 (= sample rate) |
|||
sb.Write(buf2) // bps(8) * channels(1) / 8 (= 1) |
|||
binary.LittleEndian.PutUint16(buf2, 8) |
|||
sb.Write(buf2) // bits per sample (bps) (= 8) |
|||
sb.WriteString("data") |
|||
binary.LittleEndian.PutUint32(buf4, dataLength) |
|||
sb.Write(buf4) // size of data section |
|||
wavhdr := []byte(sb.String()) |
|||
// write WAV header |
|||
f, err := os.Create("notes.wav") |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
defer f.Close() |
|||
f.Write(wavhdr) |
|||
// compute and write actual data |
|||
freqs := [8]float64{261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3} |
|||
for j := 0; j < duration; j++ { |
|||
freq := freqs[j] |
|||
omega := 2 * math.Pi * freq |
|||
for i := 0; i < dataLength/duration; i++ { |
|||
y := 32 * math.Sin(omega*float64(i)/float64(sampleRate)) |
|||
buf1[0] = byte(math.Round(y)) |
|||
f.Write(buf1) |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|J}}== |
=={{header|J}}== |
||
< |
<syntaxhighlight lang="j">require'media/wav' |
||
0.25 wavnote 0 2 4 5 7 9 11 12</ |
0.25 wavnote 0 2 4 5 7 9 11 12</syntaxhighlight> |
||
This assumes a version such as J6 which supports media/wav. |
This assumes a version such as J6 which supports media/wav. |
||
Line 89: | Line 974: | ||
0.25 is the duration of each note (in seconds). |
0.25 is the duration of each note (in seconds). |
||
=={{header|Java}}== |
|||
Java can play sounds without external libraries. |
|||
<syntaxhighlight lang="java"> |
|||
import java.util.List; |
|||
import javax.sound.sampled.AudioFormat; |
|||
import javax.sound.sampled.AudioSystem; |
|||
import javax.sound.sampled.LineUnavailableException; |
|||
import javax.sound.sampled.SourceDataLine; |
|||
public final class MusicalScale { |
|||
=={{header|Lilypond}}== |
|||
The lilypond tool produces musical score sheets and midi files - if asked for - but does not output notes to the sound device directly. |
|||
public static void main(String[] aArgs) { |
|||
<lang lilypond>% Start at middle C |
|||
List<Double> frequencies = List.of( 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25 ); |
|||
final int duration = 500; |
|||
final int volume = 1; |
|||
for ( int i = 0; i < 3; i++ ) { |
|||
for ( double frequency : frequencies ) { |
|||
musicalTone(frequency, duration, volume); |
|||
} |
|||
} |
|||
} |
|||
private static void musicalTone(double aFrequency, int aDuration, int aVolume) { |
|||
byte[] buffer = new byte[1]; |
|||
AudioFormat audioFormat = getAudioFormat(); |
|||
try ( SourceDataLine sourceDataLine = AudioSystem.getSourceDataLine(audioFormat) ) { |
|||
sourceDataLine.open(audioFormat); |
|||
sourceDataLine.start(); |
|||
for ( int i = 0; i < aDuration * 8; i++ ) { |
|||
double angle = i / ( SAMPLE_RATE / aFrequency ) * 2 * Math.PI; |
|||
buffer[0] = (byte) ( Math.sin(angle) * 127 * aVolume ); |
|||
sourceDataLine.write(buffer, BYTE_OFFSET, buffer.length); |
|||
} |
|||
sourceDataLine.drain(); |
|||
sourceDataLine.stop(); |
|||
sourceDataLine.close(); |
|||
} catch (LineUnavailableException exception) { |
|||
exception.printStackTrace(); |
|||
} |
|||
} |
|||
private static AudioFormat getAudioFormat() { |
|||
final int sampleSizeInBits = 8; |
|||
final int numberChannels = 1; |
|||
final boolean signedData = true; |
|||
final boolean isBigEndian = false; |
|||
return new AudioFormat(SAMPLE_RATE, sampleSizeInBits, numberChannels, signedData, isBigEndian); |
|||
} |
|||
private static float SAMPLE_RATE = 8_000.0F; |
|||
private static final int BYTE_OFFSET = 0; |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|JavaScript}}== |
|||
Using the Web Audio API |
|||
<syntaxhighlight lang="javascript"><!doctype html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<title>Sample Page</title> |
|||
<script> |
|||
function musicalScale(freqArr){ |
|||
// create web audio api context |
|||
var AudioContext = window.AudioContext || window.webkitAudioContext; |
|||
var audioCtx = new AudioContext(); |
|||
// create oscillator and gain node |
|||
var oscillator = audioCtx.createOscillator(); |
|||
var gainNode = audioCtx.createGain(); |
|||
// connect oscillator to gain node to speakers |
|||
oscillator.connect(gainNode); |
|||
gainNode.connect(audioCtx.destination); |
|||
// set frequencies to play |
|||
duration = 0.5 // seconds |
|||
freqArr.forEach(function (freq, i){ |
|||
oscillator.frequency.setValueAtTime(freq, audioCtx.currentTime + i * duration); |
|||
}); |
|||
// start playing! |
|||
oscillator.start(); |
|||
// stop playing! |
|||
oscillator.stop(audioCtx.currentTime + freqArr.length * duration); |
|||
} |
|||
</script> |
|||
</head> |
|||
<body> |
|||
<button onclick="musicalScale([261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]);">Play scale</button> |
|||
</body> |
|||
</html></syntaxhighlight> |
|||
=={{header|Julia}}== |
|||
<syntaxhighlight lang="julia">using PortAudio |
|||
function paudio() |
|||
devs = PortAudio.devices() |
|||
devnum = findfirst(x -> x.maxoutchans > 0, devs) |
|||
(devnum == nothing) && error("No output device for audio found") |
|||
return PortAudioStream(devs[devnum].name, 0, 2) |
|||
end |
|||
function play(ostream, pitch, durationseconds) |
|||
sinewave(t) = 0.6sin(t) + 0.2sin(2t) + .05sin(8t) |
|||
timesamples = 0:(1 / 44100):(durationseconds * 0.98) |
|||
v = Float64[sinewave(2π * pitch * t) for t in timesamples] |
|||
write(ostream, v) |
|||
sleep(durationseconds * 0.9) |
|||
end |
|||
# C major scale starting with middle C |
|||
# pitches from //pages.mtu.edu/~suits/notefreqs.html |
|||
const scale = [261.6, 293.7, 329.6, 349.2, 392, 440, 493.9, 523.3] |
|||
const ostream = paudio() |
|||
for pitch in scale |
|||
play(ostream, pitch, 0.5) |
|||
sleep(0.4) |
|||
end |
|||
</syntaxhighlight> |
|||
=={{header|Kotlin}}== |
|||
This uses the same frequencies and duration as the Python entry and works fine on Windows 10. |
|||
When building win32.klib from windows.h, one needs to make sure NOT to filter out utilapiset.h because this is where the Beep function now resides, not in winbase.h as stated in the MSDN documentation. |
|||
<syntaxhighlight lang="scala">// Kotlin Native v0.3 |
|||
import kotlinx.cinterop.* |
|||
import win32.* |
|||
fun main(args: Array<String>) { |
|||
val freqs = intArrayOf(262, 294, 330, 349, 392, 440, 494, 523) // CDEFGABc |
|||
val dur = 500 |
|||
repeat(5) { for (freq in freqs) Beep(freq, dur) } |
|||
}</syntaxhighlight> |
|||
=={{header|LilyPond}}== |
|||
The lilyPond tool produces musical score sheets and midi files - if asked for - but does not output notes to the sound device directly. |
|||
<syntaxhighlight lang="lilypond">% Start at middle C |
|||
\relative c' { |
\relative c' { |
||
c d e f |
c d e f |
||
g a b c |
g a b c |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Lambdatalk}}== |
|||
<syntaxhighlight lang="Scheme"> |
|||
Using the musicalScale() javascript function found in this wiki page, we build a lambdatalk interface to output the 8 notes of the C major diatonic scale, and more. |
|||
{def note |
|||
{lambda {:i} |
|||
{round {* 261.63 {pow 2 {/ :i 12}}}}}} |
|||
{def scale |
|||
{lambda {:notes} |
|||
[{S.map {lambda {:i} {note :i},} :notes}]}} |
|||
{def play |
|||
{lambda {:n} |
|||
{input {@ type="button" |
|||
value="Play :n" |
|||
onclick="musicalScale({scale :n});"}}}} |
|||
1) diatonic up |
|||
{play 0 2 4 5 7 9 11 12} |
|||
2) diatonic down |
|||
{play 12 11 9 7 5 4 2 0} |
|||
3) twelve notes of the octave plus one |
|||
{play {S.serie 0 12}} |
|||
4) one more ... from Fantasia (Disney Studios, 1940) |
|||
{play 0 2 3 5 7 3 7 7 6 2 6 6 7 3 7 7 0 2 3 5 7 3 7 12 10 7 3 7 10 10 10 10} |
|||
-> |
|||
</syntaxhighlight> |
|||
=={{header|Locomotive Basic}}== |
=={{header|Locomotive Basic}}== |
||
< |
<syntaxhighlight lang="locobasic">10 mode 1 |
||
20 print "Note","Freq. (Hz)","Period" |
20 print "Note","Freq. (Hz)","Period" |
||
30 ' program loop: |
30 ' program loop: |
||
Line 112: | Line 1,171: | ||
110 f=440*(2^((n-10)/12)) |
110 f=440*(2^((n-10)/12)) |
||
120 p=round(62500/f) |
120 p=round(62500/f) |
||
130 print mid$("cdefgabc",note,1),f,p |
130 print mid$("cdefgabc",note,1),round(f,2),p |
||
140 sound 1,p,100 |
140 sound 1,p,100 |
||
150 return |
150 return |
||
160 data 1,3,5,6,8,10,12,13,-1</ |
160 data 1,3,5,6,8,10,12,13,-1</syntaxhighlight> |
||
=={{header|Mathematica}}== |
|||
=={{header|Lua}}== |
|||
<lang mathem><lang mathematica>EmitSound@Sound[SoundNote /@ {0, 2, 4, 5, 7, 9, 11, 12}]</lang> |
|||
Lua has no native sound support. |
|||
===Lua Portable=== |
|||
The most portable native solution that could actually ''play'' the scale (''with some external help from a media player'') would be to write a MIDI file.. |
|||
<syntaxhighlight lang="lua">c = string.char |
|||
midi = "MThd" .. c(0,0,0,6,0,0,0,1,0,96) -- header |
|||
midi = midi .. "MTrk" .. c(0,0,0,8*8+4) -- track |
|||
for _,note in ipairs{60,62,64,65,67,69,71,72} do |
|||
midi = midi .. c(0, 0x90, note, 0x40, 0x60, 0x80, note, 0) -- notes |
|||
end |
|||
midi = midi .. c(0, 0xFF, 0x2F, 0) -- end |
|||
file = io.open("scale.mid", "wb") |
|||
file:write(midi) |
|||
file:close() |
|||
-- (optional: hex dump to screen) |
|||
midi:gsub(".", function(c) io.write(string.format("%02X ", string.byte(c))) end)</syntaxhighlight> |
|||
{{out}} |
|||
<pre>4D 54 68 64 00 00 00 06 00 00 00 01 00 60 4D 54 72 6B 00 00 00 44 00 90 3C 40 60 80 3C 00 00 90 3E 40 60 80 3E 00 00 90 40 40 60 80 40 00 00 90 41 40 60 80 41 00 00 90 43 40 60 80 43 00 00 90 45 40 60 80 45 00 00 90 47 40 60 80 47 00 00 90 48 40 60 80 48 00 00 FF 2F 00</pre> |
|||
===Lua ASCII=== |
|||
The task allows for score output, which could also be done natively.. |
|||
<syntaxhighlight lang="lua">staff = { |
|||
lines = { "", "", "", "", "", "", "", "", "", "", "" }, |
|||
nnotes = 0, |
|||
measure = function(self) |
|||
for i, line in ipairs(self.lines) do |
|||
self.lines[i] = line .. (i<#self.lines-1 and "|" or " ") |
|||
end |
|||
end, |
|||
play = function(self, note) |
|||
if self.nnotes%4==0 then self:measure() end |
|||
local n = #self.lines-note |
|||
for i, line in ipairs(self.lines) do |
|||
local linechar = (i%2==0) and " " or "-" |
|||
local fillchar = (i<#self.lines) and linechar or " " |
|||
self.lines[i] = line .. (i==n and linechar.."@"..linechar..fillchar or (i==n-1 or i==n-2) and string.rep(fillchar,2).."|"..fillchar or string.rep(fillchar,4)) |
|||
end |
|||
self.nnotes = self.nnotes + 1 |
|||
end, |
|||
dump = function(self) |
|||
for i, line in ipairs(self.lines) do print(line) end |
|||
end |
|||
} |
|||
for note = 0,7 do |
|||
staff:play(note) |
|||
end |
|||
staff:measure() |
|||
staff:dump()</syntaxhighlight> |
|||
{{out}} |
|||
<pre>|----------------|----------------| |
|||
| | | | |
|||
|----------------|----------|---|-| |
|||
| | | | @ | |
|||
|----------------|--|---|--@------| |
|||
| | | | @ | |
|||
|----------|---|-|-@--------------| |
|||
| | | @ | | |
|||
|--|---|--@------|----------------| |
|||
| @ |
|||
-@-</pre> |
|||
===Lua Windows=== |
|||
Non-portable, O/S-specific, requires <code>alien</code> library.. |
|||
<syntaxhighlight lang="lua">beep = require"alien".kernel32.Beep |
|||
beep:types{ret='long', abi='stdcall', 'long', 'long'} |
|||
for _,step in ipairs{0,2,4,5,7,9,11,12} do |
|||
beep(math.floor(261.63 * 2^(step/12) + 0.5), 1000) |
|||
end</syntaxhighlight> |
|||
=={{header|M2000 Interpreter}}== |
|||
Score make an internal bank (replace a previous one), on a voice, (1 to 16), where 10 is for drum machine. |
|||
Play assign a midi organ to a score and start play, in a "music" thread. We can can use Play 0 to stop all scores, or Play number, 0 to stop as specific score. Beat value 300 is in milliseconds, so play each not in Tune each 300 milliseconds, and the same for Score (scores may use @1 to @6 to play 300/1 to 300/32 for specific note, and can use V1 to V127 for volume control per note). Spaces in strings are pauses, and for scores we can use @1 to @6 to reduce pause value). We can use a thread to send a drum score every some seconds, to play a rhythm. Thread { score 10... : play 10,10 ....} as drums interval 1000 (second value for play 10 maybe 0 or any other 1 to 127 but always assign the drum machine. [https://en.wikipedia.org/wiki/General_MIDI Midi] |
|||
TUNE use kernel [https://msdn.microsoft.com/en-us/library/windows/desktop/ms679277(v=vs.85).aspx Beep] which is synchronous and not leaving M2000 threads to process, until ends. |
|||
<syntaxhighlight lang="text"> |
|||
Module checkit { |
|||
\\ using internal speaker |
|||
TUNE 300, "C3DEFGABC4" |
|||
TUNE 300, "C3C#DD#EFF#GG#AA#BC4" |
|||
Thread { |
|||
score 10, 100, "CAC" |
|||
Play 10, 1 |
|||
} as drums interval 1000 |
|||
\\ Play in background (16 scores - no 10 for drum machine) |
|||
SCORE 1, 300, "C3DEFGABC4" |
|||
PLAY 1, 19 ' use score 1 with organ 19 |
|||
Wait 2400 |
|||
} |
|||
checkit |
|||
</syntaxhighlight> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">EmitSound@Sound[SoundNote /@ {0, 2, 4, 5, 7, 9, 11, 12}]</syntaxhighlight> |
|||
=={{header|Nanoquery}}== |
|||
<syntaxhighlight lang="nanoquery">import tonegen |
|||
note_freqs = {261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25} |
|||
tg = new(tonegen) |
|||
for freq in note_freqs |
|||
tg.beep(freq) |
|||
end</syntaxhighlight> |
|||
=={{header|Nim}}== |
|||
{{trans|Go}} |
|||
<syntaxhighlight lang="nim">import endians, math |
|||
const |
|||
SampleRate = 44100 |
|||
Duration = 8 |
|||
DataLength = SampleRate * Duration |
|||
HdrSize = 44 |
|||
FileLen = DataLength + HdrSize - 8 |
|||
Bps = 8 |
|||
Channels = 1 |
|||
proc writeUint16(f: File; x: uint16) = |
|||
var x = x |
|||
var y: array[2, byte] |
|||
littleEndian16(y.addr, x.addr) |
|||
let n = f.writeBytes(y, 0, 2) |
|||
doAssert n == 2 |
|||
proc writeUint32(f: File; x: uint32) = |
|||
var x = x |
|||
var y: array[4, byte] |
|||
littleEndian32(y.addr, x.addr) |
|||
let n = f.writeBytes(y, 0, 4) |
|||
doAssert n == 4 |
|||
let file = open("notes.wav", fmWrite) |
|||
# Wav header. |
|||
file.write "RIFF" |
|||
file.writeUint32(FileLen) |
|||
file.write "WAVE" |
|||
file.write "fmt " |
|||
file.writeUint32(16) # length of format data. |
|||
file.writeUint16(1) # type of format(PCM). |
|||
file.writeUint16(Channels) |
|||
file.writeUint32(SampleRate) |
|||
file.writeUint32(SampleRate * Bps * Channels div 8) |
|||
file.writeUint16(Bps * Channels div 8) |
|||
file.writeUint16(Bps) |
|||
file.write "data" |
|||
file.writeUint32(DataLength) # size of data section. |
|||
# Compute and write actual data. |
|||
const Freqs = [261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3] |
|||
for freq in Freqs: |
|||
let omega = 2 * Pi * freq |
|||
for i in 0..<(DataLength div Duration): |
|||
let y = (32 * sin(omega * i.toFloat / SampleRate.toFloat)).toInt |
|||
file.write chr(y.byte) # Signed int to byte then to char as it’s easier this way. |
|||
file.close()</syntaxhighlight> |
|||
=={{header|ooRexx}}== |
=={{header|ooRexx}}== |
||
< |
<syntaxhighlight lang="oorexx">/* REXX --------------------------------------------------------------- |
||
* 24.02.2013 Walter Pachl derived from REXX |
* 24.02.2013 Walter Pachl derived from original REXX version |
||
* Changes: sound(f,sec) --> beep(trunc(f),millisec) |
* Changes: sound(f,sec) --> beep(trunc(f),millisec) |
||
* $ -> sc |
* $ -> sc |
||
Line 144: | Line 1,363: | ||
f.ut=f.do |
f.ut=f.do |
||
f.ra=293.66 |
f.ra=293.66 |
||
f.re=f.ra /* re is to be a synonym for ra */ |
|||
f.mi=329.63 |
f.mi=329.63 |
||
f.ma=f.mi |
f.ma=f.mi |
||
Line 152: | Line 1,372: | ||
If f.note\==0 Then |
If f.note\==0 Then |
||
Call beep trunc(f.note),dur /* sound the "note". */ |
Call beep trunc(f.note),dur /* sound the "note". */ |
||
Return</ |
Return</syntaxhighlight> |
||
=={{header|Perl |
=={{header|Perl}}== |
||
<syntaxhighlight lang="perl">use MIDI::Simple; |
|||
<lang perl6>for 0,2,4,5,7,9,11,12 { |
|||
shell "play -n -c1 synth 0.2 sin %{$_ - 9}" |
|||
# setup, 1 quarter note is 0.5 seconds (500,000 microseconds) |
|||
}</lang> |
|||
set_tempo 500_000; |
|||
# C-major scale |
|||
n 60; n 62; n 64; n 65; n 67; n 69; n 71; n 72; |
|||
write_score 'scale.mid';</syntaxhighlight> |
|||
=={{header|Phix}}== |
|||
{{libheader|Phix/pGUI}} |
|||
{{libheader|Phix/online}} |
|||
You can run this online [http://phix.x10.mx/p2js/Musical_scale.htm here]. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- demo\rosetta\Musical_scale.exw |
|||
--</span> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #7060A8;">beep</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">freq</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">261.63</span><span style="color: #0000FF;">,</span><span style="color: #000000;">293.66</span><span style="color: #0000FF;">,</span><span style="color: #000000;">329.63</span><span style="color: #0000FF;">,</span><span style="color: #000000;">349.23</span><span style="color: #0000FF;">,</span><span style="color: #000000;">392</span><span style="color: #0000FF;">,</span><span style="color: #000000;">440</span><span style="color: #0000FF;">,</span><span style="color: #000000;">493.88</span><span style="color: #0000FF;">,</span><span style="color: #000000;">523.25</span><span style="color: #0000FF;">},</span> |
|||
<span style="color: #000000;">durations</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">500</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">freq</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">1000</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">button_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*playbtn*/</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">beep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">freq</span><span style="color: #0000FF;">,</span><span style="color: #000000;">durations</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.5</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">label</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Please don't shoot the piano player, he's doing the best that he can!"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">playbtn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Play"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"button_cb"</span><span style="color: #0000FF;">),</span><span style="color: #008000;">"PADDING=30x0"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">hbox</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #7060A8;">IupFill</span><span style="color: #0000FF;">(),</span><span style="color: #000000;">playbtn</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">IupFill</span><span style="color: #0000FF;">()},</span><span style="color: #008000;">"MARGIN=0x20"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">vbox</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">label</span><span style="color: #0000FF;">,</span><span style="color: #000000;">hbox</span><span style="color: #0000FF;">},</span> <span style="color: #008000;">"MARGIN=10x5, GAP=5"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">vbox</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="Musical Scale"`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|PowerShell}}== |
|||
List of frequencies directly taken from the Python example. |
|||
<syntaxhighlight lang="powershell">$frequencies = 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25 |
|||
foreach($tone in $frequencies){ |
|||
[Console]::beep($tone, 500) |
|||
}</syntaxhighlight> |
|||
=={{header|Processing}}== |
|||
Requires the Processing Sound library. |
|||
<syntaxhighlight lang="java"> |
|||
//Aamrun, 2nd July 2022 |
|||
import processing.sound.*; |
|||
float[] frequencies = {261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25}; |
|||
SinOsc sine; |
|||
size(500,500); |
|||
sine = new SinOsc(this); |
|||
for(int i=0;i<frequencies.length;i++){ |
|||
sine.freq(frequencies[i]); |
|||
sine.play(); |
|||
delay(500); |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Pure Data}}== |
=={{header|Pure Data}}== |
||
Line 221: | Line 1,511: | ||
#X connect 22 0 6 0; |
#X connect 22 0 6 0; |
||
</pre> |
</pre> |
||
=={{header|Python}}== |
|||
(Windows) |
|||
<syntaxhighlight lang="python">>>> import winsound |
|||
>>> for note in [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]: |
|||
winsound.Beep(int(note+.5), 500) |
|||
>>> </syntaxhighlight> |
|||
'''Library:''' SDL2 (pip install PySDL2) |
|||
<syntaxhighlight lang="python"> |
|||
import sys |
|||
import ctypes |
|||
import math |
|||
import time |
|||
import struct |
|||
import sdl2 |
|||
import sdl2.sdlmixer as mixer |
|||
def create_sound(frequency, duration): |
|||
"""Create a buffer with sound at given frequency and duration""" |
|||
num_samples = int(48000 * duration) |
|||
wave = struct.pack( |
|||
f"<{num_samples}i", |
|||
*[ |
|||
int(2**30 * math.sin(2 * math.pi * frequency / 48000 * t)) |
|||
for t in range(num_samples) |
|||
] |
|||
) |
|||
length = num_samples * 4 |
|||
sound_buffer = (ctypes.c_ubyte * length).from_buffer_copy(wave) |
|||
sound = mixer.Mix_QuickLoad_RAW( |
|||
ctypes.cast(sound_buffer, ctypes.POINTER(ctypes.c_ubyte)), length |
|||
) |
|||
return sound |
|||
def main(): |
|||
"""Play sine wave""" |
|||
mixer.Mix_Init(0) |
|||
mixer.Mix_OpenAudioDevice(48000, sdl2.AUDIO_S32, 1, 2048, None, 0) |
|||
note = 261.63 |
|||
semitone = math.pow(2, 1 / 12) |
|||
duration = 0.5 # seconds |
|||
for step in [0, 2, 2, 1, 2, 2, 2, 1]: |
|||
note *= semitone**step |
|||
sound = create_sound(note, duration) |
|||
mixer.Mix_PlayChannel(0, sound, 1) |
|||
time.sleep(duration) |
|||
return 0 |
|||
if __name__ == "__main__": |
|||
sys.exit(main()) |
|||
</syntaxhighlight> |
|||
=={{header|R}}== |
|||
<syntaxhighlight lang="r"> |
|||
install.packages("audio") |
|||
library(audio) |
|||
hz=c(1635,1835,2060,2183,2450,2750,3087,3270) |
|||
for (i in 1:8){ |
|||
play(audioSample(sin(1:1000), hz[i])) |
|||
Sys.sleep(.7) |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
With a quick and dirty WinMM interface. |
With a quick and dirty WinMM interface. |
||
< |
<syntaxhighlight lang="racket"> |
||
#lang racket |
#lang racket |
||
(require ffi/unsafe ffi/unsafe/define) |
(require ffi/unsafe ffi/unsafe/define) |
||
Line 236: | Line 1,598: | ||
(for ([i '(60 62 64 65 67 69 71 72)]) (midi #x90 i 127) (sleep 0.5)) |
(for ([i '(60 62 64 65 67 69 71 72)]) (midi #x90 i 127) (sleep 0.5)) |
||
(sleep 2) |
(sleep 2) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
<syntaxhighlight lang="raku" line>for 0,2,4,5,7,9,11,12 { |
|||
shell "play -n -c1 synth 0.2 sin %{$_ - 9}" |
|||
}</syntaxhighlight> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Line 242: | Line 1,610: | ||
{{works with|Personal REXX}} |
{{works with|Personal REXX}} |
||
{{works with|Regina}} |
{{works with|Regina}} |
||
< |
<syntaxhighlight lang="rexx">/*REXX program sounds eight notes of the C major natural diatonic music scale.*/ |
||
parse arg ! |
parse arg ! /*obtain optional arguments from the CL*/ |
||
/* [↓] invoke boilerplate REXX code. */ |
|||
if !all( arg() ) then exit /*determine which REXX is running, if */ |
|||
/* any form of help requested, exit.*/ |
|||
if \!regina & \!pcrexx then do |
|||
say "***error*** this program can't execute under:" !ver |
|||
exit 13 |
|||
end |
|||
$ = 'do ra me fa so la te do' /*the words for music scale sounding. */ |
|||
if \!regina & \!pcrexx then do |
|||
dur = 1/4 /*define duration as a quarter second. */ |
|||
do j=1 for words($) /*sound each "note" in the string. */ |
|||
call notes word($, j), dur /*invoke a subroutine for the sounds. */ |
|||
end /*j*/ /* [↑] sound each of the words. */ |
|||
exit 0 /*stick a fork in it, we're all done. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
notes: procedure expose !regina !pcrexx; arg note,dur /*obtain the arguments from list. */ |
|||
@.= 0 /*define common names for sounds. */ |
|||
@.la= 220; @.si= 246.94; @.te= @.si; @.ta= @.te; @.ti= @.te |
|||
@.do= 261.6256; @.ut= @.do; @.re= 293.66; @.ra= @.re; @.mi= 329.63 |
|||
@.ma= @.mi; @.fa= 349.23; @.so= 392; @.sol= @.so |
|||
if @.note==0 then return /*if frequency is zero, skip it. */ |
|||
if !pcrexx then call sound @.note,dur /*sound the note using SOUND bif. */ |
|||
if !regina then do /* [↓] reformat some numbers. */ |
|||
ms= format(dur*1000, , 0) /*Regina requires DUR in millisec.*/ |
|||
intN= format(@.note, , 0) /* " " NOTE is integer.*/ |
|||
call beep intN, ms /*sound the note using BEEP BIF.*/ |
|||
end |
|||
return |
|||
/*─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/ |
|||
!all: !!=!;!=space(!);upper !;call !fid;!nt=right(!var('OS'),2)=='NT';!cls=word('CLS VMFCLEAR CLRSCREEN',1+!cms+!tso*2);if arg(1)\==1 then return 0;if wordpos(!,'? ?SAMPLES ?AUTHOR ?FLOW')==0 then return 0;!call=']$H';call '$H' !fn !;!call=;return 1 |
|||
!cal: if symbol('!CALL')\=="VAR" then !call=; return !call |
|||
!env: !env= 'ENVIRONMENT'; if !sys=="MSDOS" | !brexx | !r4 | !roo then !env= 'SYSTEM'; if !os2 then !env= "OS2"!env; !ebcdic= 3=='f3'x; if !crx then !env="DOS"; return |
|||
!fid: parse upper source !sys !fun !fid . 1 . . !fn !ft !fm .; call !sys; if !dos then do; _= lastpos('\',!fn); !fm= left(!fn,_); !fn= substr(!fn,_+1); parse var !fn !fn "." !ft; end; return word(0 !fn !ft !fm, 1 + ('0'arg(1) ) ) |
|||
!rex: parse upper version !ver !vernum !verdate .; !brexx= 'BY'==!vernum; !kexx= "KEXX"==!ver; !pcrexx= 'REXX/PERSONAL'==!ver | "REXX/PC"==!ver; !r4= 'REXX-R4'==!ver; !regina= "REXX-REGINA"==left(!ver, 11); !roo= 'REXX-ROO'==!ver; call !env; return |
|||
!sys: !cms= !sys=='CMS'; !os2= !sys=="OS2"; !tso= !sys=='TSO' | !sys=="MVS"; !vse= !sys=='VSE'; !dos= pos("DOS", !sys)\==0 | pos('WIN', !sys)\==0 | !sys=="CMD"; !crx= left(!sys, 6)=='DOSCRX'; call !rex; return |
|||
!var: call !fid; if !kexx then return space( dosenv( arg(1) ) ); return space( value( arg(1), , !env) )</syntaxhighlight> |
|||
Programming note: |
|||
$ = 'do ra me fa so la te do' /*words for music scale sounding.*/ |
|||
The general 1-line subroutines at the end of the REXX program are boilerplate code which: |
|||
dur = 1/4 /*define the duration as ¼ second*/ |
|||
do j=1 for words($) /*sound each "note" in the string*/ |
|||
call notes word($,j),dur /*invoke a subroutine for sounds.*/ |
|||
end /*j*/ /* [↑] sound each of the words.*/ |
|||
exit /*stick a fork in it, we're done.*/ |
|||
/*─────────────────────────────────NOTES subroutine─────────────────────*/ |
|||
notes: procedure expose !regina !pcrexx; arg note,dur; @.=0 |
|||
/*define common names for sounds.*/ |
|||
@.la=220; @.si=246.94; @.te=@.si; @.ta=@.te; @.ti=@.te |
|||
@.do=261.6256; @.ut=@.do; @.re=293.66; @.ra=@.re; @.mi=329.63 |
|||
@.ma=@.mi; @.fa=349.23; @.so=392; @.sol=@.so |
|||
if @.note==0 then return /*if frequency is zero, skip it.*/ |
|||
if !pcrexx then call sound @.note,dur /*sound the note using SOUND bif.*/ |
|||
if !regina then do /* [↓] reformat some numbers. */ |
|||
ms=format(dur*1000,,0) /*Regina requires DUR in millisec*/ |
|||
intN=format(@.note,,0) /* " " NOTE be an int.*/ |
|||
call beep intN,ms /*sound the note using BEEP bif.*/ |
|||
end |
|||
return |
|||
/*═════════════════════════════general 1-line subs════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════*/ |
|||
!all:!!=!;!=space(!);upper !;call !fid;!nt=right(!var('OS'),2)=='NT';!cls=word('CLS VMFCLEAR CLRSCREEN',1+!cms+!tso*2);if arg(1)\==1 then return 0;if wordpos(!,'? ?SAMPLES ?AUTHOR ?FLOW')==0 then return 0;!call=']$H';call '$H' !fn !;!call=;return 1 |
|||
!cal:if symbol('!CALL')\=="VAR" then !call=;return !call |
|||
!env:!env='ENVIRONMENT';if !sys=='MSDOS'|!brexx|!r4|!roo then !env='SYSTEM';if !os2 then !env='OS2'!env;!ebcdic=1=='f0'x;if !crx then !env='DOS';return |
|||
!fid:parse upper source !sys !fun !fid . 1 . . !fn !ft !fm .;call !sys;if !dos then do;_=lastpos('\',!fn);!fm=left(!fn,_);!fn=substr(!fn,_+1);parse var !fn !fn '.' !ft;end;return word(0 !fn !ft !fm,1+('0'arg(1))) |
|||
!rex:parse upper version !ver !vernum !verdate .;!brexx='BY'==!vernum;!kexx='KEXX'==!ver;!pcrexx='REXX/PERSONAL'==!ver|'REXX/PC'==!ver;!r4='REXX-R4'==!ver;!regina='REXX-REGINA'==left(!ver,11);!roo='REXX-ROO'==!ver;call !env;return |
|||
!sys:!cms=!sys=='CMS';!os2=!sys=='OS2';!tso=!sys=='TSO'|!sys=='MVS';!vse=!sys=='VSE';!dos=pos('DOS',!sys)\==0|pos('WIN',!sys)\==0|!sys=='CMD';!crx=left(!sys,6)=='DOSCRX';call !rex;return |
|||
!var:call !fid;if !kexx then return space(dosenv(arg(1)));return space(value(arg(1),,!env))</lang> |
|||
Programming note: The general 1-line subroutines at the end of the REXX program are boilerplate code which: |
|||
::* check for invocation with a '''?''' single argument to support general documentation (help). |
::* check for invocation with a '''?''' single argument to support general documentation (help). |
||
::* check for invocation with a '''?SAMPLES''' single argument to support documentation for sample usages. |
::* check for invocation with a '''?SAMPLES''' single argument to support documentation for sample usages. |
||
Line 296: | Line 1,667: | ||
::::::::* as a function |
::::::::* as a function |
||
::::::::* as a subroutine |
::::::::* as a subroutine |
||
<br> |
|||
=={{header| |
=={{header|Ring}}== |
||
<syntaxhighlight lang="ring"> |
|||
# Project : Musical scale |
|||
loadlib("C:\Ring\extensions\ringbeep\ringbeep.dll") |
|||
The following Sparkling program generates a WAVE audio file named "notes.wav" that can be played in order to achieve the required effect: |
|||
freqs = [[262,"Do"], [294,"Ra"], [330,"Me"], [349,"Fa"], [392,"So"], [440,"La"], [494,"Te"], [523,"do"]] |
|||
<lang Sparkling> |
|||
for f = 1 to len(freqs) |
|||
var sampleRate = 44100.0; |
|||
see freqs[f][2] + nl |
|||
beep(freqs[f][1],300) |
|||
next |
|||
</syntaxhighlight> |
|||
Output video: |
|||
[https://www.dropbox.com/s/jf34s6apalw0k7c/CalmoSoftMusicalScale.avi?dl=0 Musical scale] |
|||
=={{header|RPL}}== |
|||
≪ 2 SWAP 12 / ^ 440 * ≫ '<span style="color:blue>FREQ</span>' STO |
|||
≪ { -9 -7 -5 -4 -2 0 2 3 } |
|||
1 OVER SIZE '''FOR''' j |
|||
DUP j GET <span style="color:blue>FREQ</span> .1 BEEP '''NEXT''' |
|||
DROP |
|||
≫ '<span style="color:blue>GAMME</span>' STO |
|||
=={{header|Scala}}== |
|||
===Windows=== |
|||
{{libheader|net.java.dev.sna.SNA}} |
|||
<syntaxhighlight lang="scala">import net.java.dev.sna.SNA |
|||
object PlayMusicScale extends App with SNA { |
|||
snaLibrary = "Kernel32" |
|||
val Beep = SNA[Int, Int, Unit] |
|||
println("Please don't shoot the piano player, he's doing the best that he can!") |
|||
List(0, 2, 4, 5, 7, 9, 11, 12). |
|||
foreach(f => Beep((261.63 * math.pow(2, f / 12.0)).toInt, if (f == 12) 1000 else 500)) |
|||
println("That's all") |
|||
}</syntaxhighlight> |
|||
=={{header|Sparkling}}== |
|||
The following Sparkling program generates a WAVE audio file named "notes.wav" |
|||
that can be played in order to achieve the required effect: |
|||
<syntaxhighlight lang="sparkling">var sampleRate = 44100.0; |
|||
var duration = 8.0; |
var duration = 8.0; |
||
var dataLength = round(sampleRate * duration); |
var dataLength = round(sampleRate * duration); |
||
Line 351: | Line 1,760: | ||
} |
} |
||
fclose(f);</ |
fclose(f);</syntaxhighlight> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
{{libheader|Snack}} |
{{libheader|Snack}} |
||
< |
<syntaxhighlight lang="tcl">package require sound |
||
# Encapsulate the tone generation |
# Encapsulate the tone generation |
||
set filter [snack::filter generator 1 20000 0.5 sine -1] |
set filter [snack::filter generator 1 20000 0.5 sine -1] |
||
set sound [snack::sound -rate 22050] |
set sound [snack::sound -rate 22050] |
||
proc play {frequency length} { |
proc play {frequency length} { |
||
global filter sound |
global filter sound |
||
Line 377: | Line 1,786: | ||
foreach i {0 2 4 5 7 9 11 12 11 9 7 5 4 2 0} { |
foreach i {0 2 4 5 7 9 11 12 11 9 7 5 4 2 0} { |
||
play [expr {$tonicFrequency*2**($i/12.0)}] [expr {$i%12?250:500}] |
play [expr {$tonicFrequency*2**($i/12.0)}] [expr {$i%12?250:500}] |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Ursa}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="ursa">decl double<> notes |
|||
append 261.63 293.66 329.63 349.23 392.00 440.00 493.88 523.25 notes |
|||
for (decl int i) (< i (size notes)) (inc i) |
|||
ursa.util.sound.beep notes<i> 0.5 |
|||
end for</syntaxhighlight> |
|||
=={{header|VBA}}== |
|||
<syntaxhighlight lang="vb">Option Explicit |
|||
Declare Function Beep Lib "kernel32" (ByVal Freq As Long, ByVal Dur As Long) As Long |
|||
Sub Musical_Scale() |
|||
Dim Fqs, i As Integer |
|||
Fqs = Array(264, 297, 330, 352, 396, 440, 495, 528) |
|||
For i = LBound(Fqs) To UBound(Fqs) |
|||
Beep Fqs(i), 500 |
|||
Next |
|||
End Sub</syntaxhighlight> |
|||
=={{header|V (Vlang)}}== |
|||
{{trans|Go}} |
|||
<br> |
|||
As Vlang doesn't have any audio support in its standard library, we instead build a .wav file which can then be played using a utility such as SoX. |
|||
<syntaxhighlight lang="v (vlang)">import strings |
|||
import os |
|||
import encoding.binary |
|||
import math |
|||
const ( |
|||
sample_rate = 44100 |
|||
duration = 8 |
|||
data_length = sample_rate * duration |
|||
hdr_size = 44 |
|||
file_len = data_length + hdr_size - 8 |
|||
) |
|||
fn main() { |
|||
// buffers |
|||
mut buf1 := []byte{len:1} |
|||
mut buf2 := []byte{len:2} |
|||
mut buf4 := []byte{len:4} |
|||
// WAV header |
|||
mut sb := strings.new_builder(128) |
|||
sb.write_string("RIFF") |
|||
binary.little_endian_put_u32(mut &buf4, file_len) |
|||
sb.write(buf4)? // file size - 8 |
|||
sb.write_string("WAVE") |
|||
sb.write_string("fmt ") |
|||
binary.little_endian_put_u32(mut &buf4, 16) |
|||
sb.write(buf4)? // length of format data (= 16) |
|||
binary.little_endian_put_u16(mut &buf2, 1) |
|||
sb.write(buf2)? // type of format (= 1 (PCM)) |
|||
sb.write(buf2)? // number of channels (= 1) |
|||
binary.little_endian_put_u32(mut &buf4, sample_rate) |
|||
sb.write(buf4)? // sample rate |
|||
sb.write(buf4)? // sample rate * bps(8) * channels(1) / 8 (= sample rate) |
|||
sb.write(buf2)? // bps(8) * channels(1) / 8 (= 1) |
|||
binary.little_endian_put_u16(mut &buf2, 8) |
|||
sb.write(buf2)? // bits per sample (bps) (= 8) |
|||
sb.write_string("data") |
|||
binary.little_endian_put_u32(mut &buf4, data_length) |
|||
sb.write(buf4)? // size of data section |
|||
wavhdr := sb.str().bytes() |
|||
// write WAV header |
|||
mut f := os.create("notes.wav")? |
|||
defer { |
|||
f.close() |
|||
} |
|||
f.write(wavhdr)? |
|||
// compute and write actual data |
|||
freqs := [261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3]! |
|||
for j in 0..duration { |
|||
freq := freqs[j] |
|||
omega := 2 * math.pi * freq |
|||
for i in 0..data_length/duration { |
|||
y := 32 * math.sin(omega*f64(i)/f64(sample_rate)) |
|||
buf1[0] = u8(math.round(y)) |
|||
f.write(buf1)? |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Wren}}== |
|||
{{trans|Sparkling}} |
|||
{{libheader|Wren-sound}} |
|||
As Wren-cli doesn't have any built-in audio support, we instead build a .wav file which can then be played using a utility such as rhythmbox or SoX. |
|||
<syntaxhighlight lang="wren">import "./sound" for Wav |
|||
var sampleRate = 44100 |
|||
var duration = 8 |
|||
var data = List.filled(sampleRate * duration, 0) |
|||
var freqs = [261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3] |
|||
for (j in 0...duration) { |
|||
var freq = freqs[j] |
|||
var omega = 2 * Num.pi * freq |
|||
for (i in 0...sampleRate) { |
|||
var y = (32 * (omega * i / sampleRate).sin).round & 255 |
|||
data[i + j * sampleRate] = y |
|||
} |
|||
} |
|||
Wav.create("musical_scale.wav", data, sampleRate)</syntaxhighlight> |
|||
<br> |
|||
It's also possible to play .wav files which (preferably) have a sample rate of 44.1 kHz using DOME: |
|||
{{libheader|DOME}} |
|||
<syntaxhighlight lang="wren">import "audio" for AudioEngine |
|||
class Main { |
|||
construct new() {} |
|||
init() { |
|||
AudioEngine.load("doremi", "musical_scale.wav") |
|||
AudioEngine.play("doremi") |
|||
} |
|||
update() {} |
|||
draw(alpha) {} |
|||
} |
|||
var Game = Main.new()</syntaxhighlight> |
|||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">\Square waves on the beeper speaker: |
||
code Sound=39; |
code Sound=39; |
||
real Period; int I; |
real Period; int I; |
||
Line 400: | Line 1,936: | ||
Note:= Note + (if I&3 then 2 else 1); |
Note:= Note + (if I&3 then 2 else 1); |
||
]; |
]; |
||
]</ |
]</syntaxhighlight> |
||
=={{header|Yabasic}}== |
|||
{{trans|Phix}} |
|||
<syntaxhighlight lang="yabasic">// Rosetta Code problem: http://rosettacode.org/wiki/Musical_scale |
|||
// by Galileo, 03/2022 |
|||
sample_rate = 44100 |
|||
duration = 8 |
|||
dataLength = sample_rate * duration |
|||
hdrSize = 44 |
|||
fileLen = dataLength + hdrSize - 8 |
|||
data 261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3 |
|||
sub int_to_bytes(dato, long) |
|||
local dato$, esp, esp$, i |
|||
esp$ = "00000000" |
|||
dato$ = hex$(dato) |
|||
esp = long * 2 |
|||
dato$ = right$(esp$ + dato$, esp) |
|||
for i = esp - 1 to 1 step -2 |
|||
poke #fn, dec(mid$(dato$, i, 2)) |
|||
next |
|||
end sub |
|||
fn = open("notesyab.wav", "wb") |
|||
print #fn, "RIFF"; |
|||
int_to_bytes(fileLen, 4) |
|||
print #fn, "WAVEfmt "; |
|||
int_to_bytes(16, 4) // length of format data (= 16) |
|||
int_to_bytes(1, 2) // type of format (= 1 (PCM)) |
|||
int_to_bytes(1, 2) // number of channels (= 1) |
|||
int_to_bytes(sample_rate, 4) // sample rate |
|||
int_to_bytes(sample_rate, 4) // sample rate * bps(8) * channels(1) / 8 (= sample rate) |
|||
int_to_bytes(1,2) // bps(8) * channels(1) / 8 (= 1) |
|||
int_to_bytes(8,2) // bits per sample (bps) (= 8) |
|||
print #fn, "data"; |
|||
int_to_bytes(dataLength, 4) // size of data section |
|||
for j = 1 to duration |
|||
read f |
|||
omega = 2 * PI * f |
|||
for i = 0 to dataLength/duration-1 |
|||
y = 32 * sin(omega * i / sample_rate) |
|||
byte = and(y, 255) |
|||
poke #fn, byte |
|||
next |
|||
next |
|||
close(fn) |
|||
if peek$("os") = "windows" then |
|||
system("notesyab.wav") |
|||
else // Linux |
|||
system("aplay notesyab.wav") |
|||
endif</syntaxhighlight> |
|||
=={{header|ZX Spectrum Basic}}== |
=={{header|ZX Spectrum Basic}}== |
||
< |
<syntaxhighlight lang="zxbasic">10 REM Musical scale |
||
20 LET n=0: REM Start at middle C |
20 LET n=0: REM Start at middle C |
||
30 LET d=0.2: REM Make each note 0.2 seconds in duration |
30 LET d=0.2: REM Make each note 0.2 seconds in duration |
||
Line 412: | Line 2,005: | ||
80 NEXT l |
80 NEXT l |
||
90 STOP |
90 STOP |
||
9000 DATA 2,2,1,2,2,2,1,2:REM WWHWWWH</ |
9000 DATA 2,2,1,2,2,2,1,2:REM WWHWWWH</syntaxhighlight> |
||
{{omit from|BASIC}} |
|||
{{omit from|Blast}} |
|||
{{omit from|Brlcad}} |
|||
{{omit from|Openscad}} |
Latest revision as of 14:05, 8 July 2024
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Output the 8 notes of the C major diatonic scale to the default musical sound device on the system. Specifically, pitch must be tuned to 12-tone equal temperament (12TET) with the modern standard A=440Hz.
These are the notes "C, D, E, F, G, A, B, C(1 octave higher)", or "Do, Re, Mi, Fa, Sol, La, Si/Ti, Do(1 octave higher)" on Fixed do Solfège.
For the purpose of this task, Middle C (in the case of the above tuning, around 261.63 Hz) should be used as the starting note, and any note duration is allowed.
For languages that cannot utilize a sound device, it is permissible to output to a musical score sheet (or midi file), or the task can be omitted.
Action!
DEFINE PTR="CARD"
PROC Wait(BYTE frames)
BYTE RTCLOK=$14
frames==+RTCLOK
WHILE frames#RTCLOK DO OD
RETURN
PROC Main()
BYTE AUDCTL=$D208,AUDF1=$D200,AUDC1=$D201,AUDF2=$D202,AUDC2=$D203
PTR ARRAY notes(8)
BYTE ARRAY pitch8=[60 53 47 45 40 35 31 30]
CARD ARRAY pitch16=[1703 1517 1350 1274 1134 1010 899 848]
BYTE i
CARD p
notes(0)="Do" notes(1)="Re" notes(2)="Mi" notes(3)="Fa"
notes(4)="Sol" notes(5)="La" notes(6)="Si" notes(7)="Do"
PrintE("8-bit precision pitch values:")
FOR i=0 TO 7
DO
PrintF("%S-%B ",notes(i),pitch8(i))
Sound(0,pitch8(i),10,10)
Wait(20)
OD
SndRst()
Wait(20)
PutE() PutE()
AUDCTL=$50 ;join channel 1 and 2 to get 16-bit
AUDC1=$A0 ;turn off channel 1
AUDC2=$AA ;turn on channel 2
PrintE("16-bit precision pitch values:")
FOR i=0 TO 7
DO
PrintF("%S-%U ",notes(i),pitch16(i))
p=pitch16(i)
AUDF2=p RSH 8
AUDF1=p&$FF
Wait(20)
OD
SndRst()
AUDCTL=$00 ;restore default configuration
Wait(20)
RETURN
- Output:
Screenshot from Atari 8-bit computer
8-bit precision pitch values: Do-60 Re-53 Mi-47 Fa-45 Sol-40 La-35 Si-31 Do-30 16-bit precision pitch values: Do-1703 Re-1517 Mi-1350 Fa-1274 Sol-1134 La-1010 Si-899 Do-848
Ada
Ada runs everywhere, so we can't assume a sound device. This program outputs both a MIDI and a WAV audio file.
pragma Ada_2022;
with Ada.Numerics; use Ada.Numerics;
with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;
with Ada.Sequential_IO;
with Interfaces; use Interfaces;
procedure Musical_Scale is
package Byte_IO is new Ada.Sequential_IO (Unsigned_8); use Byte_IO;
SAMPLE_RATE : constant Unsigned_32 := 44100;
DURATION : constant Unsigned_32 := 8;
DATA_LENGTH : constant Unsigned_32 := SAMPLE_RATE * DURATION;
WAV_HDR_LEN : constant Integer := 44;
FILE_SIZE_8 : constant Unsigned_32 := Unsigned_32 (WAV_HDR_LEN) + DATA_LENGTH + 4;
type Byte_Arr is array (Positive range <>) of Unsigned_8;
Wav_Header : constant Byte_Arr (1 .. WAV_HDR_LEN) := [
Character'Pos ('R'), Character'Pos ('I'), Character'Pos ('F'), Character'Pos ('F'),
Unsigned_8 (FILE_SIZE_8 and 16#ff#),
Unsigned_8 (Shift_Right (FILE_SIZE_8, 8) and 16#ff#),
Unsigned_8 (Shift_Right (FILE_SIZE_8, 16) and 16#ff#),
Unsigned_8 (Shift_Right (FILE_SIZE_8, 24) and 16#ff#),
Character'Pos ('W'), Character'Pos ('A'), Character'Pos ('V'), Character'Pos ('E'),
Character'Pos ('f'), Character'Pos ('m'), Character'Pos ('t'), Character'Pos (' '),
16#10#, 0, 0, 0, 1, 0, 1, 0, 16#44#, 16#ac#, 0, 0, 16#44#, 16#ac#, 0, 0, 1, 0, 8, 0,
Character'Pos ('d'), Character'Pos ('a'), Character'Pos ('t'), Character'Pos ('a'),
Unsigned_8 (DATA_LENGTH and 16#ff#),
Unsigned_8 (Shift_Right (DATA_LENGTH, 8) and 16#ff#),
Unsigned_8 (Shift_Right (DATA_LENGTH, 16) and 16#ff#),
Unsigned_8 (Shift_Right (DATA_LENGTH, 24) and 16#ff#)
];
MIDI_Header : constant Byte_Arr (1 .. 22) := [
Character'Pos ('M'), Character'Pos ('T'), Character'Pos ('h'), Character'Pos ('d'),
0, 0, 0, 6, 0, 0, 0, 1, 0, 96, -- File header
Character'Pos ('M'), Character'Pos ('T'), Character'Pos ('r'), Character'Pos ('k'),
0, 0, 0, 8 * 8 + 4 -- Track header
];
MIDI_Trailer : constant Byte_Arr := [0, 16#ff#, 16#2f#, 0];
type Freq_Arr is array (Positive range <>) of Float;
Freqs : constant Freq_Arr := [261.63, 293.67, 329.63, 349.23, 392.0, 440.0, 493.88, 523.25];
Notes : constant Byte_Arr := [60, 62, 64, 65, 67, 69, 71, 72];
Note_On_Off : Byte_Arr := [0, 16#90#, 0, 16#40#, 16#60#, 16#80#, 0, 0];
Wav_File, MIDI_File : File_Type;
Omega : Float;
procedure Write_Arr (File : File_Type; Arr : Byte_Arr) is
begin
for B of Arr loop
Write (File, B);
end loop;
end Write_Arr;
begin
Create (Wav_File, Out_File, "scale.wav");
Write_Arr (Wav_File, Wav_Header);
for Freq of Freqs loop
Omega := 2.0 * Pi * Freq;
for Tick in 0 .. Integer (DATA_LENGTH) / 8 loop
Write (Wav_File, Unsigned_8 (32.0 * (Sin (Omega * Float (Tick) / Float (SAMPLE_RATE)) + 1.0)));
end loop;
end loop;
Close (Wav_File);
Create (MIDI_File, Out_File, "scale.mid");
Write_Arr (MIDI_File, MIDI_Header);
for Note of Notes loop
Note_On_Off (3) := Note;
Note_On_Off (7) := Note;
Write_Arr (MIDI_File, Note_On_Off);
end loop;
Write_Arr (MIDI_File, MIDI_Trailer);
Close (MIDI_File);
end Musical_Scale;
AmigaBASIC
FOR i=1 to 8
READ f
SOUND f,10
NEXT
DATA 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25
AutoHotkey
for key, val in [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]
SoundBeep, % val, 500
BASIC256
sound {261.63, 500, 293.66, 500, 329.63, 500, 349.23, 500, 392, 500, 440, 500, 493.88, 500, 523.25, 500}
Befunge
Befunge has no sound support, so this example generates a MIDI file that plays the sequence of notes. The file is written to stdout, so requires an interpreter that can cleanly redirect its output to a file (for example the bef reference implementation requires the -q option to suppress its version banner).
The tune to be played is specified on the first line of the code. The notes are specified as MIDI note numbers in reverse order in a Befunge string (for example, Middle C is note number 60, which is the character "<"). This is followed by the count of notes in the string - 8 in this example.
> "HGECA@><"8: v
v0*73"MThd"0006010101"MTrk"000<
>>#1-#,:#\_$8*74++,0,28*"'"039v
v,:,\,*2,1"Hd":\<,,,,,,*3"U"*9<
>"@1",2*,\,,1-:#^_"/3d",5*,,, @
C
Although C provides low level access to devices, there is no standardized way. Here are illustrated two approaches.
Borland's Turbo C
Borland's Turbo C system has the dos.h header file which contains the functions sound() and nosound(). sound() takes an argument which is the frequency of the note to be played through the device speaker. delay(), also part of dos.h tells the code how long to suspend execution. The sound will however still be playing. It is therefore essential to call nosound() at the end which ends the speaker output, otherwise the Turbo C (DOS) session will have to be ended.
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<dos.h>
typedef struct{
char str[3];
int key;
}note;
note sequence[] = {{"Do",0},{"Re",2},{"Mi",4},{"Fa",5},{"So",7},{"La",9},{"Ti",11},{"Do",12}};
int main(void)
{
int i=0;
while(!kbhit())
{
printf("\t%s",sequence[i].str);
sound(261.63*pow(2,sequence[i].key/12.0));
delay(sequence[i].key%12==0?500:1000);
i = (i+1)%8;
i==0?printf("\n"):printf("");
}
nosound();
return 0;
}
Windows C
I named it Windows C for want of a better name. This is actually more constrained than the above example, since although it will run on any Windows machine, Beep() can only play integer frequencies and thus the tones are noticeably lower than the ones played by sound() above.
#include<windows.h>
#include<stdio.h>
#include<math.h>
typedef struct{
char str[3];
int key;
}note;
note sequence[] = {{"Do",0},{"Re",2},{"Mi",4},{"Fa",5},{"So",7},{"La",9},{"Ti",11},{"Do",12}};
int main(void)
{
int i=0;
while(1)
{
printf("\t%s",sequence[i].str);
Beep(261.63*pow(2,sequence[i].key/12.0),sequence[i].key%12==0?500:1000);
i = (i+1)%8;
i==0?printf("\n"):printf("");
}
return 0;
}
C++
Uses Windows MIDI device
#include <iostream>
#include <windows.h>
#include <mmsystem.h>
#pragma comment ( lib, "winmm.lib" )
typedef unsigned char byte;
typedef union
{
unsigned long word;
unsigned char data[4];
}
midi_msg;
class midi
{
public:
midi()
{
if( midiOutOpen( &device, 0, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR )
{
std::cout << "Error opening MIDI Output..." << std::endl;
device = 0;
}
}
~midi()
{
midiOutReset( device );
midiOutClose( device );
}
bool isOpen() { return device != 0; }
void setInstrument( byte i )
{
message.data[0] = 0xc0; message.data[1] = i;
message.data[2] = 0; message.data[3] = 0;
midiOutShortMsg( device, message.word );
}
void playNote( byte n, unsigned i )
{
playNote( n ); Sleep( i ); stopNote( n );
}
private:
void playNote( byte n )
{
message.data[0] = 0x90; message.data[1] = n;
message.data[2] = 127; message.data[3] = 0;
midiOutShortMsg( device, message.word );
}
void stopNote( byte n )
{
message.data[0] = 0x90; message.data[1] = n;
message.data[2] = 0; message.data[3] = 0;
midiOutShortMsg( device, message.word );
}
HMIDIOUT device;
midi_msg message;
};
int main( int argc, char* argv[] )
{
midi m;
if( m.isOpen() )
{
byte notes[] = { 60, 62, 64, 65, 67, 69, 71, 72 };
m.setInstrument( 42 );
for( int x = 0; x < 8; x++ )
m.playNote( notes[x], rand() % 100 + 158 );
Sleep( 1000 );
}
return 0;
}
Clojure
(use 'overtone.live)
; Define your desired instrument
; Using saw-wave from: https://github.com/overtone/overtone/wiki/Chords-and-scales
(definst saw-wave [freq 440 attack 0.01 sustain 0.4 release 0.1 vol 0.4]
(* (env-gen (env-lin attack sustain release) 1 1 0 1 FREE)
(saw freq)
vol))
(defn play [note ms]
(saw-wave (midi->hz note))
(Thread/sleep ms))
(doseq [note (scale :c4 :major)] (play note 500))
Commodore BASIC
The Commodore 128 has available the PLAY command to make quick work of this task. The Commodore 64 lacks this command, so work must be done to initialize the SID chip and play the appropriate frequencies. The DATA statements in the Commodore 64 version are provided in hertz to show direct correlation to the appropriate musical notes (C4 through C5), and are converted to a 16-bit integer in lines 60-65 for output.
Commodore 64
10 rem musical scale
15 rem rosetta code
20 print chr$(147)
25 s=54272
30 for l=s to s+23:poke l,0:next
35 poke s+5,9:poke s+6,0
40 poke s+24,15
45 for i=1 to 8
50 read fq
60 ff=int(fq/.06097)
65 fh=int(ff/256):fl=ff-(256*fh)
70 poke s+1,fh:poke s,fl
75 poke s+4,17
80 for d=1 to 350:next
85 poke s+4,16
90 for d=1 to 25:next
95 next i
500 data 261.63,293.66,329.63,349.23,392,440,493.88,523.25
Commodore 128
10 print chr$(147)
20 play "o4 cdefgab o5 c"
Delphi
program Musical_scale;
{$APPTYPE CONSOLE}
uses
Winapi.Windows;
var
notes: TArray<Double> = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00,
493.88, 523.25];
begin
for var note in notes do
Beep(Round(note), 500);
readln;
end.
EasyLang
n[] = [ 262 294 330 349 392 440 494 523 ]
for t in n[]
sound [ t 0.5 ]
sleep 0.6
.
Emacs Lisp
(Slightly reworked code from Sine wave#Emacs Lisp)
Does not work with the Windows version of Emacs.
(defun play-scale (freq-list dur)
"Play a list of frequencies."
(setq header (unibyte-string ; AU header:
46 115 110 100 ; ".snd" magic number
0 0 0 24 ; start of data bytes
255 255 255 255 ; file size is unknown
0 0 0 3 ; 16 bit PCM samples
0 0 172 68 ; 44,100 samples/s
0 0 0 1)) ; mono
(setq s nil)
(dolist (freq freq-list)
(setq v (mapcar (lambda (x)
(mod (round (* 32000 (sin (* 2 pi freq x (/ 44100.0))))) 65536))
(number-sequence 0 (* dur 44100))))
(setq s (apply #'concat s (flatten-list (mapcar (lambda (x)
(list (unibyte-string (ash x -8))
(unibyte-string (mod x 256))))
v)))))
(setq s (concat header s))
(play-sound `(sound :data ,s)))
(play-scale '(261.63 293.66 329.63 349.23 392.00 440.00 493.88 523.25) .5)
Forth
As a low level stack language Forth programming methodology prefers short simple definitions that extend the language in the direction that allows you to solve the problem. The creation of application specific language is common in Forth. This demonstration code uses the PC speaker to generate musical tones. A simple device driver is created for hardware control via PORT I/O. A set of primitive operations are created to control the on:off times of the sounds. Then a small MUSIC language is created to create notes of different types. Finally 2 scales are created using "crotcheted notes" as they are called. We chose 1/8 notes. For fun we added the ability to change the expression of the notes using Italian musical terms.
HEX
\ PC speaker hardware control (requires giveio or DOSBOX for windows operation)
042 constant fctrl 061 constant sctrl
0FC constant smask 043 constant tctrl
0B6 constant spkr
: sing ( -- ) sctrl pc@ 03 or sctrl pc! ;
: silence ( -- ) sctrl pc@ smask and 01 or sctrl pc! ;
: tone ( divisor -- )
?dup \ check for non-zero input
if spkr tctrl pc! \ enable PC speaker
dup fctrl pc! \ load low byte
8 rshift fctrl pc! \ load high byte
sing
else silence
then ;
DECIMAL
1193181. 2constant clock \ internal oscillator freq. MHz x 10
: Hz ( freq -- divisor) clock rot um/mod nip ; \ convert Freq to osc. divisor
\ duration control variables and values
variable on_time
variable off_time
variable feel \ controls the on/off time ratio
60 value tempo
4000 tempo um* 2constant timebase \ 1 whole note=4000 ms @ 60 Beats/min
: bpm>ms ( bpm -- ms) timebase rot um/mod nip ; \ convert beats per minute to milliseconds
: wholenote ( -- ms ) tempo bpm>ms ; \ using tempo set the BPM
: play ( divisor -- )
tone on_time @ ms silence off_time @ ms ;
: expression ( ms n --) \ adjust the on:off ratio using n
over swap - tuck - ( -- on-mS off-mS )
off_time ! on_time ! ; \ store times in variables
: note ( -- ms ) on_time @ off_time @ + ; \ returns duration of current note
: duration! ( ms -- ) feel @ expression ;
: 50% ( n -- n/2) 2/ ;
: % ( n n2 -- n%) 100 */ ; \ calculate n2% of n
: 50%+ ( n -- n+50%) dup 50% + ; \ dotted notes have 50% more time
VOCABULARY MUSIC
MUSIC DEFINITIONS
: BPM ( bpm -- ) \ set tempo in beats per minute
to tempo
wholenote duration! ;
: legato 0 feel ! ;
: staccatto note 8 % feel ! ;
: Marcato note 3 % feel ! ;
: 1/1 wholenote duration! ;
: 1/2 wholenote 50% duration! ;
: 1/2. 1/2 note 50%+ duration! ;
: 1/4 1/2 note 50% duration! ;
: 1/4. 1/4 note 50%+ duration! ;
: 1/8 1/4 note 50% duration! ;
: 1/8. 1/8 note 50%+ duration! ;
: 1/16 1/8 note 50% duration! ;
: 1/32 1/16 note 50% duration! ;
: rest note ms ;
\ note object creator
: note: create hz , \ compile time: compile divisor into the note
does> @ play ; \ run time: fetch the value and play the tone
\ freq Natural Freq Accidental En-harmonic
\ ------------- ---------------- ----------------
131 note: C3 139 note: C#3 synonym Db3 C#3
147 note: D3 156 note: D#3 synonym Eb3 D#3
165 note: E3
175 note: F3 185 note: F#3 synonym Gb3 F#3
196 note: G3 208 note: G#3 synonym Ab3 G#3
220 note: A3 233 note: A#3 synonym Bb3 A#3
247 note: B3
262 note: C4 277 note: C#4 synonym Db4 C#4
: Cmajor 1/8 C3 D3 E3 F3 G3 A3 B3 C4 ;
: Chromatic 1/8 C3 C#3 D3 D#3 E3 F3 F#3 G3 G#3 A3 A#3 B3 C4 ;
Interactive test at the Console
music ok 120 bpm legato cmajor ok 200 bpm marcato chromatic ok 72 bpm legato c3 eb3 g3 c4 ok
FreeBASIC
REM FreeBASIC no tiene la capacidad de emitir sonido de forma nativa.
REM La función Sound no es mía, incluyo los créditos correspondientes.
' Sound Function v0.3 For DOS/Linux/Win by yetifoot
' Credits:
' http://www.frontiernet.net/~fys/snd.htm
' http://delphi.about.com/cs/adptips2003/a/bltip0303_3.htm
#ifdef __FB_WIN32__
#include Once "windows.bi"
#endif
Sub Sound_DOS_LIN(Byval freq As Uinteger, dur As Uinteger)
Dim t As Double
Dim As Ushort fixed_freq = 1193181 \ freq
Asm
mov dx, &H61 ' turn speaker on
in al, dx
or al, &H03
out dx, al
mov dx, &H43 ' get the timer ready
mov al, &HB6
out dx, al
mov ax, word Ptr [fixed_freq] ' move freq to ax
mov dx, &H42 ' port to out
out dx, al ' out low order
xchg ah, al
out dx, al ' out high order
End Asm
t = Timer
While ((Timer - t) * 1000) < dur ' wait for out specified duration
Sleep(1)
Wend
Asm
mov dx, &H61 ' turn speaker off
in al, dx
and al, &HFC
out dx, al
End Asm
End Sub
Sub Sound(Byval freq As Uinteger, dur As Uinteger)
#ifndef __fb_win32__
' If not windows Then call the asm version.
Sound_DOS_LIN(freq, dur)
#Else
' If Windows
Dim osv As OSVERSIONINFO
osv.dwOSVersionInfoSize = Sizeof(OSVERSIONINFO)
GetVersionEx(@osv)
Select Case osv.dwPlatformId
Case VER_PLATFORM_WIN32_NT
' If NT then use Beep from API
Beep_(freq, dur)
Case Else
' If not on NT then use the same as DOS/Linux
Sound_DOS_LIN(freq, dur)
End Select
#endif
End Sub
'----------
Sound(262, 250) 'C4
Sound(294, 250) 'D4
Sound(330, 250) 'E4
Sound(349, 250) 'F4
Sound(392, 250) 'G4
Sound(440, 250) 'A4
Sound(494, 250) 'B4
Sound(523, 250) 'C5
Sleep
FreePascal
{$mode objfpc}
uses windows,math;{ windows only }
var
Interval:Double = 1.0594630943592953;
i:integer;
begin
for i:= 0 to 11 do
beep(Round(440.0*interval**i),500);
end.
FutureBasic
This code generates a fully playable 3-ocatave piano keyboard with Middle C on the eighth white key.
output file "FB Piano Keyboard"
include "Tlbx AudioToolbox.incl"
_window = 1
begin enum output 1
_whiteKey01
_whiteKey02
_whiteKey03
_whiteKey04
_whiteKey05
_whiteKey06
_whiteKey07
_whiteKey08
_whiteKey09
_whiteKey10
_whiteKey11
_whiteKey12
_whiteKey13
_whiteKey14
_whiteKey15
_whiteKey16
_whiteKey17
_whiteKey18
_whiteKey19
_whiteKey20
_whiteKey21
_whiteKey22
_blackKey23
_blackKey24
_blackKey25
_blackKey26
_blackKey27
_blackKey28
_blackKey29
_blackKey30
_blackKey31
_blackKey32
_blackKey33
_blackKey34
_blackKey35
_blackKey36
_blackKey37
_infoField
_playBtn
_note01
_note02
_note03
_note04
_note05
_note06
_note07
_note08
_note09
_note10
_note11
_note12
_note13
_note14
_note15
_note16
_note17
_note18
_note19
_note20
_note21
_note22
end enum
begin enum output
_kMidiMessageControlChange = 0xB
_kMidiMessageProgramChange = 0xC
_kMidiMessageBankMSBControl = 0
_kMidiMessageBankLSBControl = 32
_kMidiMessageNoteOn = 0x9
end enum
BeginCDeclaration
AudioUnit synthUnit;
AUGraph graph;
EndC
void local fn PlayNote( noteNum as UInt32 )
BeginCCode
UInt8 midiChannelInUse = 0;
MusicDeviceMIDIEvent( synthUnit, kMidiMessageControlChange << 4 | midiChannelInUse, kMidiMessageBankMSBControl, 0, 0 ); //2022-Jan-04 Brian
MusicDeviceMIDIEvent( synthUnit, kMidiMessageProgramChange << 4 | midiChannelInUse, 0, 0, 0 );
AUGraphStart( graph );
UInt32 onVelocity = 127;
UInt32 noteOnCommand = kMidiMessageNoteOn << 4 | midiChannelInUse; //2022-Jan-04 Brian
MusicDeviceMIDIEvent( synthUnit, noteOnCommand, noteNum, onVelocity, 0 );
usleep ( 1 * 500 * 600 ); // 0.6 second sleep
MusicDeviceMIDIEvent( synthUnit, noteOnCommand, noteNum, 0, 0);
EndC
end fn
void local fn InitializeSynth
BeginCCode
AUNode synthNode, limiterNode, outNode;
AudioComponentDescription cd;
graph = 0;
synthUnit = 0;
cd.componentManufacturer = kAudioUnitManufacturer_Apple;
cd.componentFlags = 0;
cd.componentFlagsMask = 0;
NewAUGraph (&graph);
cd.componentType = kAudioUnitType_MusicDevice;
cd.componentSubType = kAudioUnitSubType_DLSSynth;
AUGraphAddNode (graph, &cd, &synthNode);
cd.componentType = kAudioUnitType_Effect;
cd.componentSubType = kAudioUnitSubType_PeakLimiter;
AUGraphAddNode (graph, &cd, &limiterNode);
cd.componentType = kAudioUnitType_Output;
cd.componentSubType = kAudioUnitSubType_DefaultOutput;
AUGraphAddNode (graph, &cd, &outNode);
AUGraphOpen (graph);
AUGraphConnectNodeInput (graph, synthNode, 0, limiterNode, 0);
AUGraphConnectNodeInput (graph, limiterNode, 0, outNode, 0);
AUGraphNodeInfo ( graph, synthNode, 0, &synthUnit );
AUGraphInitialize (graph);
EndC
end fn
local fn CreateKeyImage
CGRect r = {0,0,28,162}
ImageRef image = fn ImageWithSize( fn CGSizeMake( 28.0, 162.0 ) )
ImageLockFocus( image )
BezierPathFillRect( r, fn ColorBlack )
ImageUnlockFocus( image )
ImageSetName( image, @"KeyImage" )
end fn
void local fn BuildWindow
NSInteger i, count
NSInteger wndStyleMask = NSWindowStyleMaskTitled
wndStyleMask += NSWindowStyleMaskClosable
wndStyleMask += NSWindowStyleMaskMiniaturizable
CGRect r = {0,0,850,340}
window _window, @"FB Piano Keyboard", r, wndStyleMask
WindowSetBackgroundColor( _window, fn ColorWithRGB( 0.400, 0.400, 0.400, 1.0 ) )
// White keys
r = fn CGRectMake( 30, 30, 38, 250 )
for i = _whiteKey01 to _whiteKey22
button i,,,@"", r, NSButtonTypeMomentaryLight, NSBezelStyleTexturedSquare, _window
CALayerRef layer = fn CALayerInit
CALayerSetBackgroundColor( layer, fn ColorWithRGB( 0.800, 0.800, 0.800, 1.0 ) )
ViewSetWantsLayer( i, YES )
ViewSetLayer( i, layer )
r = fn CGRectOffset( r, 36, 0 )
next
// Black keys
r = fn CGRectMake( 52, 110, 28, 169 )
for i = _blackKey23 to _blackKey37
button i,,,@"", r, NSButtonTypeMomentaryLight, NSBezelStyleShadowlessSquare, _window
ButtonSetImageNamed( i, @"KeyImage" )
if ( i == 24 ) or ( i == 27 ) or ( i == 29 ) or ( i == 32 ) or ( i == 34 )
r = fn CGRectOffset( r, 72, 0 )
else
r = fn CGRectOffset( r, 36, 0 )
end if
next
r = fn CGRectMake( 30, 290, 240, 24 )
textfield _infoField,,,r, _window
TextFieldSetEditable( _infoField, NO )
TextFieldSetSelectable( _infoField, NO )
TextFieldSetDrawsBackground( _infoField, NO )
TextFieldSetBordered( _infoField, NO )
CFStringRef s = @"C,D,E,F,G,A,B,C,D,E,F,G,A,B,C,D,E,F,G,A,B,C"
CFArrayRef a = fn StringComponentsSeparatedByString( s, @"," )
r = fn CGRectMake( 30, 10, 38, 19 )
count = 0
for i = _note01 to _note22
textfield i,, fn ArrayObjectAtIndex( a, count ), r, _window
TextFieldSetDrawsBackground( i, NO )
TextFieldSetBordered( i, NO )
TextFieldSetEditable( i, NO )
TextFieldSetSelectable( i, NO )
TextSetAlignment( i, NSTextAlignmentCenter )
TextSetFontWithName( i, @"Menlo", 14.0 )
r = fn CGRectOffset( r, 36, 0 )
count++
next
end fn
local fn DoDialog( ev as NSUInteger, tag as NSUInteger, wnd as NSUInteger )
select (ev)
case _btnClick
select (tag)
case 1 : fn PlayNote( 53 ) : ControlSetStringValue( _infoField, @"C, Note 53, White key No. 1" )
case 2 : fn PlayNote( 55 ) : ControlSetStringValue( _infoField, @"D, Note 55, White key No. 2" )
case 3 : fn PlayNote( 57 ) : ControlSetStringValue( _infoField, @"E, Note 57, White key No. 3" )
case 4 : fn PlayNote( 58 ) : ControlSetStringValue( _infoField, @"F, Note 58, White key No. 4" )
case 5 : fn PlayNote( 60 ) : ControlSetStringValue( _infoField, @"G, Note 60, White key No. 5" )
case 6 : fn PlayNote( 62 ) : ControlSetStringValue( _infoField, @"A, Note 62, White key No. 6" )
case 7 : fn PlayNote( 64 ) : ControlSetStringValue( _infoField, @"B, Note 64, White key No. 7" )
case 8 : fn PlayNote( 65 ) : ControlSetStringValue( _infoField, @"C, Note 65, White key No. 8" )
case 9 : fn PlayNote( 67 ) : ControlSetStringValue( _infoField, @"D, Note 67, White key No. 9" )
case 10 : fn PlayNote( 69 ) : ControlSetStringValue( _infoField, @"E, Note 69, White key No. 10" )
case 11 : fn PlayNote( 70 ) : ControlSetStringValue( _infoField, @"F, Note 70, White key No. 11" )
case 12 : fn PlayNote( 72 ) : ControlSetStringValue( _infoField, @"G, Note 72, White key No. 12" )
case 13 : fn PlayNote( 74 ) : ControlSetStringValue( _infoField, @"A, Note 74, White key No. 13" )
case 14 : fn PlayNote( 76 ) : ControlSetStringValue( _infoField, @"B, Note 76, White key No. 14" )
case 15 : fn PlayNote( 77 ) : ControlSetStringValue( _infoField, @"C, Note 77, White key No. 15" )
case 16 : fn PlayNote( 79 ) : ControlSetStringValue( _infoField, @"D, Note 79, White key No. 16" )
case 17 : fn PlayNote( 81 ) : ControlSetStringValue( _infoField, @"E, Note 81, White key No. 17" )
case 18 : fn PlayNote( 82 ) : ControlSetStringValue( _infoField, @"F, Note 82, White key No. 18" )
case 19 : fn PlayNote( 84 ) : ControlSetStringValue( _infoField, @"G, Note 84, White key No. 19" )
case 20 : fn PlayNote( 86 ) : ControlSetStringValue( _infoField, @"A, Note 86, White key No. 20" )
case 21 : fn PlayNote( 88 ) : ControlSetStringValue( _infoField, @"B, Note 88, White key No. 21" )
case 22 : fn PlayNote( 89 ) : ControlSetStringValue( _infoField, @"C, Note 88, White key No. 22" )
case 23 : fn PlayNote( 54 ) : ControlSetStringValue( _infoField, @"C#/D\u266D, Note 54, Black key No. 23" )
case 24 : fn PlayNote( 56 ) : ControlSetStringValue( _infoField, @"D#/E\u266D, Note 56, Black key No. 24" )
case 25 : fn PlayNote( 59 ) : ControlSetStringValue( _infoField, @"F#/G\u266D, Note 59, Black key No. 25" )
case 26 : fn PlayNote( 61 ) : ControlSetStringValue( _infoField, @"G#/A\u266D, Note 61, Black key No. 26" )
case 27 : fn PlayNote( 63 ) : ControlSetStringValue( _infoField, @"A#/B\u266D, Note 63, Black key No. 27" )
case 28 : fn PlayNote( 66 ) : ControlSetStringValue( _infoField, @"C#/D\u266D, Note 66, Black key No. 28" )
case 29 : fn PlayNote( 68 ) : ControlSetStringValue( _infoField, @"D#/E\u266D, Note 68, Black key No. 29" )
case 30 : fn PlayNote( 71 ) : ControlSetStringValue( _infoField, @"F#/G\u266D, Note 71, Black key No. 30" )
case 31 : fn PlayNote( 73 ) : ControlSetStringValue( _infoField, @"G#/A\u266D, Note 73, Black key No. 31" )
case 32 : fn PlayNote( 75 ) : ControlSetStringValue( _infoField, @"A#/B\u266D, Note 75, Black key No. 32" )
case 33 : fn PlayNote( 78 ) : ControlSetStringValue( _infoField, @"C#/C\u266D, Note 78, Black key No. 33" )
case 34 : fn PlayNote( 80 ) : ControlSetStringValue( _infoField, @"D#/E\u266D, Note 80, Black key No. 34" )
case 35 : fn PlayNote( 83 ) : ControlSetStringValue( _infoField, @"F#/G\u266D, Note 83, Black key No. 35" )
case 36 : fn PlayNote( 85 ) : ControlSetStringValue( _infoField, @"G#/A\u266D, Note 85, Black key No. 36" )
case 37 : fn PlayNote( 87 ) : ControlSetStringValue( _infoField, @"A#/B\u266D, Note 87, Black key No. 37" )
end select
case _windowWillClose : end
end select
end fn
void local fn DoAppEvent( ev as long )
select (ev)
case _appWillFinishLaunching
fn InitializeSynth
fn CreateKeyImage
fn BuildWindow
end select
end fn
on appevent fn DoAppEvent
on dialog fn DoDialog
HandleEvents
- Output:
Go
As Go doesn't have any audio support in its standard library, we instead build a .wav file which can then be played using a utility such as SoX.
package main
import (
"encoding/binary"
"log"
"math"
"os"
"strings"
)
func main() {
const (
sampleRate = 44100
duration = 8
dataLength = sampleRate * duration
hdrSize = 44
fileLen = dataLength + hdrSize - 8
)
// buffers
buf1 := make([]byte, 1)
buf2 := make([]byte, 2)
buf4 := make([]byte, 4)
// WAV header
var sb strings.Builder
sb.WriteString("RIFF")
binary.LittleEndian.PutUint32(buf4, fileLen)
sb.Write(buf4) // file size - 8
sb.WriteString("WAVE")
sb.WriteString("fmt ")
binary.LittleEndian.PutUint32(buf4, 16)
sb.Write(buf4) // length of format data (= 16)
binary.LittleEndian.PutUint16(buf2, 1)
sb.Write(buf2) // type of format (= 1 (PCM))
sb.Write(buf2) // number of channels (= 1)
binary.LittleEndian.PutUint32(buf4, sampleRate)
sb.Write(buf4) // sample rate
sb.Write(buf4) // sample rate * bps(8) * channels(1) / 8 (= sample rate)
sb.Write(buf2) // bps(8) * channels(1) / 8 (= 1)
binary.LittleEndian.PutUint16(buf2, 8)
sb.Write(buf2) // bits per sample (bps) (= 8)
sb.WriteString("data")
binary.LittleEndian.PutUint32(buf4, dataLength)
sb.Write(buf4) // size of data section
wavhdr := []byte(sb.String())
// write WAV header
f, err := os.Create("notes.wav")
if err != nil {
log.Fatal(err)
}
defer f.Close()
f.Write(wavhdr)
// compute and write actual data
freqs := [8]float64{261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3}
for j := 0; j < duration; j++ {
freq := freqs[j]
omega := 2 * math.Pi * freq
for i := 0; i < dataLength/duration; i++ {
y := 32 * math.Sin(omega*float64(i)/float64(sampleRate))
buf1[0] = byte(math.Round(y))
f.Write(buf1)
}
}
}
J
require'media/wav'
0.25 wavnote 0 2 4 5 7 9 11 12
This assumes a version such as J6 which supports media/wav.
0=C, 1=C#, 2=D, ... of main octave
0.25 is the duration of each note (in seconds).
Java
Java can play sounds without external libraries.
import java.util.List;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public final class MusicalScale {
public static void main(String[] aArgs) {
List<Double> frequencies = List.of( 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25 );
final int duration = 500;
final int volume = 1;
for ( int i = 0; i < 3; i++ ) {
for ( double frequency : frequencies ) {
musicalTone(frequency, duration, volume);
}
}
}
private static void musicalTone(double aFrequency, int aDuration, int aVolume) {
byte[] buffer = new byte[1];
AudioFormat audioFormat = getAudioFormat();
try ( SourceDataLine sourceDataLine = AudioSystem.getSourceDataLine(audioFormat) ) {
sourceDataLine.open(audioFormat);
sourceDataLine.start();
for ( int i = 0; i < aDuration * 8; i++ ) {
double angle = i / ( SAMPLE_RATE / aFrequency ) * 2 * Math.PI;
buffer[0] = (byte) ( Math.sin(angle) * 127 * aVolume );
sourceDataLine.write(buffer, BYTE_OFFSET, buffer.length);
}
sourceDataLine.drain();
sourceDataLine.stop();
sourceDataLine.close();
} catch (LineUnavailableException exception) {
exception.printStackTrace();
}
}
private static AudioFormat getAudioFormat() {
final int sampleSizeInBits = 8;
final int numberChannels = 1;
final boolean signedData = true;
final boolean isBigEndian = false;
return new AudioFormat(SAMPLE_RATE, sampleSizeInBits, numberChannels, signedData, isBigEndian);
}
private static float SAMPLE_RATE = 8_000.0F;
private static final int BYTE_OFFSET = 0;
}
JavaScript
Using the Web Audio API
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Sample Page</title>
<script>
function musicalScale(freqArr){
// create web audio api context
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();
// create oscillator and gain node
var oscillator = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();
// connect oscillator to gain node to speakers
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
// set frequencies to play
duration = 0.5 // seconds
freqArr.forEach(function (freq, i){
oscillator.frequency.setValueAtTime(freq, audioCtx.currentTime + i * duration);
});
// start playing!
oscillator.start();
// stop playing!
oscillator.stop(audioCtx.currentTime + freqArr.length * duration);
}
</script>
</head>
<body>
<button onclick="musicalScale([261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]);">Play scale</button>
</body>
</html>
Julia
using PortAudio
function paudio()
devs = PortAudio.devices()
devnum = findfirst(x -> x.maxoutchans > 0, devs)
(devnum == nothing) && error("No output device for audio found")
return PortAudioStream(devs[devnum].name, 0, 2)
end
function play(ostream, pitch, durationseconds)
sinewave(t) = 0.6sin(t) + 0.2sin(2t) + .05sin(8t)
timesamples = 0:(1 / 44100):(durationseconds * 0.98)
v = Float64[sinewave(2π * pitch * t) for t in timesamples]
write(ostream, v)
sleep(durationseconds * 0.9)
end
# C major scale starting with middle C
# pitches from //pages.mtu.edu/~suits/notefreqs.html
const scale = [261.6, 293.7, 329.6, 349.2, 392, 440, 493.9, 523.3]
const ostream = paudio()
for pitch in scale
play(ostream, pitch, 0.5)
sleep(0.4)
end
Kotlin
This uses the same frequencies and duration as the Python entry and works fine on Windows 10.
When building win32.klib from windows.h, one needs to make sure NOT to filter out utilapiset.h because this is where the Beep function now resides, not in winbase.h as stated in the MSDN documentation.
// Kotlin Native v0.3
import kotlinx.cinterop.*
import win32.*
fun main(args: Array<String>) {
val freqs = intArrayOf(262, 294, 330, 349, 392, 440, 494, 523) // CDEFGABc
val dur = 500
repeat(5) { for (freq in freqs) Beep(freq, dur) }
}
LilyPond
The lilyPond tool produces musical score sheets and midi files - if asked for - but does not output notes to the sound device directly.
% Start at middle C
\relative c' {
c d e f
g a b c
}
Lambdatalk
Using the musicalScale() javascript function found in this wiki page, we build a lambdatalk interface to output the 8 notes of the C major diatonic scale, and more.
{def note
{lambda {:i}
{round {* 261.63 {pow 2 {/ :i 12}}}}}}
{def scale
{lambda {:notes}
[{S.map {lambda {:i} {note :i},} :notes}]}}
{def play
{lambda {:n}
{input {@ type="button"
value="Play :n"
onclick="musicalScale({scale :n});"}}}}
1) diatonic up
{play 0 2 4 5 7 9 11 12}
2) diatonic down
{play 12 11 9 7 5 4 2 0}
3) twelve notes of the octave plus one
{play {S.serie 0 12}}
4) one more ... from Fantasia (Disney Studios, 1940)
{play 0 2 3 5 7 3 7 7 6 2 6 6 7 3 7 7 0 2 3 5 7 3 7 12 10 7 3 7 10 10 10 10}
->
Locomotive Basic
10 mode 1
20 print "Note","Freq. (Hz)","Period"
30 ' program loop:
40 if sq(1)<128 then gosub 70 ' play next note if channel is inactive
50 goto 40
60 ' play next note
70 read n
80 if n<0 then end
90 note=note+1
100 ' calculation from chapter 7, page 26 of the CPC manual:
110 f=440*(2^((n-10)/12))
120 p=round(62500/f)
130 print mid$("cdefgabc",note,1),round(f,2),p
140 sound 1,p,100
150 return
160 data 1,3,5,6,8,10,12,13,-1
Lua
Lua has no native sound support.
Lua Portable
The most portable native solution that could actually play the scale (with some external help from a media player) would be to write a MIDI file..
c = string.char
midi = "MThd" .. c(0,0,0,6,0,0,0,1,0,96) -- header
midi = midi .. "MTrk" .. c(0,0,0,8*8+4) -- track
for _,note in ipairs{60,62,64,65,67,69,71,72} do
midi = midi .. c(0, 0x90, note, 0x40, 0x60, 0x80, note, 0) -- notes
end
midi = midi .. c(0, 0xFF, 0x2F, 0) -- end
file = io.open("scale.mid", "wb")
file:write(midi)
file:close()
-- (optional: hex dump to screen)
midi:gsub(".", function(c) io.write(string.format("%02X ", string.byte(c))) end)
- Output:
4D 54 68 64 00 00 00 06 00 00 00 01 00 60 4D 54 72 6B 00 00 00 44 00 90 3C 40 60 80 3C 00 00 90 3E 40 60 80 3E 00 00 90 40 40 60 80 40 00 00 90 41 40 60 80 41 00 00 90 43 40 60 80 43 00 00 90 45 40 60 80 45 00 00 90 47 40 60 80 47 00 00 90 48 40 60 80 48 00 00 FF 2F 00
Lua ASCII
The task allows for score output, which could also be done natively..
staff = {
lines = { "", "", "", "", "", "", "", "", "", "", "" },
nnotes = 0,
measure = function(self)
for i, line in ipairs(self.lines) do
self.lines[i] = line .. (i<#self.lines-1 and "|" or " ")
end
end,
play = function(self, note)
if self.nnotes%4==0 then self:measure() end
local n = #self.lines-note
for i, line in ipairs(self.lines) do
local linechar = (i%2==0) and " " or "-"
local fillchar = (i<#self.lines) and linechar or " "
self.lines[i] = line .. (i==n and linechar.."@"..linechar..fillchar or (i==n-1 or i==n-2) and string.rep(fillchar,2).."|"..fillchar or string.rep(fillchar,4))
end
self.nnotes = self.nnotes + 1
end,
dump = function(self)
for i, line in ipairs(self.lines) do print(line) end
end
}
for note = 0,7 do
staff:play(note)
end
staff:measure()
staff:dump()
- Output:
|----------------|----------------| | | | | |----------------|----------|---|-| | | | | @ | |----------------|--|---|--@------| | | | | @ | |----------|---|-|-@--------------| | | | @ | | |--|---|--@------|----------------| | @ -@-
Lua Windows
Non-portable, O/S-specific, requires alien
library..
beep = require"alien".kernel32.Beep
beep:types{ret='long', abi='stdcall', 'long', 'long'}
for _,step in ipairs{0,2,4,5,7,9,11,12} do
beep(math.floor(261.63 * 2^(step/12) + 0.5), 1000)
end
M2000 Interpreter
Score make an internal bank (replace a previous one), on a voice, (1 to 16), where 10 is for drum machine. Play assign a midi organ to a score and start play, in a "music" thread. We can can use Play 0 to stop all scores, or Play number, 0 to stop as specific score. Beat value 300 is in milliseconds, so play each not in Tune each 300 milliseconds, and the same for Score (scores may use @1 to @6 to play 300/1 to 300/32 for specific note, and can use V1 to V127 for volume control per note). Spaces in strings are pauses, and for scores we can use @1 to @6 to reduce pause value). We can use a thread to send a drum score every some seconds, to play a rhythm. Thread { score 10... : play 10,10 ....} as drums interval 1000 (second value for play 10 maybe 0 or any other 1 to 127 but always assign the drum machine. Midi
TUNE use kernel Beep which is synchronous and not leaving M2000 threads to process, until ends.
Module checkit {
\\ using internal speaker
TUNE 300, "C3DEFGABC4"
TUNE 300, "C3C#DD#EFF#GG#AA#BC4"
Thread {
score 10, 100, "CAC"
Play 10, 1
} as drums interval 1000
\\ Play in background (16 scores - no 10 for drum machine)
SCORE 1, 300, "C3DEFGABC4"
PLAY 1, 19 ' use score 1 with organ 19
Wait 2400
}
checkit
Mathematica /Wolfram Language
EmitSound@Sound[SoundNote /@ {0, 2, 4, 5, 7, 9, 11, 12}]
Nanoquery
import tonegen
note_freqs = {261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25}
tg = new(tonegen)
for freq in note_freqs
tg.beep(freq)
end
Nim
import endians, math
const
SampleRate = 44100
Duration = 8
DataLength = SampleRate * Duration
HdrSize = 44
FileLen = DataLength + HdrSize - 8
Bps = 8
Channels = 1
proc writeUint16(f: File; x: uint16) =
var x = x
var y: array[2, byte]
littleEndian16(y.addr, x.addr)
let n = f.writeBytes(y, 0, 2)
doAssert n == 2
proc writeUint32(f: File; x: uint32) =
var x = x
var y: array[4, byte]
littleEndian32(y.addr, x.addr)
let n = f.writeBytes(y, 0, 4)
doAssert n == 4
let file = open("notes.wav", fmWrite)
# Wav header.
file.write "RIFF"
file.writeUint32(FileLen)
file.write "WAVE"
file.write "fmt "
file.writeUint32(16) # length of format data.
file.writeUint16(1) # type of format(PCM).
file.writeUint16(Channels)
file.writeUint32(SampleRate)
file.writeUint32(SampleRate * Bps * Channels div 8)
file.writeUint16(Bps * Channels div 8)
file.writeUint16(Bps)
file.write "data"
file.writeUint32(DataLength) # size of data section.
# Compute and write actual data.
const Freqs = [261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3]
for freq in Freqs:
let omega = 2 * Pi * freq
for i in 0..<(DataLength div Duration):
let y = (32 * sin(omega * i.toFloat / SampleRate.toFloat)).toInt
file.write chr(y.byte) # Signed int to byte then to char as it’s easier this way.
file.close()
ooRexx
/* REXX ---------------------------------------------------------------
* 24.02.2013 Walter Pachl derived from original REXX version
* Changes: sound(f,sec) --> beep(trunc(f),millisec)
* $ -> sc
* @. -> f.
* re > ra (in sc)
*--------------------------------------------------------------------*/
sc='do ra mi fa so la te do'
dur=1250 /* milliseconds */
Do j=1 For words(sc) /* sound each "note" in the string*/
Call notes word(sc,j),dur /* invoke a subroutine for sounds.*/
End /* j */
Exit /* stick a fork in it, we're done.*/
notes: Procedure
Arg note,dur
f.=0 /* define common names for sounds.*/
f.la=220
f.si=246.94
f.te=f.si
f.ta=f.te
f.ti=f.te
f.do=261.6256
f.ut=f.do
f.ra=293.66
f.re=f.ra /* re is to be a synonym for ra */
f.mi=329.63
f.ma=f.mi
f.fa=349.23
f.so=392
f.sol=f.so
Say note trunc(f.note) dur
If f.note\==0 Then
Call beep trunc(f.note),dur /* sound the "note". */
Return
Perl
use MIDI::Simple;
# setup, 1 quarter note is 0.5 seconds (500,000 microseconds)
set_tempo 500_000;
# C-major scale
n 60; n 62; n 64; n 65; n 67; n 69; n 71; n 72;
write_score 'scale.mid';
Phix
You can run this online here.
-- -- demo\rosetta\Musical_scale.exw -- with javascript_semantics include pGUI.e include builtins\beep.e constant freq = {261.63,293.66,329.63,349.23,392,440,493.88,523.25}, durations = repeat(500,length(freq)-1) & 1000 function button_cb(Ihandle /*playbtn*/) beep(freq,durations,0.5) return IUP_DEFAULT end function IupOpen() Ihandle label = IupLabel("Please don't shoot the piano player, he's doing the best that he can!"), playbtn = IupButton("Play",Icallback("button_cb"),"PADDING=30x0"), hbox = IupHbox({IupFill(),playbtn,IupFill()},"MARGIN=0x20"), vbox = IupVbox({label,hbox}, "MARGIN=10x5, GAP=5"), dlg = IupDialog(vbox,`TITLE="Musical Scale"`) IupShow(dlg) if platform()!=JS then IupMainLoop() IupClose() end if
PowerShell
List of frequencies directly taken from the Python example.
$frequencies = 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25
foreach($tone in $frequencies){
[Console]::beep($tone, 500)
}
Processing
Requires the Processing Sound library.
//Aamrun, 2nd July 2022
import processing.sound.*;
float[] frequencies = {261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25};
SinOsc sine;
size(500,500);
sine = new SinOsc(this);
for(int i=0;i<frequencies.length;i++){
sine.freq(frequencies[i]);
sine.play();
delay(500);
}
Pure Data
scale.pd
#N canvas 898 363 360 460 10; #X obj 63 21 bng 15 250 50 0 empty start start 17 7 0 10 -262144 -1 -1; #X floatatom 135 21 5 0 0 1 bpm bpm -; #X obj 135 40 expr 1000 / ($f1/60); #X obj 135 62 int; #X obj 117 123 + 1; #X obj 117 145 mod 9; #X obj 63 123 int 1; #X obj 63 176 hradio 15 1 0 9 empty empty empty 0 -8 0 10 -262144 -1 -1 0; #X obj 63 196 route 0 1 2 3 4 5 6 7; #X msg 15 248 0; #X msg 93 248 62; #X msg 123 248 64; #X msg 63 248 60; #X msg 153 248 65; #X msg 183 248 67; #X msg 213 248 69; #X msg 243 248 71; #X msg 273 248 72; #X obj 111 313 mtof; #X obj 84 357 osc~; #X obj 84 384 dac~; #X obj 237 323 loadbang; #X obj 63 101 metro; #X msg 237 345 \; pd dsp 1 \; bpm 136 \; start 1; #X connect 0 0 22 0; #X connect 1 0 2 0; #X connect 2 0 3 0; #X connect 3 0 22 1; #X connect 4 0 5 0; #X connect 5 0 6 1; #X connect 6 0 4 0; #X connect 6 0 7 0; #X connect 7 0 8 0; #X connect 8 0 9 0; #X connect 8 1 12 0; #X connect 8 2 10 0; #X connect 8 3 11 0; #X connect 8 4 13 0; #X connect 8 5 14 0; #X connect 8 6 15 0; #X connect 8 7 16 0; #X connect 8 8 17 0; #X connect 9 0 19 0; #X connect 9 0 22 0; #X connect 10 0 18 0; #X connect 11 0 18 0; #X connect 12 0 18 0; #X connect 13 0 18 0; #X connect 14 0 18 0; #X connect 15 0 18 0; #X connect 16 0 18 0; #X connect 17 0 18 0; #X connect 18 0 19 0; #X connect 19 0 20 0; #X connect 19 0 20 1; #X connect 21 0 23 0; #X connect 22 0 6 0;
Python
(Windows)
>>> import winsound
>>> for note in [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]:
winsound.Beep(int(note+.5), 500)
>>>
Library: SDL2 (pip install PySDL2)
import sys
import ctypes
import math
import time
import struct
import sdl2
import sdl2.sdlmixer as mixer
def create_sound(frequency, duration):
"""Create a buffer with sound at given frequency and duration"""
num_samples = int(48000 * duration)
wave = struct.pack(
f"<{num_samples}i",
*[
int(2**30 * math.sin(2 * math.pi * frequency / 48000 * t))
for t in range(num_samples)
]
)
length = num_samples * 4
sound_buffer = (ctypes.c_ubyte * length).from_buffer_copy(wave)
sound = mixer.Mix_QuickLoad_RAW(
ctypes.cast(sound_buffer, ctypes.POINTER(ctypes.c_ubyte)), length
)
return sound
def main():
"""Play sine wave"""
mixer.Mix_Init(0)
mixer.Mix_OpenAudioDevice(48000, sdl2.AUDIO_S32, 1, 2048, None, 0)
note = 261.63
semitone = math.pow(2, 1 / 12)
duration = 0.5 # seconds
for step in [0, 2, 2, 1, 2, 2, 2, 1]:
note *= semitone**step
sound = create_sound(note, duration)
mixer.Mix_PlayChannel(0, sound, 1)
time.sleep(duration)
return 0
if __name__ == "__main__":
sys.exit(main())
R
install.packages("audio")
library(audio)
hz=c(1635,1835,2060,2183,2450,2750,3087,3270)
for (i in 1:8){
play(audioSample(sin(1:1000), hz[i]))
Sys.sleep(.7)
}
Racket
With a quick and dirty WinMM interface.
#lang racket
(require ffi/unsafe ffi/unsafe/define)
(define-ffi-definer defmm (ffi-lib "Winmm"))
(defmm midiOutOpen (_fun [h : (_ptr o _int32)] [_int = -1] [_pointer = #f]
[_pointer = #f] [_int32 = 0] -> _void -> h))
(defmm midiOutShortMsg (_fun _int32 _int32 -> _void))
(define M (midiOutOpen))
(define (midi x y z) (midiOutShortMsg M (+ x (* 256 y) (* 65536 z))))
(for ([i '(60 62 64 65 67 69 71 72)]) (midi #x90 i 127) (sleep 0.5))
(sleep 2)
Raku
(formerly Perl 6)
for 0,2,4,5,7,9,11,12 {
shell "play -n -c1 synth 0.2 sin %{$_ - 9}"
}
REXX
/*REXX program sounds eight notes of the C major natural diatonic music scale.*/
parse arg ! /*obtain optional arguments from the CL*/
/* [↓] invoke boilerplate REXX code. */
if !all( arg() ) then exit /*determine which REXX is running, if */
/* any form of help requested, exit.*/
if \!regina & \!pcrexx then do
say "***error*** this program can't execute under:" !ver
exit 13
end
$ = 'do ra me fa so la te do' /*the words for music scale sounding. */
dur = 1/4 /*define duration as a quarter second. */
do j=1 for words($) /*sound each "note" in the string. */
call notes word($, j), dur /*invoke a subroutine for the sounds. */
end /*j*/ /* [↑] sound each of the words. */
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
notes: procedure expose !regina !pcrexx; arg note,dur /*obtain the arguments from list. */
@.= 0 /*define common names for sounds. */
@.la= 220; @.si= 246.94; @.te= @.si; @.ta= @.te; @.ti= @.te
@.do= 261.6256; @.ut= @.do; @.re= 293.66; @.ra= @.re; @.mi= 329.63
@.ma= @.mi; @.fa= 349.23; @.so= 392; @.sol= @.so
if @.note==0 then return /*if frequency is zero, skip it. */
if !pcrexx then call sound @.note,dur /*sound the note using SOUND bif. */
if !regina then do /* [↓] reformat some numbers. */
ms= format(dur*1000, , 0) /*Regina requires DUR in millisec.*/
intN= format(@.note, , 0) /* " " NOTE is integer.*/
call beep intN, ms /*sound the note using BEEP BIF.*/
end
return
/*─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
!all: !!=!;!=space(!);upper !;call !fid;!nt=right(!var('OS'),2)=='NT';!cls=word('CLS VMFCLEAR CLRSCREEN',1+!cms+!tso*2);if arg(1)\==1 then return 0;if wordpos(!,'? ?SAMPLES ?AUTHOR ?FLOW')==0 then return 0;!call=']$H';call '$H' !fn !;!call=;return 1
!cal: if symbol('!CALL')\=="VAR" then !call=; return !call
!env: !env= 'ENVIRONMENT'; if !sys=="MSDOS" | !brexx | !r4 | !roo then !env= 'SYSTEM'; if !os2 then !env= "OS2"!env; !ebcdic= 3=='f3'x; if !crx then !env="DOS"; return
!fid: parse upper source !sys !fun !fid . 1 . . !fn !ft !fm .; call !sys; if !dos then do; _= lastpos('\',!fn); !fm= left(!fn,_); !fn= substr(!fn,_+1); parse var !fn !fn "." !ft; end; return word(0 !fn !ft !fm, 1 + ('0'arg(1) ) )
!rex: parse upper version !ver !vernum !verdate .; !brexx= 'BY'==!vernum; !kexx= "KEXX"==!ver; !pcrexx= 'REXX/PERSONAL'==!ver | "REXX/PC"==!ver; !r4= 'REXX-R4'==!ver; !regina= "REXX-REGINA"==left(!ver, 11); !roo= 'REXX-ROO'==!ver; call !env; return
!sys: !cms= !sys=='CMS'; !os2= !sys=="OS2"; !tso= !sys=='TSO' | !sys=="MVS"; !vse= !sys=='VSE'; !dos= pos("DOS", !sys)\==0 | pos('WIN', !sys)\==0 | !sys=="CMD"; !crx= left(!sys, 6)=='DOSCRX'; call !rex; return
!var: call !fid; if !kexx then return space( dosenv( arg(1) ) ); return space( value( arg(1), , !env) )
Programming note: The general 1-line subroutines at the end of the REXX program are boilerplate code which:
- check for invocation with a ? single argument to support general documentation (help).
- check for invocation with a ?SAMPLES single argument to support documentation for sample usages.
- check for invocation with a ?FLOW single argument to support documentation for program logic flow.
- check for invocation with a ?AUTHOR single argument to support showing the author of the REXX pgm.
- defines several !ααα variables indicating:
- name and version of the REXX interpreter being used.
- name of the program used to clear the terminal screen.
- name of the (host) operating system being used.
- name of the subsystem to issue commands (via address).
- name of the pool used to set environmental variables.
- name by which the REXX program was invoked.
- name by which the REXX program was loaded (executed).
- how the REXX program is being invoked:
- as a command
- as a function
- as a subroutine
Ring
# Project : Musical scale
loadlib("C:\Ring\extensions\ringbeep\ringbeep.dll")
freqs = [[262,"Do"], [294,"Ra"], [330,"Me"], [349,"Fa"], [392,"So"], [440,"La"], [494,"Te"], [523,"do"]]
for f = 1 to len(freqs)
see freqs[f][2] + nl
beep(freqs[f][1],300)
next
Output video:
RPL
≪ 2 SWAP 12 / ^ 440 * ≫ 'FREQ' STO ≪ { -9 -7 -5 -4 -2 0 2 3 } 1 OVER SIZE FOR j DUP j GET FREQ .1 BEEP NEXT DROP ≫ 'GAMME' STO
Scala
Windows
import net.java.dev.sna.SNA
object PlayMusicScale extends App with SNA {
snaLibrary = "Kernel32"
val Beep = SNA[Int, Int, Unit]
println("Please don't shoot the piano player, he's doing the best that he can!")
List(0, 2, 4, 5, 7, 9, 11, 12).
foreach(f => Beep((261.63 * math.pow(2, f / 12.0)).toInt, if (f == 12) 1000 else 500))
println("That's all")
}
Sparkling
The following Sparkling program generates a WAVE audio file named "notes.wav" that can be played in order to achieve the required effect:
var sampleRate = 44100.0;
var duration = 8.0;
var dataLength = round(sampleRate * duration);
var dataLength_b0 = dataLength >> 0 & 0xff;
var dataLength_b1 = dataLength >> 8 & 0xff;
var dataLength_b2 = dataLength >> 16 & 0xff;
var dataLength_b3 = dataLength >> 24 & 0xff;
const adjustedHdrSize = 36;
var len = dataLength - adjustedHdrSize;
var len_b0 = len >> 0 & 0xff;
var len_b1 = len >> 8 & 0xff;
var len_b2 = len >> 16 & 0xff;
var len_b3 = len >> 24 & 0xff;
// WAV header
var wavhdr = "RIFF";
wavhdr ..= fmtstr("%c%c%c%c", len_b0, len_b1, len_b2, len_b3);
wavhdr ..= "WAVE";
wavhdr ..= "fmt ";
wavhdr ..= "\x10\x00\x00\x00";
wavhdr ..= "\x01\x00";
wavhdr ..= "\x01\x00";
wavhdr ..= "\x44\xac\x00\x00";
wavhdr ..= "\x44\xac\x00\x00";
wavhdr ..= "\x01\x00";
wavhdr ..= "\x08\x00";
wavhdr ..= "data";
wavhdr ..= fmtstr("%c%c%c%c", dataLength_b0, dataLength_b1, dataLength_b2, dataLength_b3);
// write wav header
var f = fopen("notes.wav", "w");
fwrite(f, wavhdr);
// compute and write actual data
var frequs = { 261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3 };
for var j = 0; j < duration; j++ {
var frequ = frequs[j];
var omega = 2 * M_PI * frequ;
for var i = 0; i < dataLength / 8; i++ {
var y = 32 * sin(omega * i / sampleRate);
var byte = fmtstr("%c", round(y));
fwrite(f, byte);
}
}
fclose(f);
Tcl
package require sound
# Encapsulate the tone generation
set filter [snack::filter generator 1 20000 0.5 sine -1]
set sound [snack::sound -rate 22050]
proc play {frequency length} {
global filter sound
$filter configure $frequency
$sound play -filter $filter
# Need to run event loop; Snack uses it internally
after $length {set donePlay 1}
vwait donePlay
$sound stop
}
# Major scale up, then down; extra delay at ends of scale
set tonicFrequency 261.63; # C4
foreach i {0 2 4 5 7 9 11 12 11 9 7 5 4 2 0} {
play [expr {$tonicFrequency*2**($i/12.0)}] [expr {$i%12?250:500}]
}
Ursa
decl double<> notes
append 261.63 293.66 329.63 349.23 392.00 440.00 493.88 523.25 notes
for (decl int i) (< i (size notes)) (inc i)
ursa.util.sound.beep notes<i> 0.5
end for
VBA
Option Explicit
Declare Function Beep Lib "kernel32" (ByVal Freq As Long, ByVal Dur As Long) As Long
Sub Musical_Scale()
Dim Fqs, i As Integer
Fqs = Array(264, 297, 330, 352, 396, 440, 495, 528)
For i = LBound(Fqs) To UBound(Fqs)
Beep Fqs(i), 500
Next
End Sub
V (Vlang)
As Vlang doesn't have any audio support in its standard library, we instead build a .wav file which can then be played using a utility such as SoX.
import strings
import os
import encoding.binary
import math
const (
sample_rate = 44100
duration = 8
data_length = sample_rate * duration
hdr_size = 44
file_len = data_length + hdr_size - 8
)
fn main() {
// buffers
mut buf1 := []byte{len:1}
mut buf2 := []byte{len:2}
mut buf4 := []byte{len:4}
// WAV header
mut sb := strings.new_builder(128)
sb.write_string("RIFF")
binary.little_endian_put_u32(mut &buf4, file_len)
sb.write(buf4)? // file size - 8
sb.write_string("WAVE")
sb.write_string("fmt ")
binary.little_endian_put_u32(mut &buf4, 16)
sb.write(buf4)? // length of format data (= 16)
binary.little_endian_put_u16(mut &buf2, 1)
sb.write(buf2)? // type of format (= 1 (PCM))
sb.write(buf2)? // number of channels (= 1)
binary.little_endian_put_u32(mut &buf4, sample_rate)
sb.write(buf4)? // sample rate
sb.write(buf4)? // sample rate * bps(8) * channels(1) / 8 (= sample rate)
sb.write(buf2)? // bps(8) * channels(1) / 8 (= 1)
binary.little_endian_put_u16(mut &buf2, 8)
sb.write(buf2)? // bits per sample (bps) (= 8)
sb.write_string("data")
binary.little_endian_put_u32(mut &buf4, data_length)
sb.write(buf4)? // size of data section
wavhdr := sb.str().bytes()
// write WAV header
mut f := os.create("notes.wav")?
defer {
f.close()
}
f.write(wavhdr)?
// compute and write actual data
freqs := [261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3]!
for j in 0..duration {
freq := freqs[j]
omega := 2 * math.pi * freq
for i in 0..data_length/duration {
y := 32 * math.sin(omega*f64(i)/f64(sample_rate))
buf1[0] = u8(math.round(y))
f.write(buf1)?
}
}
}
Wren
As Wren-cli doesn't have any built-in audio support, we instead build a .wav file which can then be played using a utility such as rhythmbox or SoX.
import "./sound" for Wav
var sampleRate = 44100
var duration = 8
var data = List.filled(sampleRate * duration, 0)
var freqs = [261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3]
for (j in 0...duration) {
var freq = freqs[j]
var omega = 2 * Num.pi * freq
for (i in 0...sampleRate) {
var y = (32 * (omega * i / sampleRate).sin).round & 255
data[i + j * sampleRate] = y
}
}
Wav.create("musical_scale.wav", data, sampleRate)
It's also possible to play .wav files which (preferably) have a sample rate of 44.1 kHz using DOME:
import "audio" for AudioEngine
class Main {
construct new() {}
init() {
AudioEngine.load("doremi", "musical_scale.wav")
AudioEngine.play("doremi")
}
update() {}
draw(alpha) {}
}
var Game = Main.new()
XPL0
\Square waves on the beeper speaker:
code Sound=39;
real Period; int I;
[Period:= 1190000.0/261.625565; \middle C
for I:= 2 to 9 do
[Sound(1, 4, fix(Period)); \times 2^(-1/6) else 2^(-1/12)
Period:= Period * (if I&3 then 0.890898719 else 0.943874313);
];
]
\MIDI grand piano (requires 32-bit Windows or Sound Blaster 16):
code Sound=39;
int Note, I;
[port($331):= $3F; \set MPU-401 into UART mode
Note:= 60; \start at middle C
for I:= 2 to 9+1 do \(last note is not played)
[port($330):= $90; port($330):= Note; port($330):= $7F;
Sound(0, 4, 1); \This "Sound" is off, but convenient 0.22 sec delay
Note:= Note + (if I&3 then 2 else 1);
];
]
Yabasic
// Rosetta Code problem: http://rosettacode.org/wiki/Musical_scale
// by Galileo, 03/2022
sample_rate = 44100
duration = 8
dataLength = sample_rate * duration
hdrSize = 44
fileLen = dataLength + hdrSize - 8
data 261.6, 293.6, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3
sub int_to_bytes(dato, long)
local dato$, esp, esp$, i
esp$ = "00000000"
dato$ = hex$(dato)
esp = long * 2
dato$ = right$(esp$ + dato$, esp)
for i = esp - 1 to 1 step -2
poke #fn, dec(mid$(dato$, i, 2))
next
end sub
fn = open("notesyab.wav", "wb")
print #fn, "RIFF";
int_to_bytes(fileLen, 4)
print #fn, "WAVEfmt ";
int_to_bytes(16, 4) // length of format data (= 16)
int_to_bytes(1, 2) // type of format (= 1 (PCM))
int_to_bytes(1, 2) // number of channels (= 1)
int_to_bytes(sample_rate, 4) // sample rate
int_to_bytes(sample_rate, 4) // sample rate * bps(8) * channels(1) / 8 (= sample rate)
int_to_bytes(1,2) // bps(8) * channels(1) / 8 (= 1)
int_to_bytes(8,2) // bits per sample (bps) (= 8)
print #fn, "data";
int_to_bytes(dataLength, 4) // size of data section
for j = 1 to duration
read f
omega = 2 * PI * f
for i = 0 to dataLength/duration-1
y = 32 * sin(omega * i / sample_rate)
byte = and(y, 255)
poke #fn, byte
next
next
close(fn)
if peek$("os") = "windows" then
system("notesyab.wav")
else // Linux
system("aplay notesyab.wav")
endif
ZX Spectrum Basic
10 REM Musical scale
20 LET n=0: REM Start at middle C
30 LET d=0.2: REM Make each note 0.2 seconds in duration
40 FOR l=1 TO 8
50 BEEP d,n
60 READ i: REM Number of semitones to increment
70 LET n=n+i
80 NEXT l
90 STOP
9000 DATA 2,2,1,2,2,2,1,2:REM WWHWWWH
- Programming Tasks
- Solutions by Programming Task
- Temporal media
- BASIC/Omit
- Blast/Omit
- Brlcad/Omit
- Openscad/Omit
- Action!
- Ada
- AmigaBASIC
- AutoHotkey
- BASIC256
- Befunge
- C
- C++
- Clojure
- Overtone
- Commodore BASIC
- Delphi
- Winapi.Windows
- EasyLang
- Emacs Lisp
- Forth
- FreeBASIC
- FreePascal
- FutureBasic
- Go
- J
- Java
- JavaScript
- Julia
- Kotlin
- LilyPond
- Lambdatalk
- Locomotive Basic
- Lua
- M2000 Interpreter
- Mathematica
- Wolfram Language
- Nanoquery
- Nim
- OoRexx
- Perl
- Phix
- Phix/pGUI
- Phix/online
- PowerShell
- Processing
- Pure Data
- Python
- R
- Racket
- Raku
- REXX
- Ring
- RPL
- Scala
- Net.java.dev.sna.SNA
- Sparkling
- Tcl
- Snack
- Ursa
- VBA
- V (Vlang)
- Wren
- Wren-sound
- DOME
- XPL0
- Yabasic
- ZX Spectrum Basic