how to accept filename from user and save the sound file in python - python-3.x

i am trying to record sound from pyaudio in python and making a gui for the same.
my code run fine when i use datetime library and give the filename eg.sound_2020_21_04_03_40.wav which is current date,time but when i try to take the filename from user with tkinter (from tkinter.filedialog import asksaveasfile) it is saving the sound file but its empty with 0 bytes.
can any on e help me in this. this is my coding part of stop button which terminate the code and save the file.
import tkinter as tk
import threading
import pyaudio
import wave
from tkinter import *
import tkinter.font as font
from tkinter.filedialog import asksaveasfile
class App():
chunk = 1024
sample_format = pyaudio.paInt16
channels = 2
fs = 44100
frames = []
def __init__(self, master):
self.isrecording = False
myFont = font.Font(weight="bold")
self.button1 = tk.Button(main, text='Record',command=self.startrecording,height=2,width=20,bg='#0052cc', fg='#ffffff')
self.button2 = tk.Button(main, text='stop',command=self.stoprecording,height=2,width=20,bg='#0052cc', fg='#ffffff')
self.button1['font'] = myFont
self.button2['font'] = myFont
self.button1.place(x=30, y=30)
self.button2.place(x=280, y=30)
def startrecording(self):
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=self.sample_format,channels=self.channels,rate=self.fs,frames_per_buffer=self.chunk,input=True)
self.isrecording = True
print('Recording')
t = threading.Thread(target=self.record)
t.start()
def stoprecording(self):
self.isrecording = False
print('recording complete')
self.filename = asksaveasfile(initialdir = "/",title = "Save as",mode='w',filetypes = (("audio file","*.wav"),("all files","*.*")),defaultextension=".wav")
wf = wave.open(self.filename, 'wb')
wf.setnchannels(self.channels)
wf.setsampwidth(self.p.get_sample_size(self.sample_format))
wf.setframerate(self.fs)
wf.writeframes(b''.join(self.frames))
wf.close()
main.destroy()
def record(self):
while self.isrecording:
data = self.stream.read(self.chunk)
self.frames.append(data)
main = tk.Tk()
main.title('recorder')
main.geometry('520x120')
app = App(main)
main.mainloop()
image is here

It's strange that no exceptions were risen, because when you call askopenfile(...) it returns a file object (and opens an empty file for reading - that file you have seen), but wave.open(...) expects a filename. To get it, you need to use askopenfilename(...) instead of askopenfile(...). And don't forget to import askopenfilename in the top of your code.
Here is the full code (I have refactored it according to PEP8):
import tkinter as tk
import threading
import pyaudio
import wave
from tkinter import *
import tkinter.font as font
from tkinter.filedialog import asksaveasfilename
class App():
chunk = 1024
sample_format = pyaudio.paInt16
channels = 2
fs = 44100
frames = []
def __init__(self, master):
self.isrecording = False
myFont = font.Font(weight="bold")
self.button1 = tk.Button(main, text='Record', command=self.startrecording,
height=2, width=20, bg='#0052cc', fg='#ffffff')
self.button2 = tk.Button(main, text='stop', command=self.stoprecording,
height=2, width=20, bg='#0052cc', fg='#ffffff')
self.button1['font'] = myFont
self.button2['font'] = myFont
self.button1.place(x=30, y=30)
self.button2.place(x=280, y=30)
def startrecording(self):
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=self.sample_format, channels=self.channels,
rate=self.fs, frames_per_buffer=self.chunk, input=True)
self.isrecording = True
print('Recording')
t = threading.Thread(target=self.record)
t.start()
def stoprecording(self):
self.isrecording = False
print('recording complete')
self.filename = asksaveasfilename(initialdir="/", title="Save as",
filetypes=(("audio file", "*.wav"), ("all files", "*.*")),
defaultextension=".wav")
wf = wave.open(self.filename, 'wb')
wf.setnchannels(self.channels)
wf.setsampwidth(self.p.get_sample_size(self.sample_format))
wf.setframerate(self.fs)
wf.writeframes(b''.join(self.frames))
wf.close()
main.destroy()
def record(self):
while self.isrecording:
data = self.stream.read(self.chunk)
self.frames.append(data)
print("does it")
main = tk.Tk()
main.title('recorder')
main.geometry('520x120')
app = App(main)
main.mainloop()

Related

why the recording file is empty in python

I am trying to record my desktop screen and record the audio from microphone simentensously with the help of this python script.
Now when i run only the screen capture part the code works perfectly fine but when i try to run both sound recording and screen capture combine code as shown in below code. my video and audio both file does not open. (0 bytes) or very less size file.
How can i solve this problem.
updated Code
now i am able to record voice properly but the video file is not opening?
import datetime
import tkinter as tk
from tkinter import *
from tkinter import ttk ,FLAT
from PIL import Image, ImageTk, ImageGrab
import cv2
import numpy as np
import threading
import win32api
import pyaudio
import wave
VIDEO_SIZE = (800 , 420) #(960, 540)
p = ImageGrab.grab()
a, b = p.size
chunk = 1024
sample_format = pyaudio.paInt16
channels = 2
fs = 44100
frames = []
g = pyaudio.PyAudio()
date = datetime.datetime.now()
filename='rec_%s-%s-%s-%s-%s-%s.mp4' % (date.year, date.month, date.day,date.hour, date.minute, date.second)
#fourcc = cv2.VideoWriter_fourcc(*'XVID')
frame_rate = 24
cap = cv2.VideoCapture(0)
out = cv2.VideoWriter()
def screen_capturing():
global capturing
capturing = True
while capturing:
img = ImageGrab.grab()
frame = np.array(img)
sc = np.array(img)
_xs,_ys = win32api.GetCursorPos()
cv2.circle(frame,(_xs,_ys),20,(255,255,0), 2)
sc = cv2.resize(sc, VIDEO_SIZE)
tkimage.paste(Image.fromarray(sc))
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
out.write(frame)
def start_screen_capturing():
if not out.isOpened():
out.open(filename, 0x31637661, frame_rate,(VIDEO_SIZE))
t1=threading.Thread(target=screen_capturing, daemon=True)
t1.start()
def stop_screen_capturing():
global capturing
capturing = False
out.release()
def voice_recording():
global recording
while recording:
data = stream.read(chunk)
frames.append(data)
def start_voice_recording():
global stream
stream = g.open(format=sample_format,channels=channels,rate=fs,frames_per_buffer=chunk,input=True)
global recording
recording = True
print('capturing')
t2 = threading.Thread(target=voice_recording) # daemon=True
t2.start()
def stop_voice_recording():
#global recording
recording =False
print(' complete')
filename='test'
filename = filename+".wav"
wf = wave.open(filename,'wb')
wf.setnchannels(channels)
wf.setsampwidth(g.get_sample_size(sample_format))
wf.setframerate(fs)
wf.writeframes(b''.join(frames))
wf.close()
root = tk.Tk()
root.title('Screen Recorder')
root.geometry('+260+70')
tkimage = ImageTk.PhotoImage(Image.new('RGB', VIDEO_SIZE, (0,0,0)))
w, h = VIDEO_SIZE
vbox = tk.Label(root, image=tkimage, width=w, height=h, bg='black')
vbox.pack(pady=10,padx=25)
frame = tk.Frame(root)
frame.pack()
start_cap = tk.Button(frame, text='Start screen Recording', width=30, command=start_screen_capturing)
start_cap.grid(row=0, column=0)
stop_cap = tk.Button(frame, text='Stop screen Recording', width=30, command=stop_screen_capturing)
stop_cap.grid(row=0, column=1)
start_voice = tk.Button(frame, text='Start voice Recording', width=30, command=start_voice_recording)
start_voice.grid(row=0, column=2)
stop_voice = tk.Button(frame, text='Stop voice Recording', width=30, command=stop_voice_recording)
stop_voice.grid(row=0, column=3)
root.mainloop()

How to show multiple pictures in tkinter with function?

I want to show many pictures in my gui application. But according to Here I need to save those pictures as reference to my class. but I am confused how should I do it with many pictures?
This does not show any image on the opened Window
from tkinter import *
import tkinter
import os
from PIL import Image, ImageTk
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
class GUI():
def __init__(self,file_list):
self.file_list = file_list
self.root=Tk()
self.canvas = Canvas(self.root, width=480, height=800)
self.canvas.pack()
def image_opener(self, filename):
opened_image = Image.open(CURRENT_DIR + "images/gui/" + filename)
photo_image = ImageTk.PhotoImage(opened_image)
return photo_image
def show_image1(self):
img = self.image_opener(files["img1"])
self.canvas.create_image(0, 0, image=img, anchor = NW, state = NORMAL)
def show_image2(self):
img = self.image_opener(files["img2"])
self.canvas.create_image(0, 0, image=img, anchor = NW, state = NORMAL)
def show_screens(self):
self.show_image1()
self.show_image2()
self.root.mainloop()
files = {
"img1":"image1.png",
"img2":"image2.png",
"img3":"image3.png",
"img4":"image4.png"
}
gui = GUI(files)
gui.show_screens()
When I change it to this it shows pictures in the window but is there any elegant way to do it with many pictures (maybe around 75) ?
from tkinter import *
import tkinter
import os
from PIL import Image, ImageTk
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) + "/"
class GUI():
def __init__(self,file_list):
self.file_list = file_list
self.root=Tk()
self.canvas = Canvas(self.root, width=480, height=800)
self.canvas.pack()
self.opened_image1 = Image.open(CURRENT_DIR + "images/gui/image1")
self.photo_image1 = ImageTk.PhotoImage(self.opened_image1)
self.opened_image2 = Image.open(CURRENT_DIR + "images/gui/image2")
self.photo_image2 = ImageTk.PhotoImage(self.opened_image2)
def show_image1(self):
self.canvas.create_image(0, 0, image=self.photo_image1, anchor = NW, state = NORMAL)
def show_image2(self):
self.canvas.create_image(0, 0, image=self.photo_image2, anchor = NW, state = NORMAL)
def show_screens(self):
self.show_image1()
self.show_image2()
self.root.mainloop()
files = {
"img1":"image1.png",
"img2":"image2.png",
"img3":"image3.png",
"img4":"image4.png"
}
gui = GUI(files)
gui.show_screens()

how to break looping in tkinter?

this is my code.
from PyPDF2 import PdfFileReader
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
root = tk.Tk()
label_list = []
def get_info(path):
with open(path, 'rb') as f:
pdf = PdfFileReader(f)
info = pdf.getDocumentInfo()
page = pdf.getPage(4)
label_list[0].config(text = "Title")
label_list[1].config(text = info.title)
label_list[2].config(text = "Author")
label_list[3].config(text = info.author)
label_list[4].config(text = "Subject")
label_list[5].config(text = info.subject)
label_list[6].config(text = "Abstract")
label_list[7].config(text = page.extractText())
save = tk.Button(root, text="Save")
save.pack()
def browsefunc():
filename = filedialog.askopenfilename()
pathlabel.config(text=filename)
get_info(filename)
browsebutton = tk.Button(root, text="Choose a File", command=browsefunc)
browsebutton.pack()
pathlabel = tk.Label(root)
pathlabel.pack()
for i in range(8):
label_list.append(tk.Label(root, text=""))
label_list[i].pack()
root.mainloop()
i added button save which the button will show when i choose the file, and when i choose a new file, i got 2 save buttons and more.
how can i break the data, and when i choose a new file i only have 1 button?
Here is one way you can get the button to show when you need it and then get rid of it when you don't.
We can have a tracking variable to see if we currently have a button open and when we use the button we can get rid of the button as part of the function. So create when we need it and destroy when its done.
from PyPDF2 import PdfFileReader
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
root = tk.Tk()
label_list = []
track_save_button = False
def save_func():
global track_save_button, save
# your code for saving data here
save.destroy()
track_save_button = False
def get_info(path):
global track_save_button, save
if track_save_button == False:
save = tk.Button(root, text="Save", command=save_func)
save.pack()
track_save_button = True
with open(path, 'rb') as f:
pdf = PdfFileReader(f)
info = pdf.getDocumentInfo()
page = pdf.getPage(4)
label_list[0].config(text = "Title")
label_list[1].config(text = info.title)
label_list[2].config(text = "Author")
label_list[3].config(text = info.author)
label_list[4].config(text = "Subject")
label_list[5].config(text = info.subject)
label_list[6].config(text = "Abstract")
label_list[7].config(text = page.extractText())
else:
print("Save Button is already active!")
def browsefunc():
filename = filedialog.askopenfilename()
pathlabel.config(text=filename)
get_info(filename)
browsebutton = tk.Button(root, text="Choose a File", command=browsefunc)
browsebutton.pack()
pathlabel = tk.Label(root)
pathlabel.pack()
for i in range(8):
label_list.append(tk.Label(root, text=""))
label_list[i].pack()
root.mainloop()

How can i get data from file path using tkinter and PdFileReader

I use this method :
from PyPDF2 import PdfFileReader
from tkinter import *
from tkinter import filedialog
import os
root = Tk()
def browsefunc():
filename = filedialog.askopenfilename()
pathlabel.config(text=filename)
browsebutton = Button(root, text="Browse", command=browsefunc)
browsebutton.pack()
pathlabel = Label(root)
pathlabel.pack()
def get_info(path):
with open(path, 'rb') as f:
pdf = PdfFileReader(f)
info = pdf.getDocumentInfo()
number_of_pages = pdf.getNumPages()
print(info)
author = info.author
creator = info.creator
producer = info.producer
subject = info.subject
title = info.title
if __name__ == '__main__':
path = pathlabel.pack()
get_info(path)
mainloop()
However, i get the following error:
TypeError: invalid file: None
How can i get the file from pathlabel?
Is it possible to open the file from file path?
I see a couple problems here.
Delete this:
if __name__ == '__main__':
path = pathlabel.pack()
get_info(path)
what this is doing is making path = to the result of pathlabel.pack(). That result will always be None as pack() is always going to return None. Then you are passing None to the get_info() function.
Instead lets call get_info from your brousefunc() functions.
Change brousefunc() to this:
def browsefunc():
filename = filedialog.askopenfilename()
pathlabel.config(text=filename)
get_info(filename)
This will update your label and then also send the correct file path to the get_info function.
If you still wish to use the label's text for the file path you can do path = pathlabel["text"] as this will assign the value of the text to the path.
I can't test PyPDF2 on my end but the below should work for you.
from PyPDF2 import PdfFileReader
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
def get_info(path):
with open(path, 'rb') as f:
pdf = PdfFileReader(f)
info = pdf.getDocumentInfo()
number_of_pages = pdf.getNumPages()
author = info.author
creator = info.creator
producer = info.producer
subject = info.subject
title = info.title
print(number_of_pages, author, creator, producer, subject, title)
def browsefunc():
filename = filedialog.askopenfilename()
pathlabel.config(text=filename)
get_info(filename)
browsebutton = tk.Button(root, text="Browse", command=browsefunc)
browsebutton.pack()
pathlabel = tk.Label(root)
pathlabel.pack()
root.mainloop()
To address your question in the comments here is an example that displays in the GUI.
from PyPDF2 import PdfFileReader
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
label_list = []
def get_info(path):
with open(path, 'rb') as f:
pdf = PdfFileReader(f)
info = pdf.getDocumentInfo()
label_list[0].config(text=pdf.getNumPages())
label_list[1].config(text=info.author)
label_list[2].config(text=info.creator)
label_list[3].config(text=info.producer)
label_list[4].config(text=info.subject)
label_list[5].config(text=info.title)
def browsefunc():
filename = filedialog.askopenfilename()
pathlabel.config(text=filename)
get_info(filename)
browsebutton = tk.Button(root, text="Browse", command=browsefunc)
browsebutton.pack()
pathlabel = tk.Label(root)
pathlabel.pack()
for i in range(6):
label_list.append(tk.Label(root, text=""))
label_list[i].pack()
root.mainloop()

Using Tkinter and suprocess.call

I would like to use tkinter to open a window that will allow a user to select two separate files that will be manipulated several times within my script. I am having trouble finding a way to set the file that will be selected using the button in my tkinter window as a variable so that it can be used within subprocess.call. I have found invoke() but it doesn't seem to have any affect. Any ideas on what I might do would be greatly appreciated.
import os
import sys
import gdal
from gdalconst import *
import numpy as np
import math
import subprocess
from subprocess import call
import math
import datetime
import shutil
import tkinter
from tkinter import *
from tkinter import filedialog
newpath = os.path.expanduser('~\\Desktop\\Components\\Float32')
if not os.path.exists(newpath):
os.makedirs(newpath)
newpath_2 = os.path.expanduser('~\\Desktop\\Components\\Zeros')
if not os.path.exists(newpath_2):
os.makedirs(newpath_2)
newpath_3 = os.path.expanduser('~\\Desktop\\Components\\db_Files')
if not os.path.exists(newpath_3):
os.makedirs(newpath_3)
if __name__== '__main__':
# Set all of the necessary constants so that the script can create and save the pertinent files
# on the users desktop
#tk1 = Tk()
#tk2 = Tk()
#callTK = 'src_dataset =' + tk1
#callTK_2 = 'srcVH =' + tk2
gdalTranslate = 'C:\Program Files (x86)\GDAL\gdal_translate.exe'
tk1.fileName = filedialog.askopenfilename(text="Open HV File")
tk2.fileName = filedialog.askopenfilename(text="Open VH File")
dst_dataset = os.path.expanduser('~\\Desktop\\Components\\Float32\\newHV32.img')
dstVH = os.path.expanduser('~\\Desktop\\Components\\Float32\\newVH32.img')
sttime = datetime.datetime.now().strftime('(Time_Run = %Y-%d-%m_%H:%M:%S)')
wheel_install_1 = os.path.expanduser('~\\Desktop\\Components\\Sigma_Test\\wheel_install.py')
wheel_install_2 = os.path.expanduser('~\\Desktop\\Components\\Sigma_Test\\wheel_install2.py')
ridofz = os.path.expanduser('~\\Desktop\\Components\\Sigma_Test\\ridofZsv2.py')
to_dB = os.path.expanduser('~\\Desktop\\Components\\Sigma_Test\\to_dBv2.py')
db_HV = os.path.expanduser('~\\Desktop\\Components\\dB_Files\\newHVdB.img')
db_VH = os.path.expanduser('~\\Desktop\\Components\\dB_Files\\newVHdB.img')
cmd = "-ot float32 -of HFA" # hopefully this works
# Install necessary packages, which are GDAL and Numpy
# try:
#os.system(wheel_install_1)
#print ("GDAL intalled")
#os.system(wheel_install_2)
#print ("Numpy installed")
#except:
#print ("The packages are't installing properly")
#sys.exit()
# Create three new folders which will house the files that will be created
# along each sequential step of the script
#newpath = os.path.expanduser('~\\Desktop\\Components\\Float32')
#if not os.path.exists(newpath):
#os.makedirs(newpath)
#newpath_2 = os.path.expanduser('~\\Desktop\\Components\\Zeros')
#if not os.path.exists(newpath_2):
#os.makedirs(newpath_2)
#newpath_3 = os.path.expanduser('~\\Desktop\\Components\\db_Files')
#if not os.path.exists(newpath_3):
#os.makedirs(newpath_3)
root = Tk()
#root.fileName = filedialog.askopenfilename()
root.title("Utilis Sigma Test")
root.iconbitmap(r"C:\Users\jack.UTILIS\Desktop\images\sigma.ico")
root.configure(background="#179EBB")
topFrame = Frame(root)
topFrame.pack()
photo = PhotoImage(file="C:\\Users\\jack.UTILIS\\Desktop\\images\\Utilis_Branding2015_FINAL_Small.gif")
label = Label(root, image=photo)
label.pack(side=RIGHT)
bottomFrame = Frame(root)
bottomFrame.pack(side=BOTTOM)
button1 = Button(root, text="Open HV File", fg="black", command=filedialog.askopenfilename)
button2 = Button(root, text="Open VH FIle", fg="black", command=filedialog.askopenfilename)
button1.pack(side=LEFT)
button2.pack(side=RIGHT)
hvfullCmd = ' '.join([gdalTranslate, cmd, tk1.fileName,dst_dataset])
subprocess.call(hvfullCmd)
vhfullCmd = ' '.join([gdalTranslate,cmd, tk2.fileName,dstVH])
subprocess.call(vhfullCmd)
root.mainloop()
You have to create own function which get filename from askopenfilename and does something with this file. Then you can assign this file to button using command=
import tkinter as tk
from tkinter import filedialog
# --- functions ---
def on_click():
filename = filedialog.askopenfilename()
if filename:
print("Filename:", filename)
else:
print("Filename: not selected")
# --- main ---
root = tk.Tk()
btn = tk.Button(root, text='Click Me', command=on_click)
btn.pack()
root.mainloop()

Resources