main.py
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'untitled.ui' # # Created by: PyQt5 UI code generator 5.15.2 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(263, 70) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName("verticalLayout") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setObjectName("pushButton") self.verticalLayout.addWidget(self.pushButton) self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_2.setObjectName("pushButton_2") self.verticalLayout.addWidget(self.pushButton_2) MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "Play song 1")) self.pushButton_2.setText(_translate("MainWindow", "Play song 2")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
run_me.py
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from main import *
from pydub import AudioSegment,effects,utils,generators
import pyaudio
from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QMessageBox
from PyQt5.QtCore import QObject, QThread, pyqtSignal
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from time import sleep
import wave
class MainProgram:
def __init__(self):
self.app = QtWidgets.QApplication(sys.argv)
self.MainWindow = QtWidgets.QMainWindow()
self.ui = Ui_MainWindow()
self.ui.setupUi(self.MainWindow)
self.MainWindow.show()
self.papinhio_player = Papinhio_Player()
self.papinhio_player.start()
self.ui.pushButton.clicked.connect(lambda:self.load_file_to_deck_1())
self.ui.pushButton_2.clicked.connect(lambda:self.load_file_to_deck_2())
self.MainWindow.closeEvent = lambda event:self.closeEvent(event)
sys.exit(self.app.exec_())
def load_file_to_deck_1(self):
deck_1 = {
"saved path":"1.mp3",
"play-status":"stopped"
}
self.papinhio_player.prepare_deck_1(deck_1)
self.papinhio_player.deck_1["play-status"]="playing"
def load_file_to_deck_2(self):
deck_2 = {
"saved path":"2.mp3",
"play-status":"stopped"
}
self.papinhio_player.prepare_deck_2(deck_2)
self.papinhio_player.deck_2["play-status"]="playing"
def closeEvent(self,event):
self.papinhio_player.output_file.close()
self.papinhio_player.deck_1["play-status"] = "stopped"
self.papinhio_player.deck_2["play-status"] = "stopped"
self.papinhio_player.terminate()
self.papinhio_player.wait()
self.papinhio_player.exit()
self.papinhio_player.wait()
self.papinhio_player = None
event.accept()
class Papinhio_Player(QThread):
def __init__(self):
super().__init__()
#QoS settings
self.bit_rate = 128*1024 #128 kb/sec
self.packet_time = 93 #125 msec
self.packet_size = int(16384/4)
#self.new_sample_rate = 32768
self.new_sample_rate = 44100
self.format = pyaudio.paInt16
self.channels = 2
self.p = pyaudio.PyAudio()
sine_segment = generators.Sine(1000).to_audio_segment()
sine_segment = sine_segment.set_frame_rate(self.new_sample_rate)
sine_segment = sine_segment[454:547] #93 msec
self.silent_segment = sine_segment-200
self.deck_1 = {
"player-list-item":None,
"player-list-row":None,
"play-status":"stopped",
"chunk-number":0,
"total-duration-human":"00:00:00",
"total-duration-milliseconds":0,
"current-duration-milliseconds":0,
"muted":False,
"volume":100,
"normalize":0,
"pan":0,
"low-frequency":20,
"high-frequency":20000
}
self.deck_2 = {
"player-list-item":None,
"player-list-row":None,
"play-status":"stopped",
"chunk-number":0,
"total-duration-human":"00:00:00",
"total-duration-milliseconds":0,
"current-duration-milliseconds":0,
"muted":False,
"volume":100,
"normalize":0,
"pan":0,
"low-frequency":20,
"high-frequency":20000
}
self.output_file = wave.open("3.wav", 'wb')
self.output_file.setnchannels(1)
self.output_file.setsampwidth(self.p.get_sample_size(self.format))
self.output_file.setframerate(self.new_sample_rate)
def run(self):
self.stream = self.p.open(format=pyaudio.paInt16,channels=1,rate=self.new_sample_rate,input=True,output=True,frames_per_buffer=self.packet_size,stream_callback=self.preview_callback)
self.stream.start_stream()
def preview_callback(self,in_data, frame_count, time_info, status):
#sleep(0.01)
#deck 1
deck_1_slice = AudioSegment.empty()
if self.deck_1["play-status"]=="playing":
if self.deck_1["current-duration-milliseconds"]>self.deck_1["total-duration-milliseconds"]:
self.deck_1["play-status"] = "stopped"
#self.deck_1_status_signal.emit("stopped")
if self.deck_1["play-status"]=="playing":
if((self.deck_1["chunk-number"]+1)*(self.packet_time)<=self.deck_1["total-duration-milliseconds"]):
deck_1_slice = self.deck_1["audio-segment"][self.deck_1["chunk-number"]*(self.packet_time):(self.deck_1["chunk-number"]+1)*(self.packet_time)]
else:
if((self.deck_1["chunk-number"])*(self.packet_time)<self.deck_1["total-duration-milliseconds"]):
deck_1_slice = self.deck_1["audio-segment"][self.deck_1["chunk-number"]*(self.packet_time):]
else:
deck_1_slice = AudioSegment.empty()
else:
self.deck_1["chunk-number"] = 0
deck_1_slice = AudioSegment.empty()
elif self.deck_1["play-status"] == "stopped":
self.deck_1["chunk-number"] = 0
self.deck_1["current-duration-milliseconds"] = 0
deck_1_slice = AudioSegment.empty()
#deck 2
deck_2_slice = AudioSegment.empty()
if self.deck_2["play-status"]=="playing":
if self.deck_2["current-duration-milliseconds"]>self.deck_2["total-duration-milliseconds"]:
self.deck_2["play-status"] = "stopped"
#self.deck_1_status_signal.emit("stopped")
if self.deck_2["play-status"]=="playing":
if((self.deck_2["chunk-number"]+1)*(self.packet_time)<=self.deck_2["total-duration-milliseconds"]):
deck_2_slice = self.deck_2["audio-segment"][self.deck_2["chunk-number"]*(self.packet_time):(self.deck_2["chunk-number"]+1)*(self.packet_time)]
else:
if((self.deck_2["chunk-number"])*(self.packet_time)<self.deck_2["total-duration-milliseconds"]):
deck_2_slice = self.deck_2["audio-segment"][self.deck_2["chunk-number"]*(self.packet_time):]
else:
deck_2_slice = AudioSegment.empty()
else:
self.deck_2["chunk-number"] = 0
deck_2_slice = AudioSegment.empty()
elif self.deck_2["play-status"] == "stopped":
self.deck_2["chunk-number"] = 0
self.deck_2["current-duration-milliseconds"] = 0
deck_2_slice = AudioSegment.empty()
final_slice = self.silent_segment.overlay(deck_1_slice).overlay(deck_2_slice)
if self.deck_1["play-status"]=="playing":
self.deck_1["chunk-number"] +=1
self.deck_1["current-duration-milliseconds"] += self.packet_time
#self.deck_1_duration_signal.emit(self.deck_1["current-duration-milliseconds"])
if self.deck_2["play-status"]=="playing":
self.deck_2["chunk-number"] +=1
self.deck_2["current-duration-milliseconds"] += self.packet_time
#self.deck_2_duration_signal.emit(self.deck_2["current-duration-milliseconds"])
self.output_file.writeframesraw(final_slice.raw_data)
return (final_slice.raw_data, pyaudio.paContinue)
def prepare_deck_1(self,deck_1_dict):
self.deck_1 = deck_1_dict
saved_path = deck_1_dict["saved path"]
self.deck_1["audio-segment"] = AudioSegment.from_file(saved_path).split_to_mono()[0]
self.deck_1["total-duration-milliseconds"] = len(self.deck_1["audio-segment"])
self.deck_1["audio-segment"] = self.deck_1["audio-segment"].set_frame_rate(self.new_sample_rate)
self.deck_1["chunk-number"] = 0
self.deck_1["current-duration-milliseconds"] = 0
def prepare_deck_2(self,deck_2_dict):
self.deck_2 = deck_2_dict
saved_path = deck_2_dict["saved path"]
self.deck_2["audio-segment"] = AudioSegment.from_file(saved_path).split_to_mono()[0]
self.deck_2["total-duration-milliseconds"] = len(self.deck_1["audio-segment"])
self.deck_2["audio-segment"] = self.deck_2["audio-segment"].set_frame_rate(self.new_sample_rate)
self.deck_2["chunk-number"] = 0
self.deck_2["current-duration-milliseconds"] = 0
program = MainProgram()
Put 2 files (1.mp3,2.mp3) in the same directory as the script files.
With small files (duration time ~ 1:30) there is no error. But with large files (duration time ~ 60 minutes there is sound error).
Try to run run_me.py
First click the first button, and after 5 seconds click the second.
Can you help me to solve this?
Edit: Code updated (added record feature with wave module)
Thanks in advance, Chris Pappas