Help me play the Trumpet

14

2

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.

J. Sallé

Posted 2018-03-15T14:24:49.377

Reputation: 3 233

Sandbox – J. Sallé – 2018-03-15T14:26:16.017

2Percussionist here. Wait wait, that's how you spell embouchure. Always thought it started with an a ;-) – MayorMonty – 2018-03-15T14:39:16.153

Some of these test cases don't seem to match the problem. For example, G#, 1, 1, 0 should be F, not F#, and C#, 1, 1, 1 should be G, not F#. – vasilescur – 2018-03-15T15:42:00.147

1@vasilescur you're right. I'll fix those and review any other possible mistakes. Thanks for the heads up. – J. Sallé – 2018-03-15T15:44:10.613

1As someone who's played trumpet a long time, I'm really confused by the Embouchure measurement... For example what is a C# Embouchure? – bendl – 2018-03-15T18:39:26.960

@bendl I’m still beginning my studies on the trumpet, so I can’t really tell if those are particularly accurate or not. I tried to gather as much information as possible, and inferred some of that information from what I had available. Does that change whether or not the challenge is viable? If not, I think I’ll leave it as it is. As I said in the disclaimer, I’m not much of a musician yet and apologize for any inaccuracies. – J. Sallé – 2018-03-15T19:19:26.577

1Should F# 100 be E not F? – Level River St – 2018-03-15T19:47:00.823

I don't think it changes the viability, I was just totally confused by the concept. – bendl – 2018-03-15T19:50:46.090

@LevelRiverSt yes, thanks! – J. Sallé – 2018-03-15T20:01:11.310

2@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. – Chris – 2018-03-16T02:23:13.847

@bendl Same, got confused there – ericw31415 – 2018-03-17T17:42:47.650

@bendl playing only on the mouthpiece, sure you can have a C# embouchure. Attach the instrument and it won't work so well, as noted in other comments, unless you play in a high enough octave... :) – Oliphaunt - reinstate Monica – 2018-08-10T22:09:57.403

Answers

4

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.

vasilescur

Posted 2018-03-15T14:24:49.377

Reputation: 341

3save a few bytes by separating by spaces. "<some string>".split() splits by whitespace by default – HyperNeutrino – 2018-03-15T15:55:50.773

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!

– Jonathan Allan – 2018-03-15T22:32:10.403

...and another 8 moving to function (which works in Python 2 or 3) Try It Online!

– Jonathan Allan – 2018-03-15T22:41:37.733

@JonathanAllan I learned several Python golfing tricks from your improvements. Thank you so much! – vasilescur – 2018-03-16T12:23:46.777

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

– Jonathan Allan – 2018-03-16T17:48:40.793

3

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.

Keyu Gan

Posted 2018-03-15T14:24:49.377

Reputation: 2 028

Wait ... Mathematica has Audio output??? Wicked! – Titus – 2018-03-16T12:41:54.720

Of course Mathematica has a built-in for audio output. This is gold. – J. Sallé – 2018-03-16T13:14:29.500

2

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)

Jonathan Allan

Posted 2018-03-15T14:24:49.377

Reputation: 67 804

2

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!

Asone Tuhid

Posted 2018-03-15T14:24:49.377

Reputation: 1 944

1

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))

Luis felipe De jesus Munoz

Posted 2018-03-15T14:24:49.377

Reputation: 9 639

3 bytes less ;) BTW the flats and sharps should be counted as 3 bytes aren't they? – Shieru Asakoto – 2018-03-16T02:49:31.187

Oh nvm (I didn't see that b and # are allowed) but you need to use b and # instead of flats and sharps. – Shieru Asakoto – 2018-03-16T02:55:43.460

1

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.

Neil

Posted 2018-03-15T14:24:49.377

Reputation: 95 035

1

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

recursive

Posted 2018-03-15T14:24:49.377

Reputation: 8 616

1

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!

TFeld

Posted 2018-03-15T14:24:49.377

Reputation: 19 246

1

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.

ceilingcat

Posted 2018-03-15T14:24:49.377

Reputation: 5 503

0

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.

Phil H

Posted 2018-03-15T14:24:49.377

Reputation: 1 376

0

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.

vazt

Posted 2018-03-15T14:24:49.377

Reputation: 311