Musical note string (C#-4, F-3, etc.) to MIDI note value, in Python - string

The code in my answer below converts musical notes in strings, such as C#-4 or F-3, to their corresponding MIDI note values.
I am posting this because I am tired of trying to dig it up online every time I need it. I'm sure I'm not the only one who can find a use for it. I just wrote this up — it is tested and correct. It's in Python, but I feel that it pretty close to universally understandable.

#Input is string in the form C#-4, Db-4, or F-3. If your implementation doesn't use the hyphen,
#just replace the line :
# letter = midstr.split('-')[0].upper()
#with:
# letter = midstr[:-1]
def MidiStringToInt(midstr):
Notes = [["C"],["C#","Db"],["D"],["D#","Eb"],["E"],["F"],["F#","Gb"],["G"],["G#","Ab"],["A"],["A#","Bb"],["B"]]
answer = 0
i = 0
#Note
letter = midstr.split('-')[0].upper()
for note in Notes:
for form in note:
if letter.upper() == form:
answer = i
break;
i += 1
#Octave
answer += (int(midstr[-1]))*12
return answer

NOTES_FLAT = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']
NOTES_SHARP = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
def NoteToMidi(KeyOctave):
# KeyOctave is formatted like 'C#3'
key = KeyOctave[:-1] # eg C, Db
octave = KeyOctave[-1] # eg 3, 4
answer = -1
try:
if 'b' in key:
pos = NOTES_FLAT.index(key)
else:
pos = NOTES_SHARP.index(key)
except:
print('The key is not valid', key)
return answer
answer += pos + 12 * (int(octave) + 1) + 1
return answer

Related

How do I iterate through a list by the indices of a different list?

I want sub_main to be made from the 'sub' list as:
sub_main = ['c','d','e','f','j','k','l','m','n','o','p'...
I have tried:
for i in sub:
for j in main:
if j == i[0]:
while j != i[1]:
sub_main.append(j)
but it is an infinite loop for some reason
import string
sub_main = []
main = list(string.ascii_lowercase)
sub = [['c','f'],['j','p'],['r','t']]
import string
sub_main = []
main = list(string.ascii_lowercase)
sub = [['c', 'f'], ['j', 'p'], ['r', 't']]
indexed_main = {ch: i for i, ch in enumerate(main)}
for s in sub:
sub_main.extend(main[indexed_main[s[0]]:indexed_main[s[1]]+1])
import string
sub_main = []
main = list(string.ascii_lowercase)
sub = [['c','f'],['j','p'],['r','t']]
for chsub in sub:
amount = ord(chsub[1]) - ord(chsub[0])
remaining = amount
while remaining >= 0:
sub_main.append(main[ord(chsub[0])-ord('a') + amount - remaining])
remaining -= 1
This is how I would have done it, it uses the fact that every character has an ascii value.
Basically iterate over each sub-list in sub and get the amount of characters that are between the two in chsub.
main[ord(chsub[0])-ord('a') + amount - remaining] - This first finds the index of the character it should be on (c - a, for example, which is 2 which means it begins from main[2]).
Then inside that calculation I also check the difference between amount and remaining to see which character it needs to get past the initial character.
Result:
['c', 'd', 'e', 'f', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't']
The reason for your infinite loop has been given in a comment to your question, you never change j in the while, but 3 loops is too much for this issue.

How do I find character frequency form text file through iteration? (python3)

I'm trying to find a way to iterate through a text file and list to find character frequency. I understand that I could use Count() for this. But Count() gives everything including spaces periods and whatnots. Also it does not show the character frequency in alphabetical order. I found a way to do it and it works but not really. I'll explain later. Also when I try to put the frequency I get a KeyError. I'll also explain.
I don't want to put my whole project on here so I'll explain some stuff first. I have a separate list called alphabet_list which includes the alphabet. There's a text file that is already read through and converted into uppercase called new_text.
Character frequency Code:
for i in range(len(alphabet_list)):
for c in new_text:
if c == alphabet_list[i]:
count += 1
else:
count = 0
print(alphbet_list[i] + " " + str(count)
i += 1
Output
A 0
A 0
.
.
.
A 1
A 0
.
.
.
B 0
.
.
.
B 1
B 2
B 0
.
.
.
Z 0
P.S the str(count) is temporarily there because I want to see how it looks like print out, I needed to store the result in dictionary
My output would be that, like I said it works but not really. It will iterate but it iterates through every letter and prints out the result already and does not iterate the whole text file and just print final result. It will add to the result if there is another letter same as before right next to each other. Ex (... bb...) it will be B 1, B 2 like shown in my output. And for some reason when I use return it doesn't work. It returns nothing and just ends the program.
Second Code with KeyError:
I skipped the problem on top because I couldn't find the answer and didn't want to waste my time but ran into another problem lol*
for i in range(len(alphabet_list)):
for c in new_text:
if c == alphabet_list[i]:
count += 1
else:
count = 0
c_freq[alphabet_list[i]] == count
print(c_freq)
i += 1
This one was pretty simple I got a KeyError: 'A'.
I tried only doing the
i = 3 #just random number to test
count = 50
c_freq[alphabet_list[i]] == count
print(c_freq)
and it works, so I'm thinking that problem is also related to the problem above(? maybe). Anyways any help would be great. Thanks!
Sorry for long question but I really needed help.
This should help you:
lst = ['A', 'Z', 'H', 'A', 'B', 'N', 'H', 'Y', '.' , ',','Z'] #Initial list. Note: The list also includes characters such as commas and full stops.
alpha_dict = {}
for ch in lst:
if ch.isalpha(): #Checks if the character is an alphabet
if ch in alpha_dict.keys():
alpha_dict[ch] += 1 #If key already exists, value is incremented by 1
else:
alpha_dict[ch] = 1 #If key does not exist, a new key is created with value 1
print(alpha_dict)
Output:
{'A': 2, 'Z': 2, 'H': 2, 'B': 1, 'N': 1, 'Y': 1}
Since you want the output to be sorted in alphabetical order, add these lines to your code:
key_list = list(alpha_dict.keys()) #Creates a list of all the keys in the dict
key_list.sort() #Sorts the list in alphabetical order
final_dict = {}
for key in key_list:
final_dict[key] = alpha_dict[key]
print(final_dict)
Output:
{'A': 2, 'B': 1, 'H': 2, 'N': 1, 'Y': 1, 'Z': 2}
Thus, here is the final code:
lst = ['A', 'Z', 'H', 'A', 'B', 'N', 'H', 'Y', '.' , ',','Z']
alpha_dict = {}
for ch in lst:
if ch.isalpha():
if ch in alpha_dict.keys():
alpha_dict[ch] += 1
else:
alpha_dict[ch] = 1
key_list = list(alpha_dict.keys())
key_list.sort()
final_dict = {}
for key in key_list:
final_dict[key] = alpha_dict[key]
print(final_dict)
Output:
{'A': 2, 'B': 1, 'H': 2, 'N': 1, 'Y': 1, 'Z': 2}

Based on a condition perform reranking of elements in the list in python

i have a ranked list of elements as below :
ranked_list_1 = ['G','A','M','S','D']
i need to rerank the list as below
1) Re rank as :
re_ranked_list_1 = ['A','M','D','E','G','S']
Logic : 'G' and 'S' should always be in last 2 positions and new element 'E' should also be tagged to the list just before the last 2 position.
I think this is what you want. This will put 'G' and 'S' at the end, in the order they appear in the list.
ordered_list = list()
final_terms = ['E']
for item in ranked_list_1:
if item in ['G', 'S']:
final_terms.append(item)
else:
ordered_list.append(item)
output_list = ordered_list + final_terms
print(output_list)
>>>['A', 'M', 'D', 'E', 'G', 'S']

Python 3 - Dynamic Expression Evaluation

I am trying to figure out the syntax for evaluation an expression in Python that involves substituting a variable.
The code needs to go through a list of options, insert string input within the "{:(insert list item here)}"
Example Code (Python 3.x):
n = 11
print("my number is {:d}".format(n))
formatList = ['e', 'b', 'o', 'd', 'x', 'f', 's']
for atype in formatList:
# Failed Attempts:
# print("my number is {:eval(atype)}".format(n))
# print("my number is {:" + eval(atype) + "}".format(n))
# print(eval("my number is {:" + atype + "}").format(n))
# print(eval(' "my number is {:" + atype + "}".format(n)) '))
The output should resemble the number 11, in all the possible formats given by the list.
Thank you for everyones help!
You can achieve this by splitting in two passages:
n = 11
print("my number is {:d}".format(n))
formatList = ['e', 'b', 'o', 'd', 'x', 'f', 's']
for atype in formatList:
str_template = 'my number is {:' + atype + '}'
print(str_template.format(n))
If you really want one line, you can use this answer, to have a literal curly bracket in the string, by using double curly brackets '{{':
for atype in formatList:
print('my number is {{:{}}}'.format(atype).format(n))

Getting index of duplicate letters in a string

from graphics import *
import random
def hangman(word):
returnStuff = {'again':0, '1st':1}
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
win = GraphWin("Hangman", 800, 550)
win.setBackground("yellow")
titleText = Text(Point(400,50), 'HANGMAN')
titleText.setSize(24)
titleText.setStyle('bold')
titleText.draw(win)
#Building the hangman base
base = Line(Point(120,350),Point(230,350))
base.draw(win)
stand = Line(Point(175,350),Point(175,150))
stand.draw(win)
stand2 = Line(Point(175,150),Point(250,150))
stand2.draw(win)
stand3 = Line(Point(250,150),Point(250,180))
stand3.draw(win)
#drawing the empty lines for the word
x1 = 150
x2 = 180
l = 0
print(word)
while l< len(word):
wordLine = Line(Point(x1, 420),Point(x2,420))
wordLine.draw(win)
l+=1
x1+=40
x2+=40
guessCounter = 0
textCheck = 0
invalidText = Text(Point(600,100), 'You did not enter a valid letter.')
invalidText.setTextColor('red')
indexes = []
while guessCounter < 6:
#text entry box
textEntry = Entry(Point(600,180),10)
textEntry.draw(win)
guessText = Text(Point(600,150), 'Guess a letter:')
guessText.draw(win)
#user has to click this box to confirm the letter
enterBox = Rectangle(Point(580,200), Point(620,220))
enterBox.setFill('white')
enterBox.draw(win)
clickText = Text(Point(600,210), 'Enter')
clickText.draw(win)
click = win.getMouse()
x = click.getX()
y = click.getY()
if 580 < x < 620 and 200 < y < 220:
guess = textEntry.getText().lower().strip()
if guess not in alphabet:
if textCheck == 0:
invalidText.draw(win)
textCheck = 1
else:
if textCheck == 1:
invalidText.undraw()
textCheck = 0
for letter in word:
if letter == guess:
indexes.append(word.index(guess))
print(indexes)
win.getMouse()
win.close()
return returnStuff
#list with various words pertaining to nanotechnology
words = ['nanotechnology', 'science', 'nanometre' , 'strength', 'chemistry',
'small', 'molecule', 'light' , 'weight', 'technology', 'materials',
'property', 'physics', 'engineering', 'matter', 'waterloo', 'nanobot',
'reaction', 'structure', 'cells']
#picks a random word from the list
word = random.choice(words)
#this variable ensures it opens the game the first time
initialCall = 1
#stores the returnValue for the first call
returnValue = hangman(word)
#sets the initialCall to 0 after first call
if returnValue['1st']==1:
initialCall=0
#Calls the game function again if user wishes
while initialCall == 1 or returnStuff['again'] == 1:
returnValue = hangman(word)
I am making Hangman in Python graphics. I apologize for the huge block of code, it all works fine, I just thought it must be useful. The part of the code that I'm concerned about is this:
else:
if textCheck == 1:
invalidText.undraw()
textCheck = 0
for letter in word:
if letter == guess:
indexes.append(word.index(guess))
print(indexes)
This block of code will be executed when the user's letter guess is in the alphabet, I then run through each letter in the chosen word, and if at any point a letter in the word is the same as the guess letter, I store the index of that letter in a empty list so I can use that to tell the computer where to draw the letters on the empty lines.
It works fine, with the exception of when there is a duplicate letter in the word. For example, engineering has 3 es. Unfortunately, .index() only records the index for when the letter appears the first time, and it disregards the other letters. What is the work around for this so I can get the indexes of all 3 es in that word, instead of 3 indexes of just the first e. For testing purposes, I have printed the chosen word and the index list on the console so I can see what's going on and so I don't actually have to guess a letter.
you can do something like this
def indexes(word,letter):
for i,x in enumerate(word):
if x == letter:
yield i
test
>>> list( indexes("engineering","e") )
[0, 5, 6]
>>>
this function is a generator, that is a lazy function that only give result when asked for then, to get a individual result you use next, the functions is execute until the first yield then return the result and stop its execution and remember where it was, until another call to next is executed in witch point resume execution from the previous point until the next yield, if the is no more raise StopIteration, for example:
>>> word="engineering"
>>> index_e = indexes(word,"e")
>>> next(index_e)
0
>>> print(word)
engineering
>>> next(index_e)
5
>>> next(index_e)
6
>>> next(index_e)
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
next(index_e)
StopIteration
>>>
to update a list with the result of this function, you can use the extend method
>>> my_list=list()
>>> index_e = indexes(word,"e")
>>> my_list.extend( index_e )
>>> my_list
[0, 5, 6]
>>>
generator are used in cases where their result is only a intermediary step to something else because they use a minimum amount of memory, but in this case maybe you want the whole thing so use it as the first example or remake the function to return a list in the first place like this
def indexes(word,letter):
result = list()
for i,x in enumerate(word):
if x == letter:
result.append(i)
return result
sorry if I confuse you with the yield thing.

Resources