Musical scale: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|REXX}}: changed remark on ooRexx (which IS another Rexx))
m (→‎{{header|REXX}}: wrong tagging used)
Line 243: Line 243:
{{works with|Personal REXX}}
{{works with|Personal REXX}}
{{works with|Regina}}
{{works with|Regina}}
{{does not work with|ooRexx}}
<br>does not work with|ooRexx
<lang rexx>/*REXX pgm sounds 8 notes of the C major natural diatonic music scale.*/
<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*/
parse arg !; if !all(arg()) then exit /*determine which REXX is running*/

Revision as of 12:23, 14 March 2014

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.

AutoHotkey

Works with: AutoHotkey_L

<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*/

  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> /*Abhishek Ghosh, 6th November 2013, Rotterdam*/

  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>

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 mathem><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;

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
Works with: Regina


does not work with|ooRexx <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


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

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>