Compare commits

...
Author SHA1 Message Date
Theophile Terraz 22771c7f3a debug + pep8 2025-11-06 16:40:12 +01:00
Theophile Terraz 6d60a2017c add sound option in results for Q 2025-11-06 16:28:59 +01:00
5 changed files with 512 additions and 203 deletions

No files matched your search

+103 -8
View File
@@ -31,14 +31,23 @@ except Exception as e:
print(f"Module 'rasterio' is not available: {e}") print(f"Module 'rasterio' is not available: {e}")
_rasterio_loaded = False _rasterio_loaded = False
try:
import pyaudio
import wave
_audio_loaded = True
except Exception as e:
print(f"Either 'pyaudio' or 'wave' is not available: {e}")
_audio_loaded = False
from functools import reduce from functools import reduce
from numpy import sqrt import numpy as np
from datetime import datetime from datetime import datetime
from tools import trace, timer, logger_exception from tools import trace, timer, logger_exception
from View.Tools.PamhyrWindow import PamhyrWindow from View.Tools.PamhyrWindow import PamhyrWindow
from View.WaitingDialog import WaitingDialog
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QKeySequence, QIcon, QPixmap, QKeySequence, QIcon, QPixmap,
@@ -349,7 +358,8 @@ class ResultsWindow(PamhyrWindow):
"action_add": self._add_custom_plot, "action_add": self._add_custom_plot,
"action_export": self._export, "action_export": self._export,
# "action_export": self.export_current, # "action_export": self.export_current,
"action_import_data": self.import_data "action_import_data": self.import_data,
"action_play_sound": self.play_sound
} }
if _rasterio_loaded: if _rasterio_loaded:
actions["action_Geo_tiff"] = self.import_geotiff actions["action_Geo_tiff"] = self.import_geotiff
@@ -357,6 +367,12 @@ class ResultsWindow(PamhyrWindow):
self.find(QAction, "action_Geo_tiff")\ self.find(QAction, "action_Geo_tiff")\
.setEnabled(False) .setEnabled(False)
if _audio_loaded:
actions["action_play_sound"] = self.play_sound
else:
self.find(QAction, "action_play_sound")\
.setVisible(False)
if len(self._results) > 1: if len(self._results) > 1:
self.find(QAction, "action_reload").setEnabled(False) self.find(QAction, "action_reload").setEnabled(False)
@@ -959,7 +975,7 @@ class ResultsWindow(PamhyrWindow):
map( map(
lambda p: lambda p:
p.get_ts_key(timestamp, "V") / p.get_ts_key(timestamp, "V") /
sqrt(9.81 * ( np.sqrt(9.81 * (
p.geometry.wet_area( p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) / p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width( p.geometry.wet_width(
@@ -973,7 +989,7 @@ class ResultsWindow(PamhyrWindow):
map( map(
lambda p: lambda p:
p.get_ts_key(timestamp, "V") / p.get_ts_key(timestamp, "V") /
sqrt(9.81 * ( np.sqrt(9.81 * (
p.geometry.wet_area( p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) / p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width( p.geometry.wet_width(
@@ -986,7 +1002,7 @@ class ResultsWindow(PamhyrWindow):
map( map(
lambda p: lambda p:
p.get_ts_key(timestamp, "V") / p.get_ts_key(timestamp, "V") /
sqrt(9.81 * ( np.sqrt(9.81 * (
p.geometry.wet_area( p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) / p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width( p.geometry.wet_width(
@@ -1122,7 +1138,7 @@ class ResultsWindow(PamhyrWindow):
if self._current_results != 2: if self._current_results != 2:
fr = my_dict[dict_y["froude"]] = list( fr = my_dict[dict_y["froude"]] = list(
map(lambda z, v: map(lambda z, v:
v / sqrt(9.81 * ( v / np.sqrt(9.81 * (
profile.geometry.wet_area(z) / profile.geometry.wet_area(z) /
profile.geometry.wet_width(z)) profile.geometry.wet_width(z))
), z, v) ), z, v)
@@ -1131,7 +1147,7 @@ class ResultsWindow(PamhyrWindow):
fr1 = list( fr1 = list(
map(lambda z, v: map(lambda z, v:
v / v /
sqrt(9.81 * ( np.sqrt(9.81 * (
profile1.geometry.wet_area(z) / profile1.geometry.wet_area(z) /
profile1.geometry.wet_width(z)) profile1.geometry.wet_width(z))
), z1, v1) ), z1, v1)
@@ -1139,7 +1155,7 @@ class ResultsWindow(PamhyrWindow):
fr2 = list( fr2 = list(
map(lambda z, v: map(lambda z, v:
v / v /
sqrt(9.81 * ( np.sqrt(9.81 * (
profile2.geometry.wet_area(z) / profile2.geometry.wet_area(z) /
profile2.geometry.wet_width(z)) profile2.geometry.wet_width(z))
), z2, v2) ), z2, v2)
@@ -1313,3 +1329,82 @@ class ResultsWindow(PamhyrWindow):
for p in self._additional_plot: for p in self._additional_plot:
self._additional_plot[p].add_imported_plot(data) self._additional_plot[p].add_imported_plot(data)
def play_sound(self):
def get_sine_wave(frequency, duration,
sample_rate=44100, amplitude=4096):
t = np.linspace(0, duration, int(sample_rate*duration))
return amplitude*np.sin(2*np.pi*frequency*t)
if not _audio_loaded:
return
# results
results = self._results[self._current_results[0]]
if results is None:
return
# reach
reach = results.river.reachs[self._get_current_reach()]
profile_id = self._get_current_profile()
profile = reach.profile(profile_id)
t = self._timestamps
q = profile.get_key("Q")
scale = []
low = 30
high = 84
for k in range(low, high):
note = 440*2**((k-49)/12)
scale.append(note) # add musical note
n_notes = len(scale) # number of musical notes
# rescale
# we start at low to high
tmax = max(t)
tmin = min(t)
qmax = max(q)
qmin = min(q)
qfact = (n_notes) / (qmax - qmin + 1)
for i in range(len(q)):
q[i] = int((q[i] - qmin) * qfact)
nq = [q[0]] # (notes)
dq = [0.1] # durée
for i in range(len(t)-1):
if q[i] == q[i+1]:
dq[-1] += 0.1
else:
nq.append(q[i+1])
dq.append(0.1)
wq = []
volume = 2048
for i in range(len(dq)):
new_w = get_sine_wave(frequency=scale[nq[i]],
duration=dq[i],
amplitude=volume)
wq = np.concatenate((wq, new_w))
p = pyaudio.PyAudio()
chunk = 1048
stream = p.open(format=p.get_format_from_width(2),
channels=1,
rate=44100,
output=True)
def fn():
i = 0
while i < len(wq):
stream.write(
wq[i:min(i+chunk, len(wq))].astype(np.int16).tobytes()
)
i += chunk
dlg = WaitingDialog(
payload_fn=fn,
title="playing_sound",
parent=self
)
dlg.exec_()
stream.stop_stream()
stream.close()
p.terminate()
+3
View File
@@ -239,6 +239,9 @@ class MainTranslate(UnitTranslate):
"Results comparison with two " "Results comparison with two "
"incompatible study version" "incompatible study version"
) )
self._dict["playing_sound"] = _translate(
"MainWindow", "Playing sound..."
)
self._dict["x"] = _translate("MainWindow", "X (m)") self._dict["x"] = _translate("MainWindow", "X (m)")
self._dict["y"] = _translate("MainWindow", "Y (m)") self._dict["y"] = _translate("MainWindow", "Y (m)")
+13
View File
@@ -240,6 +240,7 @@
<addaction name="action_reload"/> <addaction name="action_reload"/>
<addaction name="action_Geo_tiff"/> <addaction name="action_Geo_tiff"/>
<addaction name="action_import_data"/> <addaction name="action_import_data"/>
<addaction name="action_play_sound"/>
</widget> </widget>
<action name="action_add"> <action name="action_add">
<property name="icon"> <property name="icon">
@@ -301,6 +302,18 @@
<string>Import data from SCV file</string> <string>Import data from SCV file</string>
</property> </property>
</action> </action>
<action name="action_play_sound">
<property name="icon">
<iconset>
<normaloff>ressources/multimedia-volume-control-symbolic.symbolic.png</normaloff>ressources/multimedia-volume-control-symbolic.symbolic.png</iconset>
</property>
<property name="text">
<string>play_sound</string>
</property>
<property name="toolTip">
<string>Play discharge as sound</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

+393 -195
View File
File diff suppressed because it is too large. Load diff