Hi, Because I want to use my FR as my daily phone and because I have no solution to perform the hardware buzz-fix yet, I decided to write an application which allows to quickly and easily change essential mixer settings.
According to http://wiki.openmoko.org/wiki/Neo_FreeRunner_Hardware_Issues#Active_Issues and http://www.mail-archive.com/[email protected]/msg00564.html 3 mixers settings (5, 12, 48) help to reduce buzz intensity and and 2 others (4, 6) affect the volume of the caller (on the neo side). Application is written in Python/Elementary. python-elementary version must be 0.1+svnr39575 or greater :-( This app works fine under SHR-unstable. For other distributions, I fear that it does not. I don't know if some people will find this app useful. But if it's the case, lets me know. I'm not sure to be able to find time in the future to improve this program, but I can: - modify it to accept GTK as toolkit for GUI (instead of Elementary) - create a project (anti-buzz ?) on http://projects.openmoko.org - create a package for opkg.org ? Description =========== The application reads mixer settings (controls) in /usr/share/openmoko/scenarios/gsmhandset.state and for 5 of them (5, 12, 48, 4, 6) displays a slider to adjust their values. NEVER the app modify the file /usr/share/openmoko/scenarios/gsmhandset.state Button "Apply": load current mixer settings in the soundcard and create an new gsmhandset.state file in /tmp. Button "Restore default": at any time, you can click on this button to restore mixer settings in the app and in the soundcard. Usage ===== * Before or during a call, launch the app: ./anti-buzz.py * Changes settings with sliders * Click on 'Apply' button to test changes in live * When you are happy with a set of settings, copy /tmp/gsmhandset.sate in /usr/share/openmoko/scenarios/ To finish, here the settings which go best with my FR: * Mono Playback Volume (5): 112 * Mono Sidetone Playback Volume (12): 5 * Mic2 Capture Volume (48): 2 * Speaker Playback Volume (4): 112 * Bypass Playback Volume (6): 7 -- Valéry Febvre
#!/usr/bin/env python
# -*- coding: utf-8 -*-
ALSA_STATE_PATH = '/usr/share/openmoko/scenarios/gsmhandset.state'
# define here controls you want to manage
# only controls of type INTEGER are allowed
CONTROLS = [
5, 12, 48, # mic volume & buzz problem
4, 6, # speaker volume & echo problem
]
################################################################################
# Anti-Buzz -- an application to kill your GSM buzz
#
# Copyright (C) 2009 Valéry Febvre <[email protected]>
# http://???.projects.openmoko.org/
#
# This file is part of Anti-Buzz.
#
# Neon 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 3 of the
# License, or (at your option) any later version.
#
# Neon 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Anti-Buzz is an application to kill your GSM buzz.
"""
import os, re, commands
import elementary
RE_CONTROL = re.compile(r'^\t\control.(\d+) {$')
RE_TYPE = re.compile(r'^\t\tcomment.type ([A-Z]+).*')
RE_COUNT = re.compile(r"^\t\tcomment.count (\d+)")
RE_RANGE = re.compile(r"^\t\tcomment.range '(\d+) - (\d+)")
RE_NAME = re.compile(r"^\t\tname '([A-Za-z0-9- ]+)'")
RE_VALUE = re.compile(r'^\t\tvalue (\d+)')
RE_VALUE0 = re.compile(r'^\t\tvalue.0 (\d+)')
RE_VALUE1 = re.compile(r'^\t\tvalue.1 (\d+)')
controls_data = {}
blocks = {}
sliders = {}
def destroy(obj, event, data):
print "Bye bye"
elementary.exit()
def restore_default(obj, event, data):
for id in sliders.keys():
control = controls_data[id]
sliders[id].value = float(control['value'])
alsactl_restore(ALSA_STATE_PATH)
def apply_changes(obj, event, data):
new_alsa_state_path = '/tmp/%s' % os.path.basename(ALSA_STATE_PATH)
f = open(new_alsa_state_path, 'w+')
f.write("state.neo1973gta02 {\n")
for id in blocks.keys():
for line in blocks[id]:
if id in CONTROLS and \
(RE_VALUE.match(line) or RE_VALUE0.match(line) or RE_VALUE1.match(line)):
old_value = controls_data[id]['value']
new_value = str(int(round(sliders[id].value)))
#print 'control %d: %s => %s' % (id, old_value, new_value)
line = line.replace(old_value, new_value)
f.write(line)
f.close()
alsactl_restore(new_alsa_state_path)
msg = "New Alsa scenario has been applied and saved in %s" % new_alsa_state_path
label_info.label_set(msg)
def alsactl_restore(state_file):
commands.getoutput('alsactl -f %s restore' % state_file)
if __name__ == "__main__":
f = open(ALSA_STATE_PATH, 'r')
lines = f.readlines()
num = None
# store lines of all controls
for line in lines:
if RE_CONTROL.match(line):
num = int(RE_CONTROL.findall(line)[0])
blocks[num] = []
if num:
blocks[num].append(line)
# get data of selected controls
for id in CONTROLS[:]:
is_valid = True
count = None
type_ = None
for line in blocks[id]:
# type
if RE_TYPE.match(line):
type_ = RE_TYPE.findall(line)[0]
if type_ and type_ != 'INTEGER':
print 'WARNING: ignore control %d of type %s' % (id, type_)
del CONTROLS[CONTROLS.index(id)]
is_valid = False
break
# name
if RE_NAME.match(line):
name = RE_NAME.findall(line)[0]
# count
if RE_COUNT.match(line):
count = int(RE_COUNT.findall(line)[0])
# range
if RE_RANGE.match(line):
range = RE_RANGE.findall(line)[0]
# value or value0
if count == 1:
if RE_VALUE.match(line):
value = RE_VALUE.findall(line)[0]
elif count == 2:
if RE_VALUE0.match(line):
value = RE_VALUE0.findall(line)[0]
if is_valid:
controls_data[id] = {
'name': name,
'type': type_,
'count': count,
'range': range,
'value': value,
}
# build GUI
elementary.init()
win = elementary.Window("test", elementary.ELM_WIN_BASIC)
win.title_set("anti-buzz application")
win.destroy = destroy
bg = elementary.Background(win)
win.resize_object_add(bg)
bg.size_hint_weight_set(1.0, 1.0)
bg.show()
box0 = elementary.Box(win)
box0.size_hint_weight_set(1.0, 1.0)
win.resize_object_add(box0)
box0.show()
sc = elementary.Scroller(win)
sc.size_hint_weight_set(1.0, 1.0)
sc.size_hint_align_set(-1.0, -1.0)
box0.pack_end(sc)
sc.show()
box1 = elementary.Box(win)
box1.size_hint_weight_set(1.0, 1.0)
sc.content_set(box1)
box1.show()
for id in CONTROLS:
if id not in controls_data.keys():
continue
control = controls_data[id]
label = elementary.Label(win)
label.label_set(' <b>%s</b> (%d)' % (control['name'], id))
label.size_hint_align_set(0, 0.5)
label.scale_set(1.5)
box1.pack_end(label)
label.show()
slider = elementary.Slider(win)
slider.label_set('')
slider.span_size_set(160)
slider.size_hint_align_set(0, 0.5)
slider.size_hint_weight_set(0, 1)
slider.unit_format_set(" %3.0f" + ' / %d' % float(control['range'][1]))
slider.indicator_format_set("%3.0f")
slider.min_max_set(float(control['range'][0]), float(control['range'][1]))
slider.value = float(control['value'])
slider.scale_set(2)
box1.pack_end(slider)
slider.show()
sliders[id] = slider
label_info = elementary.Label(win)
label_info.label_set(' ')
label_info.size_hint_align_set(0.5, 0.5)
box0.pack_end(label_info)
label_info.show()
table = elementary.Table(win)
table.size_hint_weight_set(1, -1)
box0.pack_end(table)
table.show()
btn_default = elementary.Button(win)
btn_default.label_set('Restore Default')
table.pack(btn_default, 0, 0, 1, 1)
btn_default.show()
btn_default.clicked = restore_default
btn_apply = elementary.Button(win)
btn_apply.label_set(' Apply ')
table.pack(btn_apply, 1, 0, 1, 1)
btn_apply.show()
btn_apply.clicked = apply_changes
btn_quit = elementary.Button(win)
btn_quit.label_set(' Quit ')
table.pack(btn_quit, 2, 0, 1, 1)
btn_quit.show()
btn_quit.clicked = destroy
win.resize(480, 640)
win.show()
elementary.run()
elementary.shutdown()
<<inline: Screenshot-1.jpg>>
_______________________________________________ Openmoko community mailing list [email protected] http://lists.openmoko.org/mailman/listinfo/community

