| Bytes | Lang | Time | Link |
|---|---|---|---|
| 146 | APLNARS | 251011T125424Z | Rosario |
| 047 | 05AB1E | 251013T081954Z | Kevin Cr |
| 280 | Maple | 251011T193940Z | dharr |
| 066 | Charcoal | 251010T230514Z | Neil |
| 103 | WhatLang | 251011T155622Z | YufangIG |
| 056 | Jelly | 251010T204744Z | Jonathan |
| 106 | JavaScript ES7 | 251010T152740Z | Arnauld |
APL(NARS), 146 chars
r←d w;i;l;m;n
i←1⋄r←⍬⋄l←≢w
n←0⋄m←⌊.5+110×2*12÷⍨2+{⍵=2:-∞⋄⍵}'1 2 34 5 6 7d r mf s l tD R MF S L T'⍳i⊃w
n+←1⋄→4×⍳l<i+←1⋄→3×⍳'-'=i⊃w
r,←⊂m n⋄→2×⍳l≥i
// +/14 13 75 28 16=146
The ungolfed version, with line number labels and indentation 4chars for loops
r←d w;i;l;m;n
1: i←1⋄r←⍬⋄l←≢w
2: n←0⋄m←⌊.5+110×2*12÷⍨2+{⍵=2:-∞⋄⍵}'1 2 34 5 6 7d r mf s l tD R MF S L T'⍳i⊃w
3: n+←1⋄→4×⍳l<i+←1⋄→3×⍳'-'=i⊃w
4: r,←⊂m n⋄→2×⍳l≥i
The input has to be a not void string with chars in '1234567drmfsltDRMFSLT -' the output is a array that has as elements one array of one float and one integer.
The formula for calculate the frequences in Hz of notes from Do3 it seems to be
h←{⌊.5+110×2*12÷⍨⍵+3}
h¨0..12
131 139 147 156 165 175 185 196 208 220 233 247 262
Do Do# Re Re# MI Fa Fa# Sol Sol#La La# Si Do
0 1 2 3 4 5 6 7 8 9 10 11 12
Where 0 is the Do3, 1 is Do#3, 2 is Re3 ecc
h would continue to calculate the frequence in herz in both diretion
Do1 Do2 Do3 Do4 Do5
..-24..-12..0.. 12.. 24..
The note La4 has the number 12+9=21 440Hz
h 21
440
How you can see here the notes are 12 not 7, but the question want find only the subset of these notes the ones Do Re MI Fa Sol La Si Do, only, 7 notes...
The problem has an easy solution, it is enoght use the formula h above and build the string of search with spaces where are the lost notes as
'1 2 34 5 6 7d r mf s l tD R MF S L T'
These are all corrispondences of notes
↑¨d '1234567drmfsltDRMFSLT'
131 147 165 175 196 220 247 262 294 330 349 392 440 494 523 587 659 698 784 880 988
at '1' there is 131 Hz Do3, at '2' there is 147Hz is Re,..., at 'T' there is 988Hz is Si5
h 11+12×2
988
Test:
d 'ssl-s-D-t-- ssl-s-R-D-- ssS-M-D-t-l-- FFM-D-R-D--'
392 1 392 1 440 2 392 2 523 2 494 3 0 1 392 1 392 1 440 2 392 2 587 2 523 3
0 1 392 1 392 1 784 2 659 2 523 2 494 2 440 3 0 1 698 1 698 1 659 2 52
3 2 587 2 523 3
the note here indicates from "s" has a round value of 392Hz not 391Hz at last seen the table in the wikipedia page on the notes, so above could be ok too.
The function d can make to work with all the 12 notes if the name of missed notes are add example:
'1a2b34c5e6g7dhrimfnsolptDqRuMFvSwLyT'
'1 2 34 5 6 7d r mf s l tD R MF S L T'
'0123456789abcdefghijklmnopqrstuvwxyz'
05AB1E, 47 bytes
v7LJ.•/[&8•Du««ykDdiÌ12*Ì7÷12/o6b*ïX‚ë(ÝyðÊi+])
Attempt it online or verify all test cases. (Minor note, uses ATO instead of TIO, since there used to be an 05AB1E bug with o and TIO is too outdated and therefore still has that bug.)
With extended rules: 88* bytes
v7LJ.•/[&8•Du««yk©di®Ì12*Ì7÷12/o6b*ïX‚ëy'(QiX;Uëy')QiX·Uëy'{Qi¶ëy'}Qi)¶¡`D««`ë¾X‚yðÊi+])
(Assumes {/} won't be nested.)
Try it online. (This one does use TIO instead of ATO with manual +5 bytes workaround for the bug (the Dïs‚à), since ATO times out for some reason..)
Explanation:
Uses a derived formula of the one used by @Neil in his Charcoal answer:
$$f=2^{\frac{1}{12}\left\lfloor\frac{12(n+2)+2}{7}\right\rfloor}\times110 $$
based on the 0-based index \$n\$ in "1234567drmfsltDRMFSLT".
v # Loop over the characters `y` of the (implicit) input-string:
7LJ # Push a list in the range [1,7], and join it to a string
.•/[&8• # Push compressed string "drmfslt"
Du # Push an uppercase copy
«« # Append the three strings together
yk # Get the (0-based) index of the current character in this,
# or -1 if it's one of the other characters
D # Duplicate this index
di # Pop the copy, and if it's NOT -1:
Ì # Increase the index by 2
12* # Multiply by 12
Ì # Increase by 2 again
7÷ # Integer-divide by 7
12/ # Divide by 12
o # 2 to the power this
6b* # Multiply by 110 (6 as binary)
ï # Floor it to an integer
X‚ # Pair it with a 1
ë # Else (it's a space or "-"):
( # Negate the -1 to a 1
Ý # Pop and push list [0,1]
yðÊi # If `y` is NOT a space (aka, it's "-"):
+ # Add this [0,1] to the values of the top pair instead
] # Close the if-statement and loop
) # Wrap all pairs on the stack into a list
# (which is output implicitly)
v7LJ.•/[&8•Du««yk # Same as above
© # Store this index in variable `®` (without popping)
di # Pop and if it's NOT -1:
® # Push index `®`
Ì12*Ì7÷12/o6b*ï # Same as above
X‚ # Pair it with the current frequency `X` (1 by default)
ë # Else (it's one of " -(){}"):
y'(Qi '# If the current character is a "(":
X;U # Push `X`, half it, pop and store it as new `X`
ëy')Qi '# Else-if the current character is a ")":
X·U # Double `X` instead
ëy'{Qi '# Else-if the current character is a "{":
¶ # Push a newline character
ëy'}Qi '# Else-if the current character is a "}":
) # Wrap all pairs on the stack into a list
¶¡ # Split it on the newline character
` # Pop and push both lists in this pair to the stack
D # Duplicate the second list
«« # Merge the three lists of pairs together
` # Pop and push all pairs separately to the stack again
ë # Else (the current character is "-" or " ")
¾X‚ # Push pair [0,X]
yðÊi+]) # Same as above
See this 05AB1E tip of mine (section How to compress strings not part of the dictionary?) to understand why .•/[&8• is "drmfslt".
Maple, 181 179 bytes, 282* 280* bytes
-2 bytes by using @Neil's formula.
Without extensions:
proc(s)S:=seq:g:=table([S("1234567drmfsltDRMFSLT ")]=~[S(floor(110*2^(iquo(12*n+14,7)/12)),n=1..21),0]);w,j:=<[]>,0;S(`if`(i="-",(w[j]+=[0,1]),[(j++),(w(j):=[g[i],1])]),i=s);w end;
Ugolfed:
proc(s)
S:=seq: # abbreviate seq as S
# next line sets up a table mapping a character to its frequency using @Neil's formula
g:=table([S("1234567drmfsltDRMFSLT ")]=~[S(floor(110*2^(iquo(12*n+14,7)/12)),n=1..21),0]);
w,j:=<[]>,0; # initialize output Vector w and its size j
for i in s do
if i="-" then
w[j]+=[0,1] # if "-" then add 1 to beats of previous note
else
j++;
w(j):=[g[i],1]
fi
od;
w;
end;
Inputs string, outputs Vector of [freq,beats]. Golfed version condenses the for loop and if statement into a seq with expression form for if.
Extended version, 280 bytes.
ungolfed;
proc(s)
S:=seq: # abbreviate seq as S
# next line sets up a table mapping a character to its frequency using @Neil's formula
g:=table([S("1234567drmfsltDRMFSLT ")]=~[S(floor(110*2^(iquo(12*n+14,7)/12)),n=1..21),0]);
w,j,v:=<[]>,0,1; # initialize output Vector w and its size j and default speed v
for i in s do
if i="-" then
w[j]+=[0,v] # if "-" then add v to beats of previous note
elif i="(" then
v/=2 # double speed
elif i=")" then
v*=2 # halve speed
elif i="{" then
k:=j # record current position
elif i="}" then
w,=S(w[k+1..]); # repeat
j+=j-k # update position
else
j++;
w(j):=[g[i],v]
fi
od;
w;
end;
golfed:
proc(s)S:=seq:g:=table([S("1234567drmfsltDRMFSLT ")]=~[S(floor(110*2^(iquo(12*n+14,7)/12)),n=1..21),0]);w,j,v:=<[]>,0,1;S(`if`(i="-",(w[j]+=[0,v]),`if`(i="(",(v/=2),`if`(i=")",(v*=2),`if`(i="{",(k:=j),`if`(i="}",[(w,=S(w[k+1..])),(j+=j-k)],[(j++),(w(j):=[g[i],v])]))))),i=s);w;end;
Note: the beats are output as fractions: 1/2, 3/2 etc. Add one byte to output as floats (initialize v as 1. not 1).
Charcoal, 66 bytes
≔drmfsltηFS≡ι-⊞υE⊟υ⁺κλ ⊞υE²κ⊞υ⟦⌊×¹¹⁰X²∕⁺²÷×¹²∨Σι⁺⁸⌕⁺η↥ηι⁷¦¹²¦¹⟧⭆¹υ
Try it online! Link is to verbose version of code. Explanation: By assigning the values 8..21 to the letters d..T respectively, the following formula gives the exact frequency of the note:
$$ f = 110 \times 2 ^ { \frac 1 {12} \left \lfloor \frac { 12 n + 14 } 7 \right \rfloor } $$
≔drmfsltη
Get the notes C4-B4 in a variable to avoid repetition.
FS≡ι
Switch over the input characters.
-⊞υE⊟υ⁺κλ
For a -, extend the duration of the previous note or rest.
⊞υE²κ
For a space, append a length 1 rest.
⊞υ⟦⌊×¹¹⁰X²∕⁺²÷×¹²∨Σι⁺⁸⌕⁺η↥ηι⁷¦¹²¦¹⟧
Otherwise, append a length 1 note of the floor of the frequency as given by the above formula.
⭆¹υ
Pretty-print the final list of notes.
Add 13 bytes to additionally handle ( and ):
≔drmfsltη≔¹ζFS≡ι-⊞υE⊟υ⁺κ∧λζ ⊞υ⟦⁰ζ⟧(≦⊘ζ)≦⊗ζ⊞υ⟦⌊×¹¹⁰X²∕⁺²÷×¹²∨Σι⁺⁸⌕⁺η↥ηι⁷¦¹²ζ⟧⭆¹υ
Attempt This Online! Link is to verbose version of code. (Using ATO to avoid decimals in the output.)
Add 13 bytes to additionally handle { and } (but not nested):
≔drmfsltη≔¹ζFS≡ι-⊞υE⊟υ⁺κ∧λζ ⊞υ⟦⁰ζ⟧(≦⊘ζ)≦⊗ζ{≔Lυε}F✂υε⊞υκ⊞υ⟦⌊×¹¹⁰X²∕⁺²÷×¹²∨Σι⁺⁸⌕⁺η↥ηι⁷¦¹²ζ⟧⭆¹υ
Try it online! Link is to verbose version of code. (This version also includes support for ( and ), but the support for { and } can also be added to the original version.)
Out of interest, I wrote a ZX Spectrum 128K program to translate a basic rpip7 string to a ZX Spectrum 128 PLAY command string. It only works for note lengths of 1-4 due to limitations of the PLAY command.
10 INPUT LINE a$: REM use LET a$="music goes here" for testing to save retyping each time
20 LET p$="": LET k=1: LET d=15: LET r=16: LET m=17: LET f=18: LET s=19: LET l=20: LET t=21: REM d..t are the note pitches, k is the current length and p$ is the play command string
30 FOR i=LEN(a$) TO 1 STEP -1: REM looping backwards to make the length calculation easier
40 IF a$(i)="-" THEN LET k=k+1: GO TO 90: REM increase the length
50 IF a$(i)=" " THEN LET p$="3567"(k)+"&"+p$: GO TO 80: REM a rest of the given length
60 LET n=VAL a$(i)-7*(a$(i)>"_")+1: REM pitch of current note, 2=C3 up to 22=B5
70 LET p$="O"+STR$ INT ((n+19)/7)+"N"+"3567"(k)+CHR$ (65+n-7*INT (n/7))+p$: REM a note of the right pitch and length
80 LET k=1: REM reset length
90 NEXT i
100 PLAY p$
WhatLang, 103 bytes
[( |.-*)g]match@(len@\0,\_:' ?{"1234567drmfsltDRMFSLT"\in@\_12*7/2+flr@12*2\pow@110*flr@\2>!!}_0\2>)#.
Takes string from the stack as input, outputs the result.
Using the formula: $$\mathrm{frequency} = 2^{\frac1{12}\left\lfloor\frac{12x}7+2\right\rfloor}\times110$$
Jelly, 56 bytes
⁽'ḍBṚÄṾ€;“½⁸VYɼ⁼'»;Œs¤i÷12µ2*×110Ḟ⁸aĖ
‘1¦€0¦;ç¥⁼”-$}?ƒḟ`
A moadic Link that accepts a list of 1234567drmfsltDRMFSLT - characters and yields a list of [length, frequency] pairs.
How?
⁽'ḍBṚÄṾ€;“...»;Œs¤i÷12µ2*×110Ḟ⁸aĖ - Link 1: any, Unused; character, C (never '-')
⁽'ḍBṚ - 21928 in binary, reversed -> [0,0,1,0,1,0,1,1,0,1,0,1,0,1]
Ä - cumulative sums -> [0,0,1,1,2,2,3,4,4,5,5,6,6,7]
Ṿ€ - unevaluate each -> "00112234455667"
¤ - nilad followed by link(s) as a nilad:
“...» - dictionary-string = "durum"+"fo"+"salet"
= "durumfosalet"
Œs - swap-case = "DURUMFOSALET"
; - concatenate = "durumfosaletDURUMFOSALET"
; - concatenate = "00112234455667durumfosaletDURUMFOSALET"
i - first 1-index of {C} or 0 if not found (if C is a space)
÷12 - divide that by twelve
µ - start a new monadic chain - f(E=that)
2* - two exponentiate {E}
×110Ḟ - multiply that by 110 and floor
-> frequency or 110 if C is a space
⁸a - E logical AND {that} -> frequency (0 for a space)
Ė - enumerate -> [[1, frequency]]
‘1¦€0¦;ç¥⁼”-$}?ƒḟ` - Main Link: list of characters, Score
ḟ` - {Score} filter discard itself -> []
ƒ - starting with Result = [], reduce {Score} by:
? - if...
⁼”-$} - ...condition: {Next} is equal to '-'?
€0¦ - ...then: to the rightmost element of {Result}:
‘1¦ - increment the first element (the length value)
;ç¥ - ...else: concatenate the result of Link 1({Result}, {Next})
The warrior was BṚÄṾ€ going into battle with only durum fo salet (some wheat for a helmet).
JavaScript (ES7), 106 bytes
-5 by using an unfragmented lookup table, as in Neil's answer
s=>s.match(/.-*/g).map(s=>[s<1?0:2**(~~(12*"_1234567drmfsltDRMFSLT".search(s[0])/7+2)/12)*110|0,s.length])
JavaScript (ES7), 111 bytes
-2 thanks to Jonathan Allan
s=>s.match(/.-*/g).map(s=>[(n=" ..1.2.34.5.6.7d.r.mf.s.l.tD.R.MF.S.L.T".search(s[0])/12)&&2**n*110|0,s.length])
Formula
Given \$n\in[3\dots38]\$, the formula for the frequency is:
$$\left\lfloor2^{(n-24)/12}\times 440\right\rfloor$$
Which can be simplified to:
$$\left\lfloor2^{n/12}\times\left(2^{-24/12}\times 440\right)\right\rfloor=\left\lfloor2^{n/12}\times110\right\rfloor$$