Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional Addons #1

Open
wants to merge 43 commits into
base: exe
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c63445a
Add large file using Git LFS
Inserian May 8, 2024
1564fb4
Add large file via Git LFS
Inserian May 8, 2024
296dc74
Update README.md
Inserian May 8, 2024
9cbf329
Update Sonic.pyw
Inserian May 9, 2024
8779149
Update README.md
Inserian May 9, 2024
cb62c78
Update README.md
Inserian May 9, 2024
b06658e
Update Sonic.pyw
Inserian May 9, 2024
5b22ace
Add files via upload
Inserian May 9, 2024
b05b35e
Add large file via Git LFS
Inserian May 10, 2024
3df7404
Delete dist directory
Inserian May 10, 2024
07f74a1
Delete Sonic.pyw
Inserian May 10, 2024
edc7737
Create Sonic.pyw
Inserian May 10, 2024
c6566ea
Resolve merge conflict by [keeping/removing] Sonic.exe
Inserian May 10, 2024
2384908
Add Sonic project files to repository
Inserian May 10, 2024
ecba9fc
Create Sonic
Inserian May 10, 2024
10f2900
Update Sonic
Inserian May 10, 2024
ec5b64a
Delete Sonic
Inserian May 10, 2024
633a054
Update README.md
Inserian May 10, 2024
daad27d
Add files via upload
Inserian May 10, 2024
38758b6
Update README.md
Inserian May 10, 2024
b66bb6e
Update README.md
Inserian May 10, 2024
01f312c
Update README.md
Inserian May 10, 2024
af6256d
Update README.md
Inserian May 10, 2024
901e1d3
Update README.md
Inserian May 10, 2024
1e9db8c
Update README.md
Inserian May 10, 2024
bb42ff3
Update README.md
Inserian May 10, 2024
0bf1184
Update README.md
Inserian May 10, 2024
b9d026e
Update README.md
Inserian May 10, 2024
d15bc29
Update README.md
Inserian May 10, 2024
e81d9cf
Update README.md
Inserian May 10, 2024
ed0731f
Update README.md
Inserian May 10, 2024
4626ff4
Update README.md
Inserian May 10, 2024
ee4932d
Update README.md
Inserian May 10, 2024
3b73fb5
Update README.md
Inserian May 10, 2024
fd72014
Update README.md
Inserian May 11, 2024
2b4868f
Update README.md
Inserian May 11, 2024
c333461
Create holder
Inserian May 11, 2024
fd60259
Delete Sonic2no (10).ico
Inserian May 11, 2024
8fd4526
Delete Sonic2no (6).ico
Inserian May 11, 2024
583ac22
Delete Sonic2no (7).ico
Inserian May 11, 2024
938ae51
Delete Sonic2no (9).ico
Inserian May 11, 2024
80660ba
Add files via upload
Inserian May 11, 2024
0ed1173
Create python-app.yml
Inserian May 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist/Sonic.exe filter=lfs diff=lfs merge=lfs -text
C:/Users/inser/OneDrive/Desktop/New[[:space:]]folder[[:space:]](3)/dist/Sonic.exe filter=lfs diff=lfs merge=lfs -text
39 changes: 39 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: Python application

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest
49 changes: 41 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
<center><img src="https://lh3.googleusercontent.com/kZ-YQTlfPU2s4d5HkbT2lfwOcZOHjeSgXL3YzzUldKZBCCPeDhk8SrYZSt3P0V7RVHNE0bQuwKEGcMMqqF0PF5lHLm-vDWXP=s500" alt="Sonic" width="25%"></center>
<div align="center">
<img src="https://lh3.googleusercontent.com/kZ-YQTlfPU2s4d5HkbT2lfwOcZOHjeSgXL3YzzUldKZBCCPeDhk8SrYZSt3P0V7RVHNE0bQuwKEGcMMqqF0PF5lHLm-vDWXP=s500" alt="Sonic" width="250">
</div>


# Sonic
Ultrasonic Emitter
### Ultrasonic Emitter

Sonic is a simple python program (now also available as an exe) that allows
**Sonic** is a simple python program (now also available as an `.exe`) that allows
the user to adjust the sound emitted to the connected speaker or device
between the levels of 0 - 100,000 hz.
between the levels of **0 - 100,000 Hz**.

---

#### **Update**
Sonic now includes an **amplification bar** that allows for sounds beyond what your computer is typically capable of producing.

**Download the executable**: [Sonic Standalone Executable](https://github.com/R-D-BioTech-Alaska/Sonic/raw/main/dist/Sonic.exe)

---

### Requirements
- The `Requirement.bat` is needed to run the `.pyw` file.
(If `Requirement.bat` fails to execute, run `pip install pyaudio pyqt5 pydub pybluez pyinstaller` or the equivalent commands based on your setup.)
- The `.exe` file is standalone and located in the `/dist` directory.

---

### **Warning** :warning:
Please be aware that this program emits sounds that can be **harmful and dangerous** to both people and animals. The levels permitted by this device are able to cause hallucinations.


---

### How to Use
1. Download the appropriate version for your OS.
2. If using Python script, ensure Python is installed and run `Requirement.bat` to install dependencies.
3. Open the program and adjust the frequency and amplification as needed.
4. Use responsibly.

The Requirement.bat is for the .pyw file. Exe is standalone.
---

***Warning***
### Contribution
Contributions are welcome! Please fork this repository and open a pull request to make changes.

Please aware that this program emits sounds that can be harmful and dangerous
to people and animals. The levels allowed on this device can cause hallucinations.
---

### License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
174 changes: 113 additions & 61 deletions Sonic.pyw
Original file line number Diff line number Diff line change
@@ -1,113 +1,165 @@
import sys
import numpy as np
import pyaudio
from PyQt5.QtWidgets import QApplication, QMainWindow, QSlider, QLabel, QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QLineEdit
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import (QApplication, QMainWindow, QSlider, QLabel, QVBoxLayout,
QWidget, QPushButton, QHBoxLayout, QLineEdit, QStatusBar, QMessageBox)
from PyQt5.QtCore import Qt, QThread
from PyQt5.QtGui import QPixmap

class SoundThread(QThread):
def __init__(self, get_audio_data):
super(SoundThread, self).__init__()
self.get_audio_data = get_audio_data
self.running = True

def run(self):
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32, channels=1, rate=44100, output=True)
try:
while self.running:
data = self.get_audio_data()
stream.write(data)
finally:
stream.stop_stream()
stream.close()
p.terminate()

def stop(self):
self.running = False
self.wait()

class UltrasonicEmitter(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Sonic")
self.setupUI()
self.sound_thread = None
self.frequency = 20000
self.volume = 0.5
self.amplification_factor = 1.0
self.amplified = False
self.muted = False

def setupUI(self):
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
self.statusBar.showMessage("Ready")

self.image_label = QLabel(self)
pixmap = QPixmap('Sonic2no.png')
self.image_label.setPixmap(pixmap.scaled(200, 200, Qt.KeepAspectRatio))

# Frequency Slider
self.frequency_slider = QSlider(Qt.Horizontal)
self.frequency_slider.setRange(0, 100000) # Adjusted frequency range to 0 to 100,000 Hz
self.frequency_slider.setRange(0, 100000)
self.frequency_slider.setValue(20000)
self.frequency_slider.valueChanged.connect(self.slider_changed)
self.frequency_slider.valueChanged.connect(self.update_audio_settings)
self.frequency_slider.setStyleSheet("QSlider::handle:horizontal {background-color: teal;}")

# Frequency Input
self.frequency_input = QLineEdit("20000")
self.frequency_input.returnPressed.connect(self.input_changed)
self.frequency_input.returnPressed.connect(lambda: self.frequency_slider.setValue(int(self.frequency_input.text())))
self.frequency_input.setStyleSheet("QLineEdit {background-color: white; color: black;}")

# Volume Slider
self.volume_slider = QSlider(Qt.Horizontal)
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(50)
self.volume_slider.valueChanged.connect(self.update_volume)
self.volume_slider.valueChanged.connect(self.update_audio_settings)
self.volume_slider.setStyleSheet("QSlider::handle:horizontal {background-color: teal;}")

# Labels
self.frequency_label = QLabel("Frequency: 20000 Hz")
self.volume_label = QLabel("Volume: 50%")
self.amplification_slider = QSlider(Qt.Horizontal)
self.amplification_slider.setRange(100, 500)
self.amplification_slider.setValue(100)
self.amplification_slider.valueChanged.connect(self.update_amplification)
self.amplification_slider.setStyleSheet("QSlider::handle:horizontal {background-color: teal;}")

self.amplify_button = QPushButton("Toggle Amplification")
self.amplify_button.clicked.connect(self.toggle_amplification)
self.amplify_button.setStyleSheet("QPushButton {background-color: teal; color: white;}")

self.mute_button = QPushButton("Mute")
self.mute_button.clicked.connect(self.toggle_mute)
self.mute_button.setStyleSheet("QPushButton {background-color: teal; color: white;}")

# Play/Stop Button
self.play_button = QPushButton("Play")
self.play_button.clicked.connect(self.toggle_play)
self.play_button.setStyleSheet("QPushButton {background-color: teal; color: white;}")

# Layout
layout = QVBoxLayout()
layout.addWidget(self.frequency_label)
layout.addWidget(self.image_label)
layout.addWidget(QLabel("Frequency (Hz):"))
layout.addWidget(self.frequency_input)
layout.addWidget(self.frequency_slider)
layout.addWidget(self.volume_label)
layout.addWidget(QLabel("Volume (%):"))
layout.addWidget(self.volume_slider)
layout.addWidget(QLabel("Amplification Factor:"))
layout.addWidget(self.amplification_slider)
layout.addWidget(self.amplify_button)

button_layout = QHBoxLayout()
button_layout.addWidget(self.play_button)
button_layout.addWidget(self.mute_button)
layout.addLayout(button_layout)

container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)

# Sound generation variables
self.is_playing = False
self.p = pyaudio.PyAudio()
self.stream = None
self.frequency = 20000
self.volume = 0.5
self.timer = QTimer()
self.timer.timeout.connect(self.generate_sound)

def slider_changed(self):
def update_audio_settings(self):
self.frequency = self.frequency_slider.value()
self.frequency_label.setText(f"Frequency: {self.frequency} Hz")
self.volume = self.volume_slider.value() / 100.0
self.frequency_input.setText(str(self.frequency))

def input_changed(self):
text = self.frequency_input.text()
try:
frequency = int(text)
if 0 <= frequency <= 100000:
self.frequency_slider.setValue(frequency)
self.frequency = frequency
self.frequency_label.setText(f"Frequency: {self.frequency} Hz")
self.statusBar.showMessage(f"Frequency: {self.frequency} Hz, Volume: {int(self.volume * 100)}%, Amplification: {self.amplification_factor:.1f}x")

def update_amplification(self, value):
self.amplification_factor = value / 100.0
self.statusBar.showMessage(f"Amplification set to: {self.amplification_factor:.1f}x")

def toggle_amplification(self):
if not self.amplified:
msg = QMessageBox()
msg.setIcon(QMessageBox.Warning)
msg.setText("Amplifying the volume can cause damage to your hearing and speakers.")
msg.setInformativeText("Do you want to proceed with amplifying the volume?")
msg.setWindowTitle("Warning: Amplified Volume")
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
retval = msg.exec_()
if retval == QMessageBox.Yes:
self.amplified = True
self.statusBar.showMessage(f"Amplification turned On. Factor: {self.amplification_factor:.1f}x")
else:
raise ValueError("Frequency out of range")
except ValueError:
self.frequency_input.setText(str(self.frequency)) # Reset to the previous valid value
self.amplification_slider.setValue(100)
else:
self.amplified = False
self.statusBar.showMessage("Amplification turned Off.")

def update_volume(self):
self.volume = self.volume_slider.value() / 100.0
self.volume_label.setText(f"Volume: {self.volume * 100:.0f}%")
def get_audio_data(self):
samples = np.linspace(0, 0.1, int(44100 * 0.1), endpoint=False)
effective_volume = self.volume * self.amplification_factor if self.amplified else self.volume
effective_volume = 0 if self.muted else effective_volume
waveform = (np.sin(2 * np.pi * self.frequency * samples) * effective_volume).astype(np.float32)
return waveform.tobytes()

def toggle_mute(self):
self.muted = not self.muted
self.statusBar.showMessage("Muted" if self.muted else "Unmuted")
self.volume_slider.setEnabled(not self.muted)

def toggle_play(self):
if self.is_playing:
if self.sound_thread and self.sound_thread.isRunning():
self.stop_playing()
else:
self.start_playing()

def start_playing(self):
self.is_playing = True
self.sound_thread = SoundThread(self.get_audio_data)
self.sound_thread.start()
self.play_button.setText("Stop")
self.stream = self.p.open(format=pyaudio.paFloat32,
channels=1,
rate=44100,
output=True)
self.timer.start(100) # Timer to periodically generate sound
self.statusBar.showMessage("Playing...")

def stop_playing(self):
self.is_playing = False
if self.sound_thread:
self.sound_thread.stop()
self.play_button.setText("Play")
self.timer.stop()
self.stream.stop_stream()
self.stream.close()

def generate_sound(self):
sample_rate = 44100
duration = 0.1 # seconds
samples = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
waveform = (np.sin(2 * np.pi * self.frequency * samples) * self.volume).astype(np.float32)
if self.stream.is_active():
self.stream.write(waveform.tobytes())
self.statusBar.showMessage("Stopped")

if __name__ == "__main__":
app = QApplication(sys.argv)
Expand Down
39 changes: 39 additions & 0 deletions Sonic.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
['Sonic.pyw'],
pathex=[],
binaries=[],
datas=[('Sonic2no.png', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='Sonic',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['Sonic2no25.ico'],
)
Binary file added Sonic2no.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Sonic2no25.ico
Binary file not shown.
Binary file added Sonicapp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading