Skip to content

Commit

Permalink
new version 0.8 runs in Apple Silicon via Qt6
Browse files Browse the repository at this point in the history
  • Loading branch information
drscotthawley committed Mar 13, 2023
1 parent 5ab0b1f commit 58888b6
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 230 deletions.
37 changes: 18 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ Main web page: http://hedges.belmont.edu/~shawley/SHAART<br>
GitHub page: http://github.com/drscotthawley/SHAART<br>

<p align="center">
SHAART Acoustic Tools, v 0.7<br>
(April 7, 2020)<br>
SHAART Acoustic Tools, v 0.8<br>
(March 13, 2023)<br>
<img src="images/shaart_logo.jpg"><br>
(yes, the name is a joke)<br>
<a href="#about">About</a> &nbsp;&nbsp;
Expand Down Expand Up @@ -156,13 +156,15 @@ And here's an interesting one: a "leveler" effect:<br>

## Running from Source
<b>Running SHAART.py from source:</b><br>
Create a new [Anaconda](https://www.anaconda.com/) Python environment and install dependencies, then run...
Create a new Python environment and install dependencies:
```bash
pip install librosa pyqt6 pillow pyaudio numpy matplotlib
```

Then run...

```bash
cd SHAART/source
conda create --name shaart python=3.7
conda activate shaart
conda install -c conda-forge librosa pyqt pillow pyaudio
./SHAART.py
```

Expand All @@ -175,22 +177,15 @@ conda install -c conda-forge librosa pyqt pillow pyaudio
First follow the instructions above for running from source. Then we will proceed by using `pyinstaller`, that will create a new directory called `SHAART/source/dist/`, **in which a successful build will result in the presence of working binary executable.**

```bash
conda install -c conda-forge pyinstaller
```

And (because of conflicts) downgrade setuptools too, via `pip`:

```bash
pip install --upgrade 'setuptools<45.0.0'`
pip install pyinstaller
```

### Mac

In order to run from source, you'd already need to have XCode, the command-line tools, and HomeBrew installed. Then in we install `python.app` and [an older versions of a few things](https://github.com/pyinstaller/pyinstaller/issues/4067) to build the app:

```bash
conda install -c conda-forge python.app joblib=0.11 scikit-learn=0.21.3 librosa=0.6.1
pyinstaller SHAART.spec --specpath=test
pyinstaller SHAART.spec
```

...and you'll find `SHAART.app` in `source/dist/`.
Expand All @@ -200,7 +195,7 @@ pyinstaller SHAART.spec --specpath=test
We *could* re-use the .spec file from the Mac build, but it would give us a whole directory instead of one executable. Instead, run this line:

```bash
pyinstaller -w --icon=SHAART.icns --hidden-import="sklearn.utils._cython_blas" --hidden-import="sklearn.neighbors._typedefs" --hidden-import="sklearn.neighbors.quad_tree" --hidden-import="sklearn.tree._utils" --onefile SHAART.py
pyinstaller SHAART.spec
```

...And then you can just run the `dist/SHAART` executable from the command line. (Note: I can't seem to get it to be a "clickable icon" in Nautilus/Gnome. Not sure how to do that.)
Expand Down Expand Up @@ -234,10 +229,10 @@ Here are the steps taken to build the Window EXE:

## Changing the GUI

Run QT5's `designer` or `Designer` app ([good luck finding this on your hard drive](https://stackoverflow.com/questions/37419138/is-qt-designer-bundled-with-anaconda), btw; instead you might want to just [download QT from the main site](https://www.qt.io/)). Open `ui_shaart.ui` as an input file. Change the GUI as you like, save it, and then to generate the .py file, run
Run QT's `designer` or `Designer` app ([good luck finding this on your hard drive](https://stackoverflow.com/questions/37419138/is-qt-designer-bundled-with-anaconda), btw; instead you might want to just [download QT from the main site](https://www.qt.io/)). Open `ui_shaart.ui` as an input file. Change the GUI as you like, save it, and then to generate the .py file, run

```bash
pyuic5 -x ui_shaart.ui -o ui_shaart.py
pyuic6 -x ui_shaart.ui -o ui_shaart.py
```


Expand All @@ -247,7 +242,7 @@ pyuic5 -x ui_shaart.ui -o ui_shaart.py
## FAQ

* You do realize what the name "SHAART" sounds like...? See "About" above. thatsthejoke.jpg
* Can it only read WAV files? No. Despite saying WAV file everywhere, version 0.7 can read anything [librosa](https://librosa.github.io/librosa/) can read, which is...pretty much anything, e.g. WAV, AIFF, M4A,...?
* Can it only read WAV files? No. Despite saying WAV file everywhere, SHAART can read anything [librosa](https://librosa.github.io/librosa/) can read, which is...pretty much anything, e.g. WAV, AIFF, M4A,...?
* Can I get a logarithmic frequency scale for the spectrogram? Not yet, but soon.
* For waterfall plots, it doesn't clear the window if you change the input data, resulting in multiple plots on the same page. Bug or feature?
* Does the "Record" feature work? Not yet. Use Audacity or....any other utility to record. ;-)
Expand All @@ -256,6 +251,10 @@ pyuic5 -x ui_shaart.ui -o ui_shaart.py
<a name="notes"></a>

## Release Notes / Issues
* v0.8:
* Upgrades for execution on M1 Macs:
* Upgraded from Qt5 to Qt6

* v0.7:

* Updated code from Python 2.7 to Python 3.7
Expand Down
12 changes: 6 additions & 6 deletions source/SHAART.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# used to parse files more easily
from __future__ import with_statement
from __future__ import print_function
Expand All @@ -10,9 +10,9 @@
import sys

# GUI bindings
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import *
from PyQt6 import QtGui, QtCore, QtWidgets
from PyQt6.QtWidgets import QMainWindow
from PyQt6.QtCore import *

# import the MainWindow widget from the converted .ui files
from ui_shaart import Ui_TheMainWindow
Expand Down Expand Up @@ -617,7 +617,7 @@ def update_tab(self):

def about_message(self):
msg = """
SHAART v.0.7
SHAART v.0.8
http://hedges.belmont.edu/~shawley/SHAART
A simple audio analysis suite intended for
Expand All @@ -639,4 +639,4 @@ def about_message(self):
dmw.show()
# start the Qt main loop execution, exiting from this script
# with the same return code of Qt application
sys.exit(app.exec_())
sys.exit(app.exec())
5 changes: 3 additions & 2 deletions source/SHAART.spec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ a = Analysis(['SHAART.py'],
binaries=[],
datas=[],
hiddenimports=['sklearn.utils._cython_blas', 'sklearn.neighbors.typedefs', 'sklearn.tree._utils', 'librosa', 'sklearn.neighbors.quad_tree', 'sklearn.tree', 'scipy._lib.messagestream'],
hookspath=[],
hookspath=['extra-hooks'],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
Expand Down Expand Up @@ -36,5 +36,6 @@ coll = COLLECT(exe,
name='SHAART')
app = BUNDLE(coll,
name='SHAART.app',
icon='shaart_logo_icon.icns',
icon='shaart_logo_icon.ico',
bundle_identifier=None)

3 changes: 3 additions & 0 deletions source/extra-hooks/hook-librosa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from PyInstaller.utils.hooks import collect_data_files
datas = collect_data_files('librosa')

6 changes: 3 additions & 3 deletions source/modegraphwidget.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Python Qt5 bindings for GUI objects
from PyQt5 import QtGui, QtWidgets
from PyQt6 import QtGui, QtWidgets

# import the Qt5Agg FigureCanvas object, that binds Figure to
# Qt5Agg backend. It also inherits from QWidget
Expand Down Expand Up @@ -45,8 +45,8 @@ def __init__(self):

# we define the widget as expandable
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Expanding)
# notify the system of updated policy
FigureCanvas.updateGeometry(self)

Expand Down
8 changes: 4 additions & 4 deletions source/pwrspecwidget.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Python Qt5 bindings for GUI objects
from PyQt5 import QtGui, QtWidgets
from PyQt6 import QtGui, QtWidgets

# import the Qt5Agg FigureCanvas object, that binds Figure to
# Qt5Agg backend. It also inherits from QWidget
Expand Down Expand Up @@ -50,8 +50,8 @@ def __init__(self):

# we define the widget as expandable
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Expanding)
# notify the system of updated policy
FigureCanvas.updateGeometry(self)

Expand Down Expand Up @@ -118,7 +118,7 @@ def draw_graph(self,amp,samplerate,color="red"):

self.canvas.ax.grid(True)
self.canvas.ax.axis([10,ds_f[-1],minval,0])
self.canvas.ax.set_xscale("log", nonposx='clip')
self.canvas.ax.set_xscale("log", nonpositive='clip')


# Annotation
Expand Down
7 changes: 3 additions & 4 deletions source/rcgraphwidget.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Sabine Equation / Room simulation tab

# Python Qt5 bindings for GUI objects
from PyQt5 import QtGui, QtWidgets
from PyQt6 import QtGui, QtWidgets

# import the Qt5Agg FigureCanvas object, that binds Figure to
# Qt5Agg backend. It also inherits from QWidget
Expand Down Expand Up @@ -33,8 +33,8 @@ def __init__(self):

# we define the widget as expandable
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Expanding)
# notify the system of updated policy
FigureCanvas.updateGeometry(self)

Expand Down Expand Up @@ -134,7 +134,6 @@ def update(self):
self.canvas.ax.plot(freqs, rtimes, 'bo-')
self.canvas.ax.grid(True)
self.canvas.ax.axis([0.0,freqs[-1]*1.05,0.0, np.max(rtimes)*1.05 ])
# self.canvas.ax.set_xscale("log", nonposx='clip')

# Annotation
self.canvas.ax.set_xlabel('Frequency (Hz)')
Expand Down
6 changes: 3 additions & 3 deletions source/rt60widget.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Python Qt5 bindings for GUI objects
from PyQt5 import QtGui, QtWidgets
from PyQt6 import QtGui, QtWidgets

from matplotlib.backends.backend_qt5agg \
import FigureCanvasQTAgg as FigureCanvas
Expand Down Expand Up @@ -64,8 +64,8 @@ def __init__(self):

# we define the widget as expandable
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Expanding)
# notify the system of updated policy
FigureCanvas.updateGeometry(self)

Expand Down
6 changes: 3 additions & 3 deletions source/spectrowidget.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Python Qt5 bindings for GUI objects
from PyQt5 import QtGui, QtWidgets
from PyQt6 import QtGui, QtWidgets

# import the Qt5Agg FigureCanvas object, that binds Figure to
# Qt5Agg backend. It also inherits from QWidget
Expand Down Expand Up @@ -30,8 +30,8 @@ def __init__(self):

# we define the widget as expandable
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
QtWidgets.QSizePolicy.Policy.Expanding,
QtWidgets.QSizePolicy.Policy.Expanding)
# notify the system of updated policy
FigureCanvas.updateGeometry(self)

Expand Down
Loading

0 comments on commit 58888b6

Please sign in to comment.