-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
246 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,81 @@ | ||
package Plugins::SigGen::Plugin; | ||
|
||
# Signal Generator Plugin | ||
# | ||
# (c) Triode - [email protected] | ||
# | ||
# | ||
|
||
use strict; | ||
|
||
use base qw(Slim::Plugin::Base); | ||
|
||
use Slim::Utils::Strings qw(string); | ||
use Slim::Utils::Prefs; | ||
use Slim::Utils::Log; | ||
|
||
my $log = Slim::Utils::Log->addLogCategory({ | ||
'category' => 'plugin.siggen', | ||
'defaultLevel' => 'WARN', | ||
'description' => 'PLUGIN_SIGGEN', | ||
}); | ||
|
||
my $prefs = preferences('server'); | ||
|
||
use Plugins::SigGen::ProtocolHandler; | ||
|
||
# following are the values offered by the menus or remote buttons | ||
my $v = { | ||
freq => [ 10, 20, 30, 40, 50, 60, 70, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1800, | ||
2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000, 16000, 18000, 20000 ], | ||
func => [ 'sine', 'square', 'triangle', 'sawtooth' ], | ||
amp => [ -80, -60, -40, -20, -10, -6, 0 ], | ||
chan => [ 'l+r', 'l', 'r' ], | ||
bits => [ 16, 24 ], | ||
rate => [ 8, 11, 12, 16, 22, 24, 32, 44, 48, 88, 96 ], | ||
}; | ||
|
||
# default signal - indexes into above arrays | ||
my $defaults = { | ||
freq => 11, | ||
func => 0, | ||
chan => 0, | ||
amp => 2, | ||
bits => 0, | ||
rate => 7, | ||
}; | ||
|
||
sub initPlugin { | ||
my $class = shift; | ||
|
||
$class->SUPER::initPlugin; | ||
|
||
Slim::Control::Request::addDispatch(['siggen_menu'], [ 1, 1, 1, \&cliMenu ]); | ||
|
||
my @menu = ({ | ||
stringToken => 'PLUGIN_SIGGEN', | ||
id => 'pluginSigGen', | ||
actions => { | ||
go => { | ||
cmd => [ 'siggen_menu' ], | ||
}, | ||
}, | ||
}); | ||
|
||
Slim::Control::Jive::registerPluginMenu(\@menu, 'extras'); | ||
} | ||
|
||
sub getDisplayName { 'PLUGIN_SIGGEN' }; | ||
|
||
sub modeName { 'PLUGIN_SIGGEN' }; | ||
|
||
my $prefs = preferences('server'); | ||
|
||
# following are the setting which are changed from the remote with button presses | ||
my @funcs = ( 'sine', 'square', 'triangle', 'sawtooth' ); # button 1 | ||
my @amps = ( -80, -60, -40, -20, -10, -6, 0 ); # button 2 inc, button 5 dec | ||
my @chans = ( 'l+r', 'l', 'r' ); # button 3 | ||
my @bits = ( 16, 24 ); # button 4 | ||
my @rates = ( 8, 11, 12, 16, 22, 24, 32, 44, 48, 88, 96 ); # button 6 | ||
|
||
sub setMode { | ||
my $class = shift; | ||
my $client = shift; | ||
|
||
my $s = $client->modeParam('params') || { | ||
'freq' => 500, | ||
'func' => 0, | ||
'chan' => 0, | ||
'amp' => 2, | ||
'bits' => 0, | ||
'rate' => 7, | ||
}; | ||
my $s = $client->pluginData('params') || $defaults; | ||
|
||
$client->modeParam('params', $s); | ||
$client->pluginData('params', $s); | ||
|
||
$client->lines(\&lines); | ||
|
||
|
@@ -62,13 +100,13 @@ sub exitMode { | |
sub lines { | ||
my $client = shift; | ||
|
||
my $s = $client->modeParam('params'); | ||
my $s = $client->pluginData('params'); | ||
|
||
return { | ||
'line' => [ string('PLUGIN_SIGGEN'), string('PLUGIN_SIGGEN_' . uc $funcs[$s->{'func'}]) ], | ||
'line' => [ string('PLUGIN_SIGGEN'), string('PLUGIN_SIGGEN_' . uc $v->{'func'}->[$s->{'func'}]) ], | ||
'overlay' => [ | ||
(sprintf "%s %s/%s", string('PLUGIN_SIGGEN_' . uc $chans[$s->{'chan'}]), $rates[$s->{'rate'}], $bits[$s->{'bits'}]), | ||
(sprintf "%s dB %s Hz", $amps[$s->{'amp'}], $s->{'freq'}), | ||
(sprintf "%s %s/%s", string('PLUGIN_SIGGEN_' . uc $v->{'chan'}->[$s->{'chan'}]), $v->{'rate'}->[$s->{'rate'}], $v->{'bits'}->[$s->{'bits'}]), | ||
(sprintf "%s dB %s Hz", $v->{'amp'}->[$s->{'amp'}], $v->{'freq'}->[$s->{'freq'}]), | ||
], | ||
}; | ||
} | ||
|
@@ -80,63 +118,42 @@ my %functions = ( | |
|
||
'up' => sub { | ||
my $client = shift; | ||
my $s = $client->modeParam('params'); | ||
|
||
if ($s->{'freq'} < 20000) { | ||
my $s = $client->pluginData('params'); | ||
|
||
$s->{'freq'} += ($s->{'freq'} >= 100 ? 100 : 10); | ||
$s->{'freq'} = ($s->{'freq'} + 1) % scalar @{$v->{'freq'}}; | ||
|
||
update($client); | ||
} | ||
update($client); | ||
}, | ||
|
||
'down' => sub { | ||
my $client = shift; | ||
my $s = $client->modeParam('params'); | ||
my $s = $client->pluginData('params'); | ||
|
||
if ($s->{'freq'} > 10) { | ||
|
||
$s->{'freq'} -= ($s->{'freq'} > 100 ? 100 : 10); | ||
|
||
update($client); | ||
} | ||
}, | ||
|
||
'jump' => sub { | ||
my ($client, $funct, $arg) = @_; | ||
my $s = $client->modeParam('params'); | ||
|
||
if ($arg eq 'rew') { | ||
$s->{'freq'} = $s->{'freq'} > 100 ? $s->{'freq'} / 10 : $s->{'freq'}; | ||
} | ||
|
||
if ($arg eq 'fwd') { | ||
$s->{'freq'} = $s->{'freq'} <= 2000 ? $s->{'freq'} * 10 : $s->{'freq'}; | ||
} | ||
$s->{'freq'} = ($s->{'freq'} - 1) % scalar @{$v->{'freq'}}; | ||
|
||
update($client); | ||
}, | ||
|
||
'numberScroll' => sub { | ||
my ($client, $funct, $arg) = @_; | ||
|
||
my $s = $client->modeParam('params'); | ||
my $s = $client->pluginData('params'); | ||
|
||
if ($arg eq '1') { | ||
$s->{'func'} = ($s->{'func'} + 1) % scalar @funcs; | ||
$s->{'func'} = ($s->{'func'} + 1) % scalar @{$v->{'func'}}; | ||
} | ||
|
||
if ($arg eq '2') { | ||
$s->{'amp'} = $s->{'amp'} < $#amps ? $s->{'amp'} + 1 : $s->{'amp'}; | ||
$s->{'amp'} = $s->{'amp'} < scalar @{$v->{'amp'}} - 1 ? $s->{'amp'} + 1 : $s->{'amp'}; | ||
} | ||
|
||
if ($arg eq '3') { | ||
$s->{'chan'} = ($s->{'chan'} + 1) % scalar @chans; | ||
$s->{'chan'} = ($s->{'chan'} + 1) % scalar @{$v->{'chan'}}; | ||
} | ||
|
||
if ($arg eq '4') { | ||
$s->{'rate'} = ($s->{'rate'} + 1) % scalar @rates; | ||
if ($rates[$s->{'rate'}] * 1000 > $client->maxSupportedSamplerate) { | ||
$s->{'rate'} = ($s->{'rate'} + 1) % scalar @{$v->{'rate'}}; | ||
if ($v->{'rate'}[$s->{'rate'}] * 1000 > $client->maxSupportedSamplerate) { | ||
$s->{'rate'} = 0; | ||
} | ||
} | ||
|
@@ -146,7 +163,7 @@ my %functions = ( | |
} | ||
|
||
if ($arg eq '6') { | ||
$s->{'bits'} = ($s->{'bits'} + 1) % scalar @bits; | ||
$s->{'bits'} = ($s->{'bits'} + 1) % scalar @{$v->{'bits'}}; | ||
} | ||
|
||
update($client); | ||
|
@@ -160,14 +177,14 @@ sub getFunctions { | |
sub update { | ||
my $client = shift; | ||
|
||
my $s = $client->modeParam('params'); | ||
my $s = $client->pluginData('params'); | ||
|
||
my $freq = $s->{'freq'}; | ||
my $func = $funcs[$s->{'func'}]; | ||
my $rate = $rates[$s->{'rate'}]; | ||
my $bits = $bits[$s->{'bits'}]; | ||
my $ampL = ($chans[$s->{'chan'}] =~ /l/) ? $amps[$s->{'amp'}] : 'off'; | ||
my $ampR = ($chans[$s->{'chan'}] =~ /r/) ? $amps[$s->{'amp'}] : 'off'; | ||
my $freq = $v->{'freq'}[$s->{'freq'}]; | ||
my $func = $v->{'func'}[$s->{'func'}]; | ||
my $rate = $v->{'rate'}[$s->{'rate'}]; | ||
my $bits = $v->{'bits'}[$s->{'bits'}]; | ||
my $ampL = ($v->{'chan'}[$s->{'chan'}] =~ /l/) ? $v->{'amp'}[$s->{'amp'}] : 'off'; | ||
my $ampR = ($v->{'chan'}[$s->{'chan'}] =~ /r/) ? $v->{'amp'}[$s->{'amp'}] : 'off'; | ||
|
||
my $url = "siggen://test.raw?func=$func&freq=$freq&rate=$rate&bits=$bits&L=$ampL&R=$ampR"; | ||
|
||
|
@@ -203,4 +220,124 @@ sub avoidScreenSaver { | |
} | ||
} | ||
|
||
sub cliMenu { | ||
my $request = shift; | ||
my $client = $request->client || return; | ||
my $menu = $request->getParam('menu') || 'toplevel'; | ||
my $play = $request->getParam('play'); | ||
|
||
my $s = $client->pluginData('params') || $client->pluginData('params', $defaults); | ||
|
||
# handle changes | ||
my $new; | ||
|
||
for my $param (keys %$v) { | ||
|
||
my $p = $request->getParam($param); | ||
|
||
if (defined $p && $p >= 0 && $p < scalar @{$v->{$param}}) { | ||
$s->{$param} = $p; | ||
$new = 1; | ||
} | ||
} | ||
|
||
my $freq = $v->{'freq'}->[$s->{'freq'}]; | ||
my $func = $v->{'func'}->[$s->{'func'}]; | ||
my $rate = $v->{'rate'}->[$s->{'rate'}]; | ||
my $bits = $v->{'bits'}->[$s->{'bits'}]; | ||
my $chan = $v->{'chan'}->[$s->{'chan'}]; | ||
my $amp = $v->{'amp'}->[$s->{'amp'}]; | ||
my $ampL = ($v->{'chan'}->[$s->{'chan'}] =~ /l/) ? $amp : 'off'; | ||
my $ampR = ($v->{'chan'}->[$s->{'chan'}] =~ /r/) ? $amp : 'off'; | ||
|
||
if ($play eq 'stop') { | ||
|
||
$log->info("Stopping"); | ||
|
||
$client->execute(['playlist', 'clear']); | ||
|
||
for my $track (Slim::Schema->rs('Track')->search_like({ 'url' => 'siggen%' })->all) { | ||
$track->delete; | ||
} | ||
|
||
} elsif ($play eq 'start' || $new) { | ||
|
||
my $url = "siggen://test.raw?func=$func&freq=$freq&rate=$rate&bits=$bits&L=$ampL&R=$ampR"; | ||
|
||
$log->info("Playing $url"); | ||
|
||
Slim::Music::Info::setTitle($url, "$freq Hz " . string("PLUGIN_SIGGEN_$func") . " $amp dB " . | ||
string("PLUGIN_SIGGEN_$chan") . " $rate/$bits" ); | ||
|
||
$client->execute(['playlist', 'play', $url]); | ||
} | ||
|
||
# build new menu | ||
|
||
my @menu = (); | ||
my $title; | ||
|
||
if ($menu eq 'toplevel') { | ||
|
||
push @menu, { | ||
text => $client->isPlaying ? string('PLUGIN_SIGGEN_STOP') : string('PLUGIN_SIGGEN_STOPPED'), | ||
actions => { go => { cmd => ['siggen_menu'], params => { play => $client->isPlaying ? 'stop' : 'start' } } }, | ||
nextWindow => 'refresh', | ||
}; | ||
|
||
my @menus = (freq => sprintf(string('PLUGIN_SIGGEN_FREQUENCY'), $freq), | ||
amp => sprintf(string('PLUGIN_SIGGEN_AMPLITUDE'), $amp), | ||
func => sprintf(string('PLUGIN_SIGGEN_FUNCTION'), string("PLUGIN_SIGGEN_$func")), | ||
chan => sprintf(string('PLUGIN_SIGGEN_CHANNEL'), string("PLUGIN_SIGGEN_$chan")), | ||
rate => sprintf(string('PLUGIN_SIGGEN_RATE'), $rate), | ||
bits => sprintf(string('PLUGIN_SIGGEN_BITS'), $bits), | ||
); | ||
|
||
while (my ($key, $text) = splice @menus, 0, 2) { | ||
push @menu, { | ||
text => $text, | ||
actions => { go => { cmd => [ 'siggen_menu' ], params => { menu => $key } } }, | ||
}; | ||
} | ||
|
||
} if ($menu && exists $v->{$menu}) { | ||
|
||
$title = string('PLUGIN_SIGGEN_TITLE_' . $menu); | ||
|
||
my $text = { | ||
freq => sub { $_[0] . " Hz" }, | ||
amp => sub { $_[0] . " dB" }, | ||
func => sub { string("PLUGIN_SIGGEN_" . $_[0]) }, | ||
chan => sub { string("PLUGIN_SIGGEN_" . $_[0]) }, | ||
rate => sub { $_[0] . " kHz" }, | ||
bits => sub { $_[0] } , | ||
}; | ||
|
||
for my $i (0 .. scalar @{$v->{$menu}} - 1) { | ||
push @menu, { | ||
text => $text->{$menu}->($v->{$menu}->[$i]), | ||
radio => $s->{$menu} == $i ? 1 : 0, | ||
actions => { do => { cmd => ['siggen_menu'], params => { $menu => $i } } }, | ||
nextWindow => 'refreshOrigin', | ||
}; | ||
} | ||
} | ||
|
||
if ($title) { | ||
$request->addResult('window', { text => $title }); | ||
} | ||
|
||
$request->addResult('count', scalar @menu); | ||
$request->addResult('offset', 0); | ||
|
||
my $cnt = 0; | ||
|
||
for my $item (@menu) { | ||
$request->setResultLoopHash('item_loop', $cnt++, $item); | ||
} | ||
|
||
$request->setStatusDone; | ||
} | ||
|
||
|
||
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
# SigGen convert - used to avoid processing test signal by flac | ||
|
||
raw wav * * | ||
raw pcm * * | ||
- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.