Browse Source

Added digitalpeakmeter; added jackmeter

tags/v0.9.0
falkTX 13 years ago
parent
commit
cbf5da2078
6 changed files with 450 additions and 6 deletions
  1. +231
    -0
      src/digitalpeakmeter.py
  2. +23
    -0
      src/jacklib_helpers.py
  3. +136
    -0
      src/jackmeter.py
  4. +3
    -2
      src/logs.py
  5. +1
    -2
      src/render.py
  6. +56
    -2
      src/shared.py

+ 231
- 0
src/digitalpeakmeter.py View File

@@ -0,0 +1,231 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Digital Peak Meter, a custom Qt4 widget
# Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the COPYING file

# Imports (Global)
from PyQt4.QtCore import qCritical, Qt, QRectF, QTimer, QSize
from PyQt4.QtGui import QColor, QLinearGradient, QPainter, QWidget

# Widget Class
class DigitalPeakMeter(QWidget):
HORIZONTAL = 1
VERTICAL = 2

GREEN = 1
BLUE = 2

def __init__(self, parent):
QWidget.__init__(self, parent)

self.n_channels = 0
self.bg_color = QColor("#111111")

self.base_color = QColor("#5DE73D")
self.base_colorT = QColor(15, 110, 15, 100)
self.orientation = self.VERTICAL

self.meter_gradient = QLinearGradient(0, 0, 1, 1)
self.smooth_multiplier = 1

self.setOrientation(self.VERTICAL)
self.setChannels(2)

self.paint_timer = QTimer()
self.paint_timer.setInterval(60)
self.paint_timer.timeout.connect(self.update)
self.paint_timer.start()

def minimumSizeHint(self):
return QSize(30, 30)

def sizeHint(self):
return QSize(self.width_, self.height_)

def setChannels(self, channels):
self.n_channels = channels
self.channels_data = []
self.last_max_data = []

if (channels > 0):
for i in range(channels):
self.channels_data.append(0.0)
self.last_max_data.append(0.0) #self.height_

def setColor(self, color):
if (color == self.GREEN):
self.base_color = QColor("#5DE73D")
self.base_colorT = QColor(15, 110, 15, 100)
elif (color == self.BLUE):
self.base_color = QColor("#52EEF8")
self.base_colorT = QColor(15, 15, 110, 100)
else:
return

self.setOrientation(self.orientation)

def setOrientation(self, orientation):
self.orientation = orientation

if (self.orientation == self.HORIZONTAL):
self.meter_gradient.setColorAt(0.0, self.base_color)
self.meter_gradient.setColorAt(0.2, self.base_color)
self.meter_gradient.setColorAt(0.4, self.base_color)
self.meter_gradient.setColorAt(0.6, self.base_color)
self.meter_gradient.setColorAt(0.8, Qt.yellow)
self.meter_gradient.setColorAt(1.0, Qt.red)

elif (self.orientation == self.VERTICAL):
self.meter_gradient.setColorAt(0.0, Qt.red)
self.meter_gradient.setColorAt(0.2, Qt.yellow)
self.meter_gradient.setColorAt(0.4, self.base_color)
self.meter_gradient.setColorAt(0.6, self.base_color)
self.meter_gradient.setColorAt(0.8, self.base_color)
self.meter_gradient.setColorAt(1.0, self.base_color)

self.checkSizes()

def setRefreshRate(self, rate):
self.paint_timer.stop()
self.paint_timer.setInterval(rate)
self.paint_timer.start()

def setSmoothRelease(self, value):
if (value < 0):
value = 0
elif (value > 5):
value = 5
self.smooth_multiplier = value

def displayMeter(self, meter_n, level):
if (meter_n > self.n_channels):
qCritical("DigitalPeakMeter::displayMeter(%i, %f) - Invalid meter number", meter_n, level)
return

if (level < 0.0):
level = -level
if (level > 1.0):
level = 1.0

self.channels_data[meter_n-1] = level

def checkSizes(self):
self.width_ = self.width()
self.height_ = self.height()
self.meter_size = 0

if (self.orientation == self.HORIZONTAL):
self.meter_gradient.setFinalStop(self.width_, 0)
if (self.n_channels > 0):
self.meter_size = self.height_/self.n_channels

elif (self.orientation == self.VERTICAL):
self.meter_gradient.setFinalStop(0, self.height_)
if (self.n_channels > 0):
self.meter_size = self.width_/self.n_channels

def paintEvent(self, event):
painter = QPainter(self)

painter.setPen(Qt.black)
painter.setBrush(Qt.black)
painter.drawRect(0, 0, self.width_, self.height_)

meter_x = 0

for i in range(self.n_channels):
level = self.channels_data[i]

if (level == self.last_max_data[i]):
continue

if (self.orientation == self.HORIZONTAL):
value = self.width_*level
elif (self.orientation == self.VERTICAL):
value = self.height_-(self.height_*level)
else:
value = 0

# Don't bounce the meter so much
if (self.smooth_multiplier > 0):
value = (self.last_max_data[i]*self.smooth_multiplier + value)/(self.smooth_multiplier+1)

if (value < 0):
value = 0

painter.setPen(self.bg_color)
painter.setBrush(self.meter_gradient)

if (self.orientation == self.HORIZONTAL):
painter.drawRect(0, meter_x, value, self.meter_size)
elif (self.orientation == self.VERTICAL):
painter.drawRect(meter_x, value, self.meter_size, self.height_)

meter_x += self.meter_size
self.last_max_data[i] = value

if (self.orientation == self.HORIZONTAL):
lsmall = self.width_
lfull = self.height_-1
elif (self.orientation == self.VERTICAL):
lsmall = self.height_
lfull = self.width_-1
else:
return

painter.setBrush(QColor(0, 0, 0, 0))

if (self.orientation == self.HORIZONTAL):
# Base
painter.setPen(self.base_colorT)
painter.drawLine(lsmall/4, 1, lsmall/4, lfull)
painter.drawLine(lsmall/2, 1, lsmall/2, lfull)

# Yellow
painter.setPen(QColor(110, 110, 15, 100))
painter.drawLine(lsmall/1.4, 1, lsmall/1.4, lfull)
painter.drawLine(lsmall/1.2, 1, lsmall/1.2, lfull)

# Orange
painter.setPen(QColor(180, 110, 15, 100))
painter.drawLine(lsmall/1.1, 1, lsmall/1.1, lfull)

# Red
painter.setPen(QColor(110, 15, 15, 100))
painter.drawLine(lsmall/1.04, 1, lsmall/1.04, lfull)

elif (self.orientation == self.VERTICAL):
# Base
painter.setPen(self.base_colorT)
painter.drawLine(1, lsmall-(lsmall/4), lfull, lsmall-(lsmall/4))
painter.drawLine(1, lsmall-(lsmall/2), lfull, lsmall-(lsmall/2))

# Yellow
painter.setPen(QColor(110, 110, 15, 100))
painter.drawLine(1, lsmall-(lsmall/1.4), lfull, lsmall-(lsmall/1.4))
painter.drawLine(1, lsmall-(lsmall/1.2), lfull, lsmall-(lsmall/1.2))

# Orange
painter.setPen(QColor(180, 110, 15, 100))
painter.drawLine(1, lsmall-(lsmall/1.1), lfull, lsmall-(lsmall/1.1))

# Red
painter.setPen(QColor(110, 15, 15, 100))
painter.drawLine(1, lsmall-(lsmall/1.04), lfull, lsmall-(lsmall/1.04))

def resizeEvent(self, event):
QTimer.singleShot(0, self.checkSizes)
return QWidget.resizeEvent(self, event)

+ 23
- 0
src/jacklib_helpers.py View File

@@ -53,3 +53,26 @@ def get_jack_status_error_string(c_status):
error_string = error_string.strip().rsplit(";", 1)[0]+"."

return error_string

# C char** -> Python list conversion
def c_char_p_p_to_list(c_char_p_p):
i = 0
final_list = []

if (not c_char_p_p):
return final_list

while (True):
new_char_p = c_char_p_p[i]
if (new_char_p):
final_list.append(str(new_char_p, encoding="ascii"))
else:
break
i += 1

jacklib.free(c_char_p_p)
return final_list

# C cast void* -> jack_default_audio_sample_t*
def translate_audio_port_buffer(void_p):
return jacklib.cast(void_p, jacklib.POINTER(jacklib.jack_default_audio_sample_t))

+ 136
- 0
src/jackmeter.py View File

@@ -0,0 +1,136 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Simple JACK Audio Meter
# Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the COPYING file

# Imports (Global)
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QApplication, QWidget

# Imports (Custom Stuff)
from digitalpeakmeter import DigitalPeakMeter
from jacklib_helpers import *
from shared import *

global x_port1, x_port2, need_reconnect
x_port1 = 0.0
x_port2 = 0.0
need_reconnect = False
client = None

def process_callback(nframes, arg):
global x_port1, x_port2

p_out1 = translate_audio_port_buffer(jacklib.port_get_buffer(port_1, nframes))
p_out2 = translate_audio_port_buffer(jacklib.port_get_buffer(port_2, nframes))

for i in range(nframes):
if (abs(p_out1[i]) > x_port1):
x_port1 = abs(p_out1[i])

if (abs(p_out2[i]) > x_port2):
x_port2 = abs(p_out2[i])

return 0

def port_callback(port_a, port_b, connect_yesno, arg):
global need_reconnect
need_reconnect = True
return 0

def reconnect_inputs():
play_port_1 = jacklib.port_by_name(client, "system:playback_1")
play_port_2 = jacklib.port_by_name(client, "system:playback_2")
list_port_1 = c_char_p_p_to_list(jacklib.port_get_all_connections(client, play_port_1))
list_port_2 = c_char_p_p_to_list(jacklib.port_get_all_connections(client, play_port_2))
client_name = str(jacklib.get_client_name(client), encoding="ascii")

for port in list_port_1:
this_port = jacklib.port_by_name(client, port)
if not jacklib.port_is_mine(client, this_port):
jacklib.connect(client, port, "%s:in1" % (client_name))

for port in list_port_2:
this_port = jacklib.port_by_name(client, port)
if not jacklib.port_is_mine(client, this_port):
jacklib.connect(client, port, "%s:in2" % (client_name))

global need_reconnect
need_reconnect = False

class MeterW(DigitalPeakMeter):
def __init__(self, parent):
DigitalPeakMeter.__init__(self, parent)

client_name = str(jacklib.get_client_name(client), encoding="ascii")

self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint);
self.setWindowTitle(client_name)
self.setChannels(2)
self.setOrientation(self.VERTICAL)
self.setSmoothRelease(1)

self.displayMeter(1, x_port1)
self.displayMeter(2, x_port2)

self.setRefreshRate(30)
self.peakTimer = self.startTimer(60)

def timerEvent(self, event):
if (event.timerId() == self.peakTimer):
global x_port1, x_port2, need_reconnect
self.displayMeter(1, x_port1)
self.displayMeter(2, x_port2)
x_port1 = 0.0
x_port2 = 0.0

if (need_reconnect):
reconnect_inputs()

QWidget.timerEvent(self, event)

#--------------- main ------------------
if __name__ == '__main__':

# App initialization
app = QApplication(sys.argv)

# JACK initialization
client = jacklib.client_open("M", jacklib.JackNullOption, None)

port_1 = jacklib.port_register(client, "in1", jacklib.JACK_DEFAULT_AUDIO_TYPE, jacklib.JackPortIsInput, 0)
port_2 = jacklib.port_register(client, "in2", jacklib.JACK_DEFAULT_AUDIO_TYPE, jacklib.JackPortIsInput, 0)

jacklib.set_process_callback(client, process_callback, None)
jacklib.set_port_connect_callback(client, port_callback, None)
jacklib.activate(client)

reconnect_inputs()

# Show GUI
gui = MeterW(None)
gui.resize(70, 600)
gui.show()

set_up_signals(gui)

# App-Loop
ret = app.exec_()

jacklib.deactivate(client)
jacklib.client_close(client)

sys.exit(ret)

+ 3
- 2
src/logs.py View File

@@ -17,7 +17,7 @@
# For a full copy of the GNU General Public License see the COPYING file

# Imports (Global)
from PyQt4.QtCore import pyqtSlot, Qt, QFile, QIODevice, QTextStream, QThread, SIGNAL, SLOT
from PyQt4.QtCore import pyqtSlot, Qt, QFile, QIODevice, QTextStream, QThread
from PyQt4.QtGui import QDialog, QPalette, QSyntaxHighlighter

# Imports (Custom Stuff)
@@ -352,7 +352,6 @@ class LogsW(QDialog, ui_logs.Ui_LogsW):
if __name__ == '__main__':

# Additional imports
import sys
from PyQt4.QtGui import QApplication

# App initialization
@@ -362,5 +361,7 @@ if __name__ == '__main__':
gui = LogsW(None, Qt.WindowFlags())
gui.show()

set_up_signals(gui)

# App-Loop
sys.exit(app.exec_())

+ 1
- 2
src/render.py View File

@@ -17,7 +17,7 @@
# For a full copy of the GNU General Public License see the COPYING file

# Imports (Global)
from PyQt4.QtCore import pyqtSlot, Qt, QProcess, QTime, QTimer, SIGNAL, SLOT
from PyQt4.QtCore import pyqtSlot, Qt, QProcess, QTime, QTimer
from PyQt4.QtGui import QDialog
from time import sleep

@@ -270,7 +270,6 @@ class RenderW(QDialog, ui_render.Ui_RenderW):
if __name__ == '__main__':

# Additional imports
import sys
from PyQt4.QtGui import QApplication

# App initialization


+ 56
- 2
src/shared.py View File

@@ -17,10 +17,24 @@
# For a full copy of the GNU General Public License see the COPYING file

# Imports (Global)
import os
from PyQt4.QtCore import qDebug, qWarning
import os, sys
from PyQt4.QtCore import pyqtSlot, qWarning, SIGNAL, SLOT
from PyQt4.QtGui import QIcon, QMessageBox, QFileDialog

# Set Platform
if ("linux" in sys.platform):
LINUX = True
WINDOWS = False
elif ("win" in sys.platform):
LINUX = False
WINDOWS = True
else:
LINUX = False
WINDOWS = False

if (WINDOWS == False):
from signal import signal, SIGINT, SIGTERM, SIGUSR1, SIGUSR2

# Small integrity tests
HOME = os.getenv("HOME")
if (HOME == None):
@@ -48,3 +62,43 @@ def getAndSetPath(self, currentPath, lineEdit):
if (newPath):
lineEdit.setText(newPath)
return newPath

# Custom MessageBox
def CustomMessageBox(self, icon, title, text, extra_text="", buttons=QMessageBox.Yes|QMessageBox.No, defButton=QMessageBox.No):
msgBox = QMessageBox(self)
msgBox.setIcon(icon)
msgBox.setWindowTitle(title)
msgBox.setText(text)
msgBox.setInformativeText(extra_text)
msgBox.setStandardButtons(buttons)
msgBox.setDefaultButton(defButton)
return msgBox.exec_()

# signal handler for unix systems
def set_up_signals(_gui):
if (WINDOWS == False):
from signal import signal, SIGINT, SIGTERM, SIGUSR1, SIGUSR2
global x_gui
x_gui = _gui
signal(SIGINT, signal_handler)
signal(SIGTERM, signal_handler)
signal(SIGUSR1, signal_handler)
signal(SIGUSR2, signal_handler)

x_gui.connect(x_gui, SIGNAL("SIGUSR2()"), lambda gui=x_gui: showWindow(gui))
x_gui.connect(x_gui, SIGNAL("SIGTERM()"), SLOT("close()"))

def signal_handler(sig=0, frame=0):
global x_gui
if (sig in (SIGINT, SIGTERM)):
x_gui.emit(SIGNAL("SIGTERM()"))
elif (sig == SIGUSR1):
x_gui.emit(SIGNAL("SIGUSR1()"))
elif (sig == SIGUSR2):
x_gui.emit(SIGNAL("SIGUSR2()"))

def showWindow(self):
if (self.isMaximized()):
self.showMaximized()
else:
self.showNormal()

Loading…
Cancel
Save