14
\$\begingroup\$

The trumpet is a valved aerophone instrument, usually pitched in B♭. The sound is made when the player vibrates their lips to displace air inside the instrument. That vibration is acquired by setting one's mouth in a specific way, called the embouchure. Different embouchures, with tighter or looser lips, produce different pitches.

Furthermore, each valve in the trumpet also changes the pitch of the instrument. When depressed, a valve closes a path inside the tubing of the instrument, making the air flow through a longer path, thus lowering the pitch of the original sound. For the purposes of this challenge, we'll consider the standard, B♭ trumpet, in which the first valve lowers the pitch by a full step, the second lowers the pitch by a half-step, and the third lowers the pitch by one and a half step.

The Challenge

Your challenge is to create a program or function that, given two inputs embouchure and valves, determines the pitch of the note being played.

For the purposes of this challenge, the notes will follow the sequence:

B♭, B, C, C♯, D, E♭, E, F, F♯, G, G♯, A.

Rules

  • I/O can be taken/given in any reasonable method.
  • Standard loopholes apply.
  • You're allowed to use b and # instead of and if you wish to.
  • Input for valves can be taken as a list of depressed valves (1, 3) or a boolean list (1, 0, 1).
  • This is , so shortest code in each language wins.

Test Cases:

Valves in these test cases is given as a boolean list, where 0 means depressed and 1 means pressed.

Embouchure:    Valves:   Output:
B♭             0 0 0     B♭
B♭             0 1 0     A
B♭             1 0 1     F
C♯             0 0 1     B♭
C♯             1 1 1     G
E♭             1 0 0     C♯
G              0 1 1     E♭
G♯             1 0 0     F♯
G♯             0 0 1     F
G              1 0 0     F
F♯             1 0 0     E
D              1 0 1     A
A              1 1 1     E♭
E              1 1 0     C♯
E              0 0 1     C♯

Disclaimer: I'm not much of a musician yet, so I do apologize for any butchering I might've made on the test cases. Corrections are appreciated.

\$\endgroup\$
  • 2
    \$\begingroup\$ Percussionist here. Wait wait, that's how you spell embouchure. Always thought it started with an a ;-) \$\endgroup\$ – MayorMonty Mar 15 '18 at 14:39
  • 1
    \$\begingroup\$ @vasilescur you're right. I'll fix those and review any other possible mistakes. Thanks for the heads up. \$\endgroup\$ – J. Sallé Mar 15 '18 at 15:44
  • 1
    \$\begingroup\$ As someone who's played trumpet a long time, I'm really confused by the Embouchure measurement... For example what is a C# Embouchure? \$\endgroup\$ – bendl Mar 15 '18 at 18:39
  • 1
    \$\begingroup\$ Should F# 100 be E not F? \$\endgroup\$ – Level River St Mar 15 '18 at 19:47
  • 2
    \$\begingroup\$ @bendl There's no such thing. You can't play a C# on a trumpet without pressing down any valves. Just specific notes (B♭-F-B♭-D-F-A♭-B♭...), the overtone series of B♭. Still, even if it doesn't reflect a real instrument the challenge is perfectly well defined. \$\endgroup\$ – Chris Mar 16 '18 at 2:23

11 Answers 11

4
\$\begingroup\$

Python 3 2, 125 119 81 bytes

lambda e,f,s,t,n=2*'A G# G F# F E Eb D C# C B Bb'.split():n[n.index(e)+2*f+s+3*t]

Try it online!

Saved a lot of bytes thanks to Jonathan Allan.


My original solution (in Python 3):

n=2*'Bb B C C# D Eb E F F# G G# A'.split()
e,f,s,t=str(input()).split()
print(n[n.index(e,9)-2*int(f)-int(s)-3*int(t)])

Try it online!

Saved 6 bytes thanks to @HyperNeutrino.


Explanation

First, I make an array of notes, but doubled in length so I don't have to worry about looping around from Bb to A.

Then, I take input in the following format (for example):

Bb 1 0 1

I then find the index of the starting note using n.index(e,9) (the 9 is there to make sure that I start well in the middle of the (doubled) list. I calculate the desired offset with the expression:

2*int(f) - int(s) - 3*int(t)

Where f is the first valve, s is the second valve, and t is the third.

Finally, it simply prints the note found in the list by subtracting the offset from the starting index.

\$\endgroup\$
  • 3
    \$\begingroup\$ save a few bytes by separating by spaces. "<some string>".split() splits by whitespace by default \$\endgroup\$ – HyperNeutrino Mar 15 '18 at 15:55
  • \$\begingroup\$ Save 30 bytes by moving to Python 2 (avoiding str and int casts and allowing evaluated input) and reversing the notes and offsetting forward (avoiding the ,9 in the index call. Try It Online! \$\endgroup\$ – Jonathan Allan Mar 15 '18 at 22:32
  • \$\begingroup\$ ...and another 8 moving to function (which works in Python 2 or 3) Try It Online! \$\endgroup\$ – Jonathan Allan Mar 15 '18 at 22:41
  • \$\begingroup\$ @JonathanAllan I learned several Python golfing tricks from your improvements. Thank you so much! \$\endgroup\$ – vasilescur Mar 16 '18 at 12:23
  • \$\begingroup\$ ...in fact you can use the list in its original order without repetition and subtract values since the negative index never goes out of bounds (the most negative would be 'Bb', 1, 1, 1 taking you to index -6 which would be E, as required) - it's what TFeld has since done. \$\endgroup\$ – Jonathan Allan Mar 16 '18 at 17:48
3
\$\begingroup\$

Wolfram Language (Mathematica), 100 bytes (and 134 for a working trumpet)

l="Bb,B,C,C#,D,Eb,E,F,F#,G,G#,A"~StringSplit~",";f=l[[Mod[#&@@#&@@l~Position~#-2#2-#3-3#4-1,12]+1]]&

Try it online!

Quite straightforward.

l="Bb,B,C,C#,D,Eb,E,F,F#,G,G#,A"~StringSplit~",";f=EmitSound@SoundNote[l[[Mod[#&@@#&@@l~Position~#-2#2-#3-3#4-1,12]+1]],1,"Trumpet"]&

A better output for the cost of 34 bytes.

\$\endgroup\$
  • \$\begingroup\$ Wait ... Mathematica has Audio output??? Wicked! \$\endgroup\$ – Titus Mar 16 '18 at 12:41
  • \$\begingroup\$ @Titus yes. For sound notes, it is provided by midi \$\endgroup\$ – Keyu Gan Mar 16 '18 at 12:57
  • \$\begingroup\$ Of course Mathematica has a built-in for audio output. This is gold. \$\endgroup\$ – J. Sallé Mar 16 '18 at 13:14
2
\$\begingroup\$

Jelly,  37  36 bytes

ØAḣ7;⁾#b“®JXrẊỤȥ’ṃnŒl$œṗ$Ḋ©i_⁸æ.J¤ị®

A dyadic link accepting the valves as a list of 1s or 0s as a list representing [second, first, third] on the left and the embouchure as a list of characters on the right which returns a list of characters.

Try it online!

How?

ØAḣ7;⁾#b“®JXrẊỤȥ’ṃnŒl$œṗ$Ḋ©i_⁸æ.J¤ị® - Link: list of integers, V; list of characters, E
ØA                                   - yield uppercase alphabet
  ḣ7                                 - head to index 7 = "ABCDEFG"
     ⁾#b                             - literal list of characters = "#b"
    ;                                - concatenate = "ABCDEFG#b"
        “®JXrẊỤȥ’                    - literal integer = 2270857278734171
                 ṃ                   - base decompress (i.e. convert to base 9 using the 'digits' "bABCDEFG#")
                                     -                 = "ABbBCC#DEbEFF#GG#"
                        $            - last two links as a monad:
                     $               -   last two links as a monad:
                   Œl                -     to lower case = "abbbcc#debeff#gg#"
                  n                  -     not equal? (vectorises) = [1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0]
                      œṗ             -   partition at truthy indices = [[],"A","Bb","B","C","C#","D","Eb","E","F","F#","G","G#"]
                         Ḋ           - dequeue = ["A","Bb","B","C","C#","D","Eb","E","F","F#","G","G#"]
                          ©          - copy to register and yield
                           i         - first index of E in there
                                 ¤   - nilad followed by links as a nilad:
                             ⁸       -   chain's left argument, V
                                J    -   range of length [1,2,3]
                              æ.     -   dot product (i.e. 1*second + 2*first + 3*third)
                            _        - subtract
                                   ® - recall from register
                                  ị  - index into (1-based and modular)
\$\endgroup\$
2
\$\begingroup\$

Ruby, 71 bytes

->e,(b,c,d){a=%w{Bb B C C# D Eb E F F# G G# A};a[a.index(e)-b*2-c-d*3]}

Try it online!

70 chars but 80 bytes

->e,(b,c,d){a="B♭BCC♯DE♭EFF♯GG♯A".scan /.\W?/;a[a.index(e)-b*2-c-d*3]}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Javascript 96 bytes

Following @vasilescur idea, this is the implementation in js

(a,b,c,d,_="B♭,B,C,C♯,D,E♭,E,F,F♯,G,G♯,A".split`,`)=>(l=_.concat(_))[l.indexOf(a,9)-(2*b+c+3*d)]

a=(a,b,c,d,_="B♭,B,C,C♯,D,E♭,E,F,F♯,G,G♯,A".split`,`)=>(l=_.concat(_))[l.indexOf(a,9)-(2*b+c+3*d)]
console.log(a('B♭',0,0,0))
console.log(a('B♭',0,1,0))
console.log(a('B♭',1,0,1))
console.log(a('C♯',0,0,1))
console.log(a('C♯',1,1,1))
console.log(a('E♭',1,0,0))
console.log(a('G',0,1,1))
console.log(a('G♯',1,0,0))
console.log(a('G♯',0,0,1))
console.log(a('G',1,0,0))
console.log(a('F♯',1,0,0))
console.log(a('D',1,0,1))
console.log(a('A',1,1,1))
console.log(a('E',1,1,0))
console.log(a('E',0,0,1))

\$\endgroup\$
  • \$\begingroup\$ 3 bytes less ;) BTW the flats and sharps should be counted as 3 bytes aren't they? \$\endgroup\$ – Shieru Asakoto Mar 16 '18 at 2:49
  • \$\begingroup\$ Oh nvm (I didn't see that b and # are allowed) but you need to use b and # instead of flats and sharps. \$\endgroup\$ – Shieru Asakoto Mar 16 '18 at 2:55
1
\$\begingroup\$

Batch, 188 bytes

@set n=%1
@set/aC=0,D=2,Eb=3,E=4,F=5,G=7,A=9,Bb=10,B=11,n=(%n:#=+1%+12-%2*2-%3-%4*3)%%12
@for %%n in (C.0 C#.1 D.2 Eb.3 E.4 F.5 F#.6 G.7 G#.8 A.9 Bb.10 B.11)do @if %%~xn==.%n% echo %%~nn

Uses # and b: this means that Eb and Bb are legal variable names; # is handled by doing a string replacement to +1. The result of the string replacement is then automatically evaluated and the valves are then taken into account before the result is looked up in a list.

\$\endgroup\$
1
\$\begingroup\$

Stax, 32 bytes

τ┤=Yº○!AÄΔâß₧←╥╟ö'ÄD├æñßf╧å▬tó÷╖

Run and debug it online

It takes a note name and a list of depressed valves. It builds an array of note names, then calculates the total valve interval, and gets the note at that offset in the array.

"AbABbBCC#DEbEFF#G" just a literal
{VA#}(Y             partition at capital letters and store in y
,]I                 get the index of the input note
,2R:t               swap 1s and 2s in valve list
{-F                 subtract valve list from note index
y@                  look up result from note array

Run this one

\$\endgroup\$
1
\$\begingroup\$

Python 2, 84 79 bytes

lambda e,a,b,c,s='Bb B C C# D Eb E F F# G G# A'.split():s[s.index(e)-2*a-b-3*c]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 92 86 82 bytes

*r=L"扢bc⍣d扥ef⍦g⍧a",*u;v(z,y,x,w)short*z;{u=wcschr(r,*z);u-=2*y+x+3*w;u+=(u<r)*12;}

Try it online!

Adapted from @Vazt's implementation.

\$\endgroup\$
0
\$\begingroup\$

Perl6/Rakudo 73 chars

Technically this is 83 bytes because I put the Unicode characters in, but swapping them for the ASCII equivalents would give 73 bytes.

As a {code block} with parameters like $^a this is a lambda, with a signature ($a, $b, $c, $d).

{$_=2*$^b+$^c+3*$^d;'AG♯GF♯FEE♭DC♯CBB♭'x 2~~/$^a(\w\W?)**{$_}/~~/\w\W?$/}

Call it:

say { ... }("D", 1, 0, 1)
>> A

Less-golfed:

sub f($a, $b, $c, $d) {
   my $totalShift = 2*$b + $c + 3*$d;
   my $doubledScale = 'AG♯GF♯FEE♭DC♯CBB♭' x 2;
   my $matchEmbOnward = $doubledScale ~~ / $^a (\w\W?)**{$totalShift} /;
   my $matchFinalNote = $marchEmbOnward ~~ / \w \W? $ /;
   return $matchFinalNote;
}

Here we double a string '...' x 2 using the x infix operator, then searching for the embouchure followed by n notes using the smartmatch operator '...' ~~ /.../ - the regex hinges on \w\W? which is a word char then maybe a non-word char.

We look for n instances of that via (\w\W?)**{$_}, where we've already calculated n=$_ from params $b to $d. This yields a match from the embouchure note to the resulting note, of which we just want the last so we match that with another ~~ /\w\W?$/.

The calculation of $_ first is necessary to permit $^b implicit param creation on the block.

76 chars

An alternative using an array rather than string matches is 3 more chars:

{$_=<B♭ B C C♯ D E♭ E F F♯ G G♯ A>;.[((.first: $^a,:k)-2*$^b-$^c-3*$^d)%12]}

Finding the embouchure in the list is achieved with @arr.first: $^a, :k, which returns the index (key) of the found element with :k.

Setting the array to $_ (as an object) lets us use .first and .[ ] on it without spending too many characters.

\$\endgroup\$
0
\$\begingroup\$

C (gcc), 155 bytes

char r[][12]={"bb","b","c","c#","d","eb","e","f","f#","g","g#","a"};u;v(z,y,x,w)char*z;{for(;u<12;u++)if(!strcmp(z,r[u]))break;u=u-2*y-x-3*w;u=u<0?12+u:u;}

Try it online!

Simple approach.

Valve input is 0,1.

Embouchure input must be lowercase. Interestingly, TiO is not finding strcmpi() without including string.h, whereas mingw-gcc allows it with the standard -Wimplicit-function-declaration warning.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.