Musical scale

From Rosetta Code
Musical scale is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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.

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>

  1. include<stdio.h>
  2. include<conio.h>
  3. include<math.h>
  4. 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() { 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>

  1. include<windows.h>
  2. include<stdio.h>
  3. 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() { 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>


Lilypond

The lilypond tool produces musical score sheets and does not output notes to the sound device. <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>

Perl 6

<lang perl6>for 0,2,4,5,7,9,11,12 {

   shell "play -n -c1 synth 0.2 sin %{$_ - 9}"

}</lang>

Racket

With a quick and dirty WinMM interface. <lang racket>

  1. 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

Works with: PC/REXX
Works with: Personal REXX

<lang rexx>/*REXX pgm sounds 8 notes of the C major natural diatonic muscic scale. */ $ = 'do ra me fa so la te do' dur=1/4

         do j=1  for words($)         /*sound each "note" in the string*/
         call notes word($,j),dur     /*invoke a subroutine for sounds.*/
         end   /*j*/

exit /*stick a fork in it, we're done.*/ /*─────────────────────────────────NOTES subroutine─────────────────────*/ notes: procedure; 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;@.mi=329.63;@.ma=@.mi;@.fa=349.23;@.so=392;@.sol=@.so if @.note\==0 then call sound @.note,dur /*sound the "note".*/ return</lang>

Tcl

Library: Snack

<lang tcl>package require sound

  1. 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

}

  1. 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>