Sound echo function Python - python

I need to write the function echo, that takes in a filename as and a floating-point value time_delay, which represents a number of seconds.Then, echo should handle the sound, with the original sound being overlaid by a copy of itself shifted forward in time by time_delay.
This is what I have so far:
def add_scale_2(L, M, L_scale, M_scale):
""" add_scale_2 has as intput list L and list M and rertuns a new list LC,
with a linear sum of the two lists times their scale respectively. LC will use the length of the
shortest list
"""
if len(L) >= len (M):
N = len(M)
else:
N = len(L)
LC = [L[i]*L_scale + M[i]*M_scale for i in range(N)]
return LC
And:
def echo(filename, time_delay):
print "Playing filename1 ..."
play(filename)
print "Reading in the sound data..."
samps1, sr = readwav(filename)
samps2 = [0]*float(samps1*time_delay) + samps1
print "Computing new sound..."
newsamps = add_scale_2(samps1, samps2, 0.5, 0.5)
newsr = sr # no change to the sr
writewav( newsamps, newsr, "out.wav" )
print "Playing new sound..."
play( 'out.wav' )
Can someone help me please because I can't figure it out!
samps2 = [0]*int(samps1*time_delay) + samps1
TypeError: can't multiply sequence by non-int of type 'float'

Your line:
[0]*float(samps1*time_delay) + samps1
tries to multiply a sequence [0] by a float. Which lead to error TypeError: can't multiply sequence by non-int of type 'float'
You can cast to an int instead:
[0]*int(len(samps1)*time_delay) + samps1

Related

Issue with turning tuple entry variables into an int for a math problem

currently I've been trying to have my tuple variables: tempLentry,windLentry,dewpointLentry, be converted into an integer so I can use them in the math sequence. However I keep getting this error whenever it happens: TypeError: int() argument must be a string, a bytes-like object or a real number, not 'Entry'. I was hoping someone could point in the right direction, Thank you!
The code is below
def calc ():
#Tuple being recieved from askUser
tempLentry,windLentry,dewpointLentry = askUser()
#Converts string input from entries to integers for the calculations to work.
t = int(tempLentry)
ws = int(windLentry)
dp = int(dewpointLentry)
#Checks to see if inputed data for temperature and windspeed is less than 50mph and
greater than 3 mph
if (t < 50 and ws > 3):
windchill = (35.74 + 0.6215 * t - (35.75 * math.pow(ws,0.16)) + (0.4275 * t * math.pow(ws,0.16)))
else:
windchill = 0
You need to first convert the Entry to a string, and then cast it to an int.
You can get the Entry as a string by using .get()
t = int(tempLentry.get())
ws = int(windLentry.get())
dp = int(dewpointLentry.get())

Python internal metric unit conversion function

I'm trying to build a function to do internal metric conversion on a wavelength to frequency conversion program and have been having a hard time getting it to behave properly. It is super slow and will not assign the correct labels to the output. If anyone can help with either a different method of computing this or a reason on why this is happening and any fixes that I cond do that would be amazing!
def convert_SI_l(n):
if n in range( int(1e-12),int(9e-11)):
return n/0.000000000001, 'pm'
else:
if n in range(int(1e-10),int(9e-8)):
return n/0.000000001 , 'nm'
else:
if n in range(int(1e-7),int(9e-5)):
return n/0.000001, 'um'
else:
if n in range(int(1e-4),int(9e-3)):
return n/0.001, 'mm'
else:
if n in range(int(0.01), int(0.99)):
return n/0.01, 'cm'
else:
if n in range(1,999):
return n/1000, 'm'
else:
if n in range(1000,299792459):
return n/1000, 'km'
else:
return n , 'm'
def convert_SI_f(n):
if n in range( 1,999):
return n, 'Hz'
else:
if n in range(1000,999999):
return n/1000 , 'kHz'
else:
if n in range(int(1e6),999999999):
return n/1e6, 'MHz'
else:
if n in range(int(1e9),int(1e13)):
return n/1e9, 'GHz'
else:
return n, 'Hz'
c=299792458
i=input("Are we starting with a frequency or a wavelength? ( F / L ): ")
#Error statements
if i.lower() == ("f"):
True
else:
if not i.lower() == ("l"):
print ("Error invalid input")
#Cases
if i.lower() == ("f"):
f = float(input("Please input frequency (in Hz): "))
size_l = c/f
print(convert_SI_l(size_l))
if i.lower() == ("l"):
l = float(input("Please input wavelength (in meters): "))
size_f = ( l/c)
print(convert_SI_f(size_f))
You are using range() in a way that is close to how it is used in natural language, to express a contiguous segment of the real number line, as in in the range 4.5 to 5.25. But range() doesn't mean that in Python. It means a bunch of integers. So your floating-point values, even if they are in the range you specify, will not occur in the bunch of integers that the range() function generates.
Your first test is
if n in range( int(1e-12),int(9e-11)):
and I am guessing you wrote it like this because what you actually wanted was range(1e-12, 9e-11) but you got TypeError: 'float' object cannot be interpreted as an integer.
But if you do this at the interpreter prompt
>>> range(int(1e-12),int(9e-11))
range(0, 0)
>>> list(range(int(1e-12),int(9e-11)))
[]
you will see it means something quite different to what you obviously expect.
To test if a floating-point number falls in a given range do
if lower-bound <= mynumber <= upper-bound:
You don't need ranges and your logic will be more robust if you base it on fixed threshold points that delimit the unit magnitude. This would typically be a unit of one in the given scale.
Here's a generalized approach to all unit scale determination:
SI_Length = [ (1/1000000000000,"pm"),
(1/1000000000, "nm"),
(1/1000000, "um"),
(1/1000, "mm"),
(1/100, "cm"),
(1, "m"),
(1000, "km") ]
SI_Frequency = [ (1, "Hz"), (1000,"kHz"), (1000000,"MHz"), (1000000000,"GHz")]
def convert(n,units):
useFactor,useName = units[0]
for factor,name in units:
if n >= factor : useFactor,useName = factor,name
return (n/useFactor,useName)
print(convert(0.0035,SI_Length)) # 3.5 mm
print(convert(12332.55,SI_Frequency)) # 12.33255 kHz
Each unit array must be in order of smallest to largest multiplier.
EDIT: Actually, range is a function which is generally used in itaration to generate numbers. So, when you write if n in range(min_value, max_value), this function generates all integers until it finds a match or reach the max_value.
The range type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in for loops.
Instead of writing:
if n in range(int(1e-10),int(9e-8)):
return n/0.000000001 , 'nm'
you should write:
if 1e-10 <= n < 9e-8:
return n/0.000000001 , 'nm'
Also keep in mind that range only works on integers, not float.
More EDIT:
For your specific use case, you can define dictionary of *(value, symbol) pairs, like below:
import collections
symbols = collections.OrderedDict(
[(1e-12, u'p'),
(1e-9, u'n'),
(1e-6, u'μ'),
(1e-3, u'm'),
(1e-2, u'c'),
(1e-1, u'd'),
(1e0, u''),
(1e1, u'da'),
(1e2, u'h'),
(1e3, u'k'),
(1e6, u'M'),
(1e9, u'G'),
(1e12, u'T')])
The use the bisect.bisect function to find the "insertion" point of your value in that ordered collection. This insertion point can be used to get the simplified value and the SI symbol to use.
For instance:
import bisect
def convert_to_si(value):
if value < 0:
value, symbol = convert_to_si(-value)
return -value, symbol
elif value > 0:
orders = list(symbols.keys())
order_index = bisect.bisect(orders, value / 10.0)
order = orders[min(order_index, len(orders) - 1)]
return value / order, symbols[order]
else:
return value, u""
Demonstration:
for value in [1e-12, 3.14e-11, 0, 2, 20, 3e+9]:
print(*convert_to_si(value), sep="")
You get:
1.0p
0.0314n
0
2.0
2.0da
3.0G
You can adapt this function to your needs…

Error when passing list of float values to function

Unsupported operand type(s) for -: 'str' and 'str'
I am passing two lists to a functions to find the starting distance,ending distance ,starting time, ending time using sesnor data. when the list contains only integer values, it doesn't throw any error and works fine but when i tried to convert the list to floating value , its showing an error
x = ["%.2f"%(b*1000) for b in t] # t is a list of time values
y = [c*0.002 for c in values]# values is a list of sensor values
z = ["%.2f"%(d*48.484) for d in y]
p1,t1 = min_distance(z,x)
p2,t2 = max_distance(z,x)
def min_distance(self,z,x):
count = True
i = 0
while count and (i+1) !=len(z):
if abs(z[i] - z[i+1]) >= 1:
count = False
else:
i +=1
min_value = z[i])
min_time = x[i])
return min_value,min_time
def max_distance(self,z,x):
count = 0
j = 1
while count<20:
if abs(z[-j] - z[-j-1]) >=1:
count +=1
else:
j +=1
max_value = z[-j+20]
max_time = x[-j+20]
return max_value,max_time
x, y and z are arrays of strings, not integers or floats. You are creating them using string substitution, which inserts and formats a float value but results in a string.
To ensure you get a float, ensure either that b and c are floats, or force the integer to a float by adding a decimal point. For example, if b is an integer, b*1000 will result in an integer, but b*1000.0 or float(b*1000) will give a float
Try, for example: x = [b*1000 for b in t] and so on then format any resulting string (like you had done) only when you need output visible to the user.

Rounding to 2 decimal places in Python

This isn't a duplicate because I have checked everything before this post on this site. I think I have managed to do the first two bullet points. The first one I will do through a string but I am willing to change that if you know another way. The 2nd one is using comma seperators for the $'s. So I will use a float but once again am willing to change if better way is found.
But I am stuck.
And the "print("%.2f") % str) is something I found but I need work on rounding to two decimal spaces and the last bullet point.
Code:
import random
def random_number():
random_dollars = random.uniform(1.00, 10000.00)
print(round(random_dollars, 2))
print("%.2f") % str
print(random_number())
Shell:
C:\Users\jacke\PycharmProjects\ASLevelHomeworkWeek18\venv\Scripts\python.exe C:/Users/jacke/PycharmProjects/ASLevelHomeworkWeek18/ASLevelHomeworkWeek18.py 6567.62 Traceback (most recent call last): %.2f File
C:/Users/jacke/PycharmProjects/ASLevelHomeworkWeek18/ASLevelHomeworkWeek18.py", line 10, in <module> print(random_number()) File
C:/Users/jacke/PycharmProjects/ASLevelHomeworkWeek18/ASLevelHomeworkWeek18.py", line 7, in random_number print("%.2f") % str TypeError: unsupported operand type(s) for %: 'NoneType' and 'type' Process finished with exit code 1
You can format currency like this:
def random_number():
random_dollars = random.uniform(1, 10000)
result = '$ {:0>9}'.format('{:,.2f}'.format(random_dollars))
print(result)
{:0>10} means: pad string left to width 9 with 0's.
{:,.2f} rounds to two decimal places (.2f) and adds a comma as thousands-separator.
Just one side note: by using random.uniform(1, 10000) most of your numbers will be large (>1000), if you want to test your script with small amounts you could use random_dollars = 10**random.uniform(0, 4) instead:
def random_number():
random_dollars = 10**random.uniform(0, 4)
result = '$ {:0>9}'.format('{:,.2f}'.format(random_dollars))
print(result)
If I get what you are saying you want to round a number to 2 decimal places. Here is how I would do it.
import random
def random_number():
random_dollars = random.uniform(1, 10000)
split = str(random_dollars).split(".")
if (len(split) == 2 ):
if (len(split[1]) == 1 ):# checks if 1 digit after decimal place
answer = split[0] + ".0"
split[1] = str(int(int(split[1]) / (10 ** (len(split[1]) - 3) )))
# Gets 3 decimal places
if int(split[1][-1:]) => 5: #Checks if last digit is above or equal to 5
split[1] = int(split[1][:-1])
split[1] += 1
else:
split[1] = int(split[1][:-1])
answer = split[0] + '.' + str(split[1])
else:
answer = split[0] + ".00"
print(answer)
random_number()
This makes it so if the random number is somehow 100 it will add 2 zeros. If the number is like 100.1 it will add one zero. It will also round it.
def random_number():
random_dollars = random.uniform (1.00, 10000.00)
n = round(random_dollars,2)
bd, d = str(n).split('.')
if len(d) == 1:
n = bd + "." + d + '0'
return n
else:
return n
for i in range(1, 20):
print(random_number())
7340.55
7482.70
3956.81
3044.50
4108.57
4864.90
235.00
9831.98
960.97
1172.28
5221.31
3663.50
5410.50
3448.52
8288.13
293.48
1390.68
9216.15
6493.65
TL;DR: you have to put the % directly after the string and you have to put a real variable there, not the type str
from the last line of your error message you can see that the problem is the % operator. You can also see that it tried to do the operation with two objects of types 'NoneType' and 'type'. Since you put the entire print statement in front of the % and print returns None (which is of type NoneType), the first operand is of type NoneType. then, the second operand is the type str, which is, as just said, a type. You can fix this by moving the % operator after the string and replacing str with your variable random_dollars since that is what you want to insert into the string.
import random
def random_number():
random_dollars = random.uniform(1.00, 10000.00)
print(round(random_dollars, 2))
# this:
print("%.2f" % random_dollars)
print(random_number())

Find length of a string that includes its own length?

I want to get the length of a string including a part of the string that represents its own length without padding or using structs or anything like that that forces fixed lengths.
So for example I want to be able to take this string as input:
"A string|"
And return this:
"A string|11"
On the basis of the OP tolerating such an approach (and to provide an implementation technique for the eventual python answer), here's a solution in Java.
final String s = "A String|";
int n = s.length(); // `length()` returns the length of the string.
String t; // the result
do {
t = s + n; // append the stringified n to the original string
if (n == t.length()){
return t; // string length no longer changing; we're good.
}
n = t.length(); // n must hold the total length
} while (true); // round again
The problem of, course, is that in appending n, the string length changes. But luckily, the length only ever increases or stays the same. So it will converge very quickly: due to the logarithmic nature of the length of n. In this particular case, the attempted values of n are 9, 10, and 11. And that's a pernicious case.
A simple solution is :
def addlength(string):
n1=len(string)
n2=len(str(n1))+n1
n2 += len(str(n2))-len(str(n1)) # a carry can arise
return string+str(n2)
Since a possible carry will increase the length by at most one unit.
Examples :
In [2]: addlength('a'*8)
Out[2]: 'aaaaaaaa9'
In [3]: addlength('a'*9)
Out[3]: 'aaaaaaaaa11'
In [4]: addlength('a'*99)
Out[4]: 'aaaaa...aaa102'
In [5]: addlength('a'*999)
Out[5]: 'aaaa...aaa1003'
Here is a simple python port of Bathsheba's answer :
def str_len(s):
n = len(s)
t = ''
while True:
t = s + str(n)
if n == len(t):
return t
n = len(t)
This is a much more clever and simple way than anything I was thinking of trying!
Suppose you had s = 'abcdefgh|, On the first pass through, t = 'abcdefgh|9
Since n != len(t) ( which is now 10 ) it goes through again : t = 'abcdefgh|' + str(n) and str(n)='10' so you have abcdefgh|10 which is still not quite right! Now n=len(t) which is finally n=11 you get it right then. Pretty clever solution!
It is a tricky one, but I think I've figured it out.
Done in a hurry in Python 2.7, please fully test - this should handle strings up to 998 characters:
import sys
orig = sys.argv[1]
origLen = len(orig)
if (origLen >= 98):
extra = str(origLen + 3)
elif (origLen >= 8):
extra = str(origLen + 2)
else:
extra = str(origLen + 1)
final = orig + extra
print final
Results of very brief testing
C:\Users\PH\Desktop>python test.py "tiny|"
tiny|6
C:\Users\PH\Desktop>python test.py "myString|"
myString|11
C:\Users\PH\Desktop>python test.py "myStringWith98Characters.........................................................................|"
myStringWith98Characters.........................................................................|101
Just find the length of the string. Then iterate through each value of the number of digits the length of the resulting string can possibly have. While iterating, check if the sum of the number of digits to be appended and the initial string length is equal to the length of the resulting string.
def get_length(s):
s = s + "|"
result = ""
len_s = len(s)
i = 1
while True:
candidate = len_s + i
if len(str(candidate)) == i:
result = s + str(len_s + i)
break
i += 1
This code gives the result.
I used a few var, but at the end it shows the output you want:
def len_s(s):
s = s + '|'
b = len(s)
z = s + str(b)
length = len(z)
new_s = s + str(length)
new_len = len(new_s)
return s + str(new_len)
s = "A string"
print len_s(s)
Here's a direct equation for this (so it's not necessary to construct the string). If s is the string, then the length of the string including the length of the appended length will be:
L1 = len(s) + 1 + int(log10(len(s) + 1 + int(log10(len(s)))))
The idea here is that a direct calculation is only problematic when the appended length will push the length past a power of ten; that is, at 9, 98, 99, 997, 998, 999, 9996, etc. To work this through, 1 + int(log10(len(s))) is the number of digits in the length of s. If we add that to len(s), then 9->10, 98->100, 99->101, etc, but still 8->9, 97->99, etc, so we can push past the power of ten exactly as needed. That is, adding this produces a number with the correct number of digits after the addition. Then do the log again to find the length of that number and that's the answer.
To test this:
from math import log10
def find_length(s):
L1 = len(s) + 1 + int(log10(len(s) + 1 + int(log10(len(s)))))
return L1
# test, just looking at lengths around 10**n
for i in range(9):
for j in range(30):
L = abs(10**i - j + 10) + 1
s = "a"*L
x0 = find_length(s)
new0 = s+`x0`
if len(new0)!=x0:
print "error", len(s), x0, log10(len(s)), log10(x0)

Categories