Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Changed
- ALSA state seeding moved to firstboot/recovery (pistomp-audio `seed.sh`). `change-audio-card.sh` forwards to it.

## [v3.3.2] - 2026-09-08
### Changed
Expand Down
2 changes: 0 additions & 2 deletions modalapistomp.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,8 @@ def main():
is_emulator = args.host[0] in EMULATOR_HOSTS

if not is_emulator:
# Audio Card Config - doing this early so audio passes ASAP
factory = Audiocardfactory.Audiocardfactory(cwd)
audiocard = factory.create()
audiocard.restore()

# MIDI initialization
# Prompts user for MIDI input port, unless a valid port number or name
Expand Down
30 changes: 1 addition & 29 deletions pistomp/audiocard.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
# along with pi-stomp. If not, see <https://www.gnu.org/licenses/>.

import logging
import mmap
import os
import re
import subprocess
import time
Expand All @@ -36,8 +34,7 @@ class Audiocard:
cwd: str
card_index: int = 0
config_file: str = "/var/lib/alsa/asound.state" # global config used by alsamixer, etc.
initial_config_file: str | None = None # use this if common config_file loading fails
initial_config_name: str | None = None

bypass: bool = False
_store_at: float | None = None

Expand All @@ -55,31 +52,6 @@ class Audiocard:
def __init__(self, cwd: str) -> None:
self.cwd = cwd

def restore(self):
# If the global config_file either doesn't exist, doesn't contain the name of our audiocard, or fails restore,
# read initial_config_file (our backup). This will be the case on first boot after install.
# Subsequent boots will likely use the global config_file since initial_config_file settings will get
# appended if a 'alsactl store' operation occurs or the system has a clean shutdown
conf_files = [self.config_file, self.initial_config_file]
for fname in conf_files:
if os.access(fname, os.R_OK) is True:
try:
looking_for = bytes(("state.%s" % self.initial_config_name), "utf-8")
f = open(fname)
with f as text:
s = mmap.mmap(text.fileno(), 0, access=mmap.ACCESS_READ)
if s.find(looking_for) != -1:
logging.info("restoring audio card settings from: %s" % fname)
subprocess.run(["/usr/sbin/alsactl", "-f", fname, "--no-lock", "--no-ucm", "restore"])
f.close()
# If the file loaded was not the global, then save it so it will be next time
if fname is not self.config_file:
self.store()
break
f.close()
except Exception:
logging.error("Failed trying to restore audio card settings from: %s" % fname)

def store(self):
# /var/lib/alsa/asound.state is root:root; this process runs as the
# unprivileged pistomp user, so alsactl needs sudo to lock and write it.
Expand Down
3 changes: 0 additions & 3 deletions pistomp/audioinjector.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with pi-stomp. If not, see <https://www.gnu.org/licenses/>.

import os
import pistomp.audiocard as audiocard


class Audioinjector(audiocard.Audiocard):

def __init__(self, cwd):
super(Audioinjector, self).__init__(cwd)
self.initial_config_file = os.path.join(cwd, 'setup', 'audio', 'audioinjector.state')
self.initial_config_name = 'audioinjectorpi'
self.CAPTURE_VOLUME = 'Capture'
self.MASTER = 'Master'
3 changes: 0 additions & 3 deletions pistomp/hifiberry.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with pi-stomp. If not, see <https://www.gnu.org/licenses/>.

import os
import pistomp.audiocard as audiocard


class Hifiberry(audiocard.Audiocard):

def __init__(self, cwd):
super(Hifiberry, self).__init__(cwd)
self.initial_config_file = os.path.join(cwd, 'setup', 'audio', 'hifiberry.state')
self.initial_config_name = 'sndrpihifiberry'
self.CAPTURE_VOLUME = 'Digital'
self.MASTER = None
30 changes: 13 additions & 17 deletions pistomp/iqaudiocodec.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,28 @@
# You should have received a copy of the GNU Affero General Public License
# along with pi-stomp. If not, see <https://www.gnu.org/licenses/>.

import os
import pistomp.audiocard as audiocard


class IQaudioCodec(audiocard.Audiocard):

def __init__(self, cwd):
super(IQaudioCodec, self).__init__(cwd)
self.initial_config_file = os.path.join(cwd, 'setup', 'audio', 'iqaudiocodec.state')
self.initial_config_name = 'IQaudIOCODEC'
self.CAPTURE_VOLUME = 'Aux'
self.MASTER = 'Headphone' # Changed to headphone to allow digital control of output.
self.CAPTURE_VOLUME = "Aux"
self.MASTER = "Headphone" # Changed to headphone to allow digital control of output.
self.DAC_EQ = "DAC EQ"
self.EQ_1 = 'DAC EQ1'
self.EQ_2 = 'DAC EQ2'
self.EQ_3 = 'DAC EQ3'
self.EQ_4 = 'DAC EQ4'
self.EQ_5 = 'DAC EQ5'
self.EQ_1 = "DAC EQ1"
self.EQ_2 = "DAC EQ2"
self.EQ_3 = "DAC EQ3"
self.EQ_4 = "DAC EQ4"
self.EQ_5 = "DAC EQ5"

self.bypass_left = False
self.bypass_right = False
self._init_bypass()

def _init_bypass(self):
self.bypass_left = not self.get_switch_parameter('Mixout Left DAC Left')
self.bypass_right = not self.get_switch_parameter('Mixout Right DAC Right')
self.bypass_left = not self.get_switch_parameter("Mixout Left DAC Left")
self.bypass_right = not self.get_switch_parameter("Mixout Right DAC Right")

def get_bypass_left(self) -> bool:
return self.bypass_left
Expand All @@ -50,10 +46,10 @@ def get_bypass_right(self) -> bool:

def set_bypass_left(self, bypass):
self.bypass_left = bypass
self.set_switch_parameter('Mixout Left Aux Left', self.bypass_left, store=False)
self.set_switch_parameter('Mixout Left DAC Left', not self.bypass_left)
self.set_switch_parameter("Mixout Left Aux Left", self.bypass_left, store=False)
self.set_switch_parameter("Mixout Left DAC Left", not self.bypass_left)

def set_bypass_right(self, bypass):
self.bypass_right = bypass
self.set_switch_parameter('Mixout Right Aux Right', self.bypass_right, store=False)
self.set_switch_parameter('Mixout Right DAC Right', not self.bypass_right)
self.set_switch_parameter("Mixout Right Aux Right", self.bypass_right, store=False)
self.set_switch_parameter("Mixout Right DAC Right", not self.bypass_right)
166 changes: 0 additions & 166 deletions setup/audio/audioinjector.state

This file was deleted.

Loading
Loading