Musical scale: Difference between revisions
m →{{header|Mathematica}}: Fixed lang tag (I think) |
Added Scala |
||
Line 247: | Line 247: | ||
{{works with|PC/REXX}} |
{{works with|PC/REXX}} |
||
{{works with|Personal REXX}} |
{{works with|Personal REXX}} |
||
⚫ | |||
{{works with|Regina}} |
|||
⚫ | |||
parse arg !; if !all(arg()) then exit /*determine which REXX is running*/ |
parse arg !; if !all(arg()) then exit /*determine which REXX is running*/ |
||
Line 302: | Line 301: | ||
::::::::* as a function |
::::::::* as a function |
||
::::::::* as a subroutine |
::::::::* as a subroutine |
||
<br> |
|||
=={{header|Scala}}== |
|||
===Windows=== |
|||
[[Category:Scala Implementations]] |
|||
{{libheader|net.java.dev.sna.SNA}} |
|||
<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") |
|||
}</lang> |
|||
=={{header|Sparkling}}== |
=={{header|Sparkling}}== |
Revision as of 16:20, 21 June 2014
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.
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.
AutoHotkey
<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</lang>
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.
<lang c>/*Abhishek Ghosh, 6th November 2013, Rotterdam*/
- 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; }</lang>
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.
<lang c>/*Abhishek Ghosh, 6th November 2013, Rotterdam*/
- 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; }</lang>
J
<lang J>require'media/wav' 0.25 wavnote 0 2 4 5 7 9 11 12</lang>
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).
Lilypond
The lilypond tool produces musical score sheets and midi files - if asked for - but does not output notes to the sound device directly. <lang lilypond>% Start at middle C \relative c' {
c d e f g a b c
}</lang>
Locomotive Basic
<lang locobasic>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),f,p 140 sound 1,p,100 150 return 160 data 1,3,5,6,8,10,12,13,-1</lang>
Mathematica
<lang mathematica>EmitSound@Sound[SoundNote /@ {0, 2, 4, 5, 7, 9, 11, 12}]</lang>
ooRexx
<lang 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</lang>
Perl 6
<lang perl6>for 0,2,4,5,7,9,11,12 {
shell "play -n -c1 synth 0.2 sin %{$_ - 9}"
}</lang>
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) <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)
>>> </lang>
Racket
With a quick and dirty WinMM interface. <lang racket>
- 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) </lang>
REXX
<lang rexx>/*REXX pgm sounds 8 notes of the C major natural diatonic music scale.*/
parse arg !; if !all(arg()) then exit /*determine which REXX is running*/
if \!regina & \!pcrexx then do
say '***error!***' say "this program can't execute under:" !ver exit 13 end
$ = 'do ra me fa so la te do' /*words for music scale sounding.*/ 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 ?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
Scala
Windows
<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")
}</lang>
Sparkling
The following Sparkling program generates a WAVE audio file named "notes.wav" that can be played in order to achieve the required effect: <lang Sparkling> 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);</lang>
Tcl
<lang 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}]
}</lang>
XPL0
<lang 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); ];
]</lang>
ZX Spectrum Basic
<lang zxbasic>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</lang>