How to convert bar count to time, in midi? (music) - python

Given a midi file, how can one convert the bar count to time?
Generally, how can one easily map the bar count, in entire numbers, to the time in seconds in the song

Using pretty midi, my solution
import pretty_midi as pm
def get_bar_to_time_dict(self,song,id):
def get_numerator_for_sig_change(signature_change,id):
# since sometime pretty midi count are wierd
if int(signature_change.numerator)==6 and int(signature_change.denominator)==8:
# 6/8 goes to 2 for sure
return 2
return signature_change.numerator
# we have to take into account time-signature-changes
changes = song.time_signature_changes
beats = song.get_beats()
bar_to_time_dict = dict()
# first bar is on first position
current_beat_index = 0
current_bar = 1
bar_to_time_dict[current_bar] = beats[current_beat_index]
for index_time_sig, _ in enumerate(changes):
numerator = get_numerator_for_sig_change(changes[index_time_sig],id)
# keep adding to dictionary until the time signature changes, or we are in the last change, in that case iterate till end of beats
while index_time_sig == len(changes) - 1 or beats[current_beat_index] < changes[index_time_sig + 1].time:
# we have to increase in numerator steps, minus 1 for counting logic of natural counting
current_beat_index += numerator
if current_beat_index > len(beats) - 1:
# we labeled all beats so end function
return bar_to_time_dict
current_bar += 1
bar_to_time_dict[current_bar] = beats[current_beat_index]
return bar_to_time_dict
song = pm.PrettyMIDI('some_midi_file.midi')
get_bar_to_time_dict(song)
If anyone knows a function in pretty midi or music21 that solves the same issue please let me know, couldn't find one.
EDIT: There was also an issue with 6/8 beats, I think this covers all edge cases(not 100% sure)

Related

How do I fix infinite loop bugs in Python?

I have a problem regarding a competition question I'm attempting to do. Here is the question (its a bit long)
""""
Welcome aboard, Captain! Today you are in charge of the first ever doughnut-shaped spaceship, The
Circular. There are N cabins arranged in a circle on the spaceship. They are numbered from 1 to N in
a clockwise direction around the ship. The ith and the (i + 1)th cabins are connected. So too are cabin
1 and cabin N.
Currently the ith cabin has Ai crewmates, however the spaceship cannot depart unless there are exactly
Bi crewmates in this cabin.
To achieve this, you have the power to pay crewmates to change cabins. You can pay a crewmate $1 to
move to an adjacent cabin. A crewmate can be asked to move multiple times, provided that you pay
them $1 each time.
What is the fewest dollars you must pay before you can depart? It is always be possible to depart.
""""
https://orac2.info/problem/aio22spaceship/ (the link to the intereactive Qs)
I searched the web and i found no solutions to the Q. My code seems to be infinite looping i guess but im not sure as i cant see what cases the sit uses to determine if my code is right.
Heres my code
#!/usr/bin/env python
import sys
sys.setrecursionlimit(1000000000)
#
# Solution Template for Spaceship Shuffle
#
# Australian Informatics Olympiad 2022
#
# This file is provided to assist with reading and writing of the input
# files for the problem. You may modify this file however you wish, or
# you may choose not to use this file at all.
#
# N is the number of cabins.
N = None
# A contains the initial number of crewmates in each cabin. Note that here the
# cabins are numbered starting from 0.
A = []
# B contains the desired number of crewmates in each cabin. Note that here the
# cabins are numbered starting from 0.
B = []
answer = 0
# Open the input and output files.
input_file = open("spacein.txt", "r")
output_file = open("spaceout.txt", "w")
# Read the value of N.
N = int(input_file.readline().strip())
# Read the values of A and B.
input_line = input_file.readline().strip()
A = list(map(int, input_line.split()))
input_line = input_file.readline().strip()
B = list(map(int, input_line.split()))
AM = A
#AM is my modifying set
# TODO: This is where you should compute your solution. Store the fewest
# dollars you must pay before you can depart into the variable
while AM != B:
#Check if the set is correct
#notfound is a testing variable to see if my code was looping due to input error
notfound = True
for i in range(N):
#Check which places needs people to be moved
while AM[i]>B[i]:
notfound = False
#RV and LV check the "neediness" for each half's people requirements. I check how many people
#are needed on one side compared to the other and subtract the "overflow of people"
RV = 0
LV = 0
for j in range(int(N/2-0.5)):
#The range thing makes sure that if N is odd, im splitting the middle but if N is even, i leave out the end pod
RV += B[(i+j+1)%N]-AM[(i+j+1)%N]
LV += B[(i-j-1)%N]-AM[(i-j-1)%N]
answer +=1
if RV>LV:
AM[i]+=-1
AM[(i+1)%N]+=1
else:
AM[i]+=-1
AM[(i-1)%N]+=1
print(AM,B)
if notfound:
break
print(answer)
# Write the answer to the output file.
output_file.write("%d\n" % (answer))
# Finally, close the input/output files.
input_file.close()
output_file.close()
please help i really neeed to know the answer, driving me mad ngl
Welp, there aren't any resources online and I've tried everything. I think the problem might be that because of my solving method, passengers may be flicked between two pods indefinitely. Not sure since i could make a case that demoed this.
also my post probably is messy since this is my first time posting

Looping problem Elden ring runes per level calculation

This code is currently showing the total amount needed to reach the next level, but what I would like it to do is show the complete total amount so for example if you pick 50 the total amount needed from level 1 to 50. Looping through the calculation from 50 to 1 and only showing the sum of that total. and hereby I mean only showing the total amount of runes needed to reach level 50 for example, but I seem to get the entire list for each level. I, unfortunately, can't seem to find the right way to do this online, so I would try my luck here. any help is appreciated.
def total_runes_per_lvl(lvl):
list = []
for i in range(lvl):
runes = 0.02*(lvl)**3 + 3.06*(lvl)**2 + 105.6*(lvl) - 895
list.append(runes)
lvl -= 1
print(sum(list))
total_runes_per_lvl(50)
15102.68
14535.0
28514.440000000002
41950.32
54854.520000000004
67238.8
etc`
should only be one number: 277.571
Your identation is incorrect, and you're decrementing lvl even though there's already an iterator on it.
def total_runes_per_lvl(lvl):
total = 9381
for i in range(13,lvl+1):
runes = 0.02*(i+1)**3 + 3.06*(i+1)**2 + 105.6*(i+1) - 895
total += int(runes)
print(total)
total_runes_per_lvl(16) # 15605
total_runes_per_lvl(50) # 277574
Edit: since the formula works accurately after level 12, I've hardcoded the value for the total of first 12 levels. The formula works as expected, though it still isn't accurate.

How to set up this programm idea? : Elliott Wave Counter on Stock Charts by finding Minima and Maxima and how they relate to each other

My Idea is as follows and i want to really get to learn more about programming and how to structure a program:
I want to let count waves on a stock chart.
Within the Elliott Wave Rules are some specifications, like (most basic):
Wave 2 never retraces more than 100% of wave 1.
Wave 3 cannot be the shortest of the three impulse waves, namely waves 1, 3 and 5.
Wave 4 does not overlap with the price territory of wave 1, except in the
rare case of a diagonal triangle formation.
(from Wikipedia https://en.wikipedia.org/wiki/Elliott_wave_principle#Wave_rules_and_guidelines)
There are more sophisticated rules of course, but in my imagination, they could be addressed by the same iterative logic like in which I want to apply my rules.
Please guys, and girls, give me feedback on my thoughts if they make any sense in structure and layout to set up a program or not, because i lack experience here:
I want to find the minima and maxima, and give them a wavecount depending on the minima and maxima before.
Therefore i would check every candle (every closing price, day, hour, etc) if the value is below or above the previous value and also values. For example:
If there are two candles going up, then one down, then three up, then two down, then two up, this could be a complete Impulsewave, according to the above-listed rules. In total, i would have 10 candles and the following rules must apply:
The third candle (or the first that goes down, after the two going up) must not close below the starting price of the initial candle. AND also it must be met, that the following candles (how much that would become) must all go up in a row, unless they overcome the price of the previous maxima (the second candle).
When the price starts to drop again, it could be counted as wave 4 then (second minima in a sequence) and when it goes up again, this would indicate wave 5.
Then it also must be met, that, if the price starts to go down again, it does not close below the first maxima (in this case the second candle).
And so on and so on.
My question now is: Is this kind of looping through certain data points is even a appropriate way to approach that kind of project? Or am I totally wrong here?
I just thought: because of the fractal character of Elliott waves, I would only need very basic rules, that would depend on, what the same iterative process spits out the previous times it is scanning data points.
What do you think?
Is there a better, a smarter way to realise what i am planing to do?
And also, how I could do this in a good way?
Maybe there is also a way to just feed some patterns into a predefined execution structure and then let this run over data points just as price charts.
What would your approach look like?
Thanks a lot and best wishes, Benjamin
Here is my idea/code for finding highs and lows. It's doenst work standalone. If you have any idea, how it can help to find waves, let me know.
import pandas as pd
import config.Text
class AnalyzerHighLow(object):
def __init__(self, df):
self.high_low = None
self.df = df.close.values
self.highs = pd.DataFrame(columns=[config.Text.date, config.Text.extrema, config.Text.type])
self.lows = pd.DataFrame(columns=[config.Text.date, config.Text.extrema, config.Text.type])
def highlow(self):
idx_start = 0
self.find_high(self.df, idx_start)
self.find_low(self.df, idx_start)
self.high_low = pd.concat([self.highs, self.lows], ignore_index=True, sort=True, axis=0)
self.high_low = self.high_low.sort_values(by=[config.Text.date])
self.high_low = self.high_low.reset_index(drop=True)
return self.high_low
def find_high(self, high_low, idx_start):
pvt_high = high_low[idx_start]
reached = False
for i in range(idx_start + 1, len(high_low)):
act_high = high_low[i]
if act_high > pvt_high:
reached = True
pvt_high = act_high
elif act_high < pvt_high and reached is True:
self.highs.loc[i - 1] = [i - 1, pvt_high, config.Text.maxima]
return self.find_high(high_low, i)
elif act_high < pvt_high:
pvt_high = high_low[i]
if (reached is True) and (i == (len(high_low))):
self.highs.loc[i - 1] = [i - 1, pvt_high, config.Text.maxima]
def find_low(self, high_low, idx_start):
pvt_low = high_low[idx_start]
reached = False
for i in range(idx_start + 1, len(high_low)):
act_low = high_low[i]
if act_low < pvt_low:
reached = True
pvt_low = act_low
elif act_low > pvt_low and reached is True:
self.lows.loc[i - 1] = [i - 1, pvt_low, config.Text.minima]
return self.find_low(high_low, i)
elif act_low > pvt_low:
pvt_low = high_low[i]
if (reached is True) and (i == (len(high_low) - 1)):
self.lows.loc[i - 1] = [i - 1, pvt_low, config.Text.minima]

How to combine two programs into a single one?

I am trying to figure out how to find the average of how many seconds it takes for 1000 horses. I figured out how to find find the average of 1000 random integers and the time for one horse to finish. I do not understand how to implement them together.
EDIT: Any advice to make my code neater is fine!
EDIT 2: Sorry it probably wasn't clear. Part A was to find the average of 1000 random integers from ranges 10-20 which should be around 15. Part B is to see how many seconds it takes for one horse to finish a race which averages out to 450-500 something. Part C is supposed to simulate 1000 races but find also find the average. *
Here are my codes:
#Main Program
#This program will find the average of 1000 random numbers.
from random import randrange
def main():
numbers = []
for count in range(1000):
number = random.randrange(10,21)
numbers.append(number)
print('{} is the average of 1000 random numbers from the range 10 to 20.'.format(sum(numbers)/len(numbers)))
main()
#Part B
#This program will similate one horse race.
from random import randrange
def race():
goal = 10560 #2 miles is 10,560 feet
current_position = 0
elapsed_seconds = 0
while current_position <= goal:
elapsed_seconds += 1
current_position += randrange(4,41)
print('{} seconds for one horse to finish the race.'.format(elapsed_seconds))
race()
#Part C
#This program will find the average of 1000 horse races.
def races():
numbers = []
goal = 10560
current_position = 0
elapsed_seconds = 0
I'm not following your program completely, but I have a few thoughts.
One thing you probably need to do is imbed the race() module within races(), so that when you call races() is executes race(). To get the data sent back to the races() module, replace the print() function with a return function (keep and mind that return functions terminate loops), and put something like the following code into races():
race_value = race()
numbers.append(race_value)

Algorithm to return all possible paths in this program to a nested list

So I have a game with a function findViableMoves(base). If i call this function at the start with the parameter base, I get an output [move1, move2 ... moven] which denotes all of the n viable moves that the user can perform give the state base. (there are in fact 2 root moves)
Upon performing a move, say move2 - base gets changed depending on the move, the function gets called again and now we have an output for findViableMoves(base) of [move21,move22 .... move2n].
Depth-first-tree
If you look at this diagram, it's a very similar situation - there's no looping back, it's just a normal tree. I need a program that performs a depth-first search (i think?) on all the possible moves given a starting state of base, and then returns then in a list as such:
[[move1,move11,move111],[move1,move11,move112],....[moven,moven1,moven11],...]
There will be more elements in these lists (14 at most), but I was just wondering if someone could provide any hints over how I can build an algorithm to do this? Efficiency doesn't really matter to me as there isn't too many paths, I just want it done for now.
I'm not 100% clear on what you're after, but if you have a list or similar iterable that is changing while the loop is happening you could try something like the below.
This example allows the list and the loop condition to both remain dynamic during the loop execution.
import random
import sys
import time
changing_list = ['A', 27, 0.12]
def perform_operation(changing_list, counter):
sometimes_add_another_element_threshold = 0.6
if random.random() > sometimes_add_another_element_threshold:
changing_list.append(random.random())
print(changing_list[counter])
def main(z=0):
safety_limit = 100
counter = 0
condition = True
while condition and counter < safety_limit:
perform_operation(changing_list, counter)
counter += 1
condition = counter<len(changing_list)
print("loop finished")
if __name__ == '__main__':
start_time = time.time()
main(int(sys.argv[1])) if len(sys.argv)>1 else main()
print(time.time() - start_time)
which provides output of varying length that looks something like:
A
27
0.12
0.21045788812161237
0.20230442292518247
loop finished
0.0058634281158447266

Categories

Resources