diff --git a/Readme.adoc b/Readme.adoc
index aae846d..56ed3aa 100644
--- a/Readme.adoc
+++ b/Readme.adoc
@@ -38,8 +38,4 @@ A printout of the thread with those golden informations which kick started me on
== Current State
-As I just started to convert the project to kotlin (the original Java code will remain private as ther is a lot of chaos...)
-the REST interface itself is not yet implemented (also because I do not know which framework I want to use.
-Spring boot seems not to be appropriate anymore along with kotlin and Micronaut seems to be abandonded and my
-current experience with the latter during my professional work life is not so good.
-
+For now things here are pretty basic as I start with implementing all models needed and basic interface access.
diff --git a/docs/hardware/yamaha/RX AX10 VX71 Series Function Tree-1.xls b/docs/hardware/yamaha/RX AX10 VX71 Series Function Tree-1.xls
new file mode 100644
index 0000000..ddeb896
Binary files /dev/null and b/docs/hardware/yamaha/RX AX10 VX71 Series Function Tree-1.xls differ
diff --git a/docs/hardware/yamaha/YXC_API_Spec_Advanced-1.pdf b/docs/hardware/yamaha/YXC_API_Spec_Advanced-1.pdf
new file mode 100644
index 0000000..7328767
Binary files /dev/null and b/docs/hardware/yamaha/YXC_API_Spec_Advanced-1.pdf differ
diff --git a/docs/hardware/yamaha/YXC_API_Spec_Basic.pdf b/docs/hardware/yamaha/YXC_API_Spec_Basic.pdf
new file mode 100644
index 0000000..94ab961
Binary files /dev/null and b/docs/hardware/yamaha/YXC_API_Spec_Basic.pdf differ
diff --git a/docs/hardware/yamaha/rx-v673_dec.xml b/docs/hardware/yamaha/rx-v673_dec.xml
new file mode 100644
index 0000000..75eb342
--- /dev/null
+++ b/docs/hardware/yamaha/rx-v673_dec.xml
@@ -0,0 +1,2968 @@
+
+
+ Title_1
+
+
+
+
+ Param_1
+
+ 1,9,Latin-1
+
+
+
+ Name,Zone=Param_1
+
+ 1,9,Latin-1
+
+
+
+
+
+
+ Param_1
+
+
+
+
+
+ Input,Input_Sel=Param_1
+
+
+
+
+
+
+
+ Param_1
+
+
+
+
+
+ Input,Input_Sel=Param_1
+
+
+
+
+
+
+
+
+
+ Val=Param_1:Exp=Param_2:Unit=Param_3
+
+ -805,165,5
+
+
+ 1
+
+
+ dB
+
+
+
+ Volume,Lvl,Val=Param_1:Volume,Lvl,Exp=Param_2:Volume,Lvl,Unit=Param_3
+
+ -805,165,5
+
+
+ 1
+
+
+ dB
+
+
+
+
+ On
+ Off
+
+ Volume,Mute=Param_1
+
+ On
+ Off
+
+
+
+
+
+
+ On
+ Standby
+
+ Power_Control,Power=Param_1
+
+ On
+ Standby
+
+
+
+
+ Last
+ 120 min
+ 90 min
+ 60 min
+ 30 min
+ Off
+
+ Power_Control,Sleep=Param_1
+
+ 120 min
+ 90 min
+ 60 min
+ 30 min
+ Off
+
+
+
+
+
+
+ Play
+ Pause
+ Stop
+
+
+ Skip Fwd
+ Skip Rev
+
+
+
+
+ Up
+ Down
+ Left
+ Right
+ Return
+ Sel
+ Return to Home
+ On Screen
+ Top Menu
+ Menu
+ Option
+ Display
+
+
+
+
+
+
+ Param_1
+
+ Hall in Munich
+ Hall in Vienna
+ Chamber
+ Cellar Club
+ The Roxy Theatre
+ The Bottom Line
+ Sports
+ Action Game
+ Roleplaying Game
+ Music Video
+ Standard
+ Spectacle
+ Sci-Fi
+ Adventure
+ Drama
+ Mono Movie
+ Surround Decoder
+ 2ch Stereo
+ 7ch Stereo
+
+
+
+ Surround,Program_Sel,Current,Sound_Program=Param_1
+
+ Hall in Munich
+ Hall in Vienna
+ Chamber
+ Cellar Club
+ The Roxy Theatre
+ The Bottom Line
+ Sports
+ Action Game
+ Roleplaying Game
+ Music Video
+ Standard
+ Spectacle
+ Sci-Fi
+ Adventure
+ Drama
+ Mono Movie
+ Surround Decoder
+ 2ch Stereo
+ 7ch Stereo
+
+
+
+
+ On
+ Off
+
+ Surround,Program_Sel,Current,Straight=Param_1
+
+ On
+ Off
+
+
+
+
+ On
+ Off
+
+ Surround,Program_Sel,Current,Enhancer=Param_1
+
+ On
+ Off
+
+
+
+
+
+
+
+ Val=Param_1:Exp=Param_2:Unit=Param_3
+
+ -60,60,5
+
+
+ 1
+
+
+ dB
+
+
+
+ Sound_Video,Tone,Bass,Val=Param_1:Sound_Video,Tone,Bass,Exp=Param_2:Sound_Video,Tone,Bass,Unit=Param_3
+
+ -60,60,5
+
+
+ 1
+
+
+ dB
+
+
+
+
+
+ Val=Param_1:Exp=Param_2:Unit=Param_3
+
+ -60,60,5
+
+
+ 1
+
+
+ dB
+
+
+
+ Sound_Video,Tone,Treble,Val=Param_1:Sound_Video,Tone,Treble,Exp=Param_2:Sound_Video,Tone,Treble,Unit=Param_3
+
+ -60,60,5
+
+
+ 1
+
+
+ dB
+
+
+
+
+
+
+ Val=Param_1:Exp=Param_2:Unit=Param_3
+
+ -60,60,5
+
+
+ 1
+
+
+ dB
+
+
+
+ Volume,Subwoofer_Trim,Val=Param_1:Volume,Subwoofer_Trim,Exp=Param_2:Volume,Subwoofer_Trim,Unit=Param_3
+
+ -60,60,5
+
+
+ 1
+
+
+ dB
+
+
+
+
+ Auto
+ Off
+
+ Sound_Video,Adaptive_DRC=Param_1
+
+ Auto
+ Off
+
+
+
+
+ Auto
+ Off
+
+ Surround,_3D_Cinema_DSP=Param_1
+
+ Auto
+ Off
+
+
+
+
+
+ Param_1
+
+ 0,5,1
+
+
+
+ Sound_Video,Dialogue_Adjust,Dialogue_Lift=Param_1
+
+ 0,5,1
+
+
+
+
+
+ Param_1
+
+ 0,3,1
+
+
+
+ Sound_Video,Dialogue_Adjust,Dialogue_Lvl=Param_1
+
+ 0,3,1
+
+
+
+
+ On
+ Off
+
+ Sound_Video,Pure_Direct,Mode=Param_1
+
+ On
+ Off
+
+
+
+
+
+ Sound_Video,HDMI,Standby_Through_Info=Param_1
+
+ On
+ Off
+
+
+
+
+
+ Main_Zone,Power_Control,Power
+ Main_Zone,Volume,Lvl
+ Main_Zone,Volume,Mute
+ Main_Zone,Input,Input_Sel
+ Main_Zone,Config,Name,Zone
+ Main_Zone,Scene,Scene_Sel
+ Main_Zone,Sound_Video,Tone,Bass
+ Main_Zone,Sound_Video,Tone,Treble
+ Main_Zone,Surround,Program_Sel,Current,Sound_Program
+ Main_Zone,Surround,Program_Sel,Current,Straight
+ Main_Zone,Surround,Program_Sel,Current,Enhancer
+ Main_Zone,Sound_Video,Adaptive_DRC
+ Main_Zone,Surround,_3D_Cinema_DSP
+ Main_Zone,Sound_Video,Dialogue_Adjust,Dialogue_Lift
+ System,Sound_Video,HDMI,Video,Preset_Sel,Current
+ Main_Zone,Sound_Video,Pure_Direct,Mode
+ Main_Zone,List_Control,Cursor
+ Main_Zone,List_Control,Menu_Control
+ Main_Zone,Surround,Enhancer_Type
+ Main_Zone,Sound_Video,Dialogue_Adjust,Dialogue_Lvl
+ Main_Zone,Volume,Subwoofer_Trim
+ Main_Zone,Power_Control,Sleep
+ Main_Zone,Play_Control,Playback
+ Main_Zone,Basic_Status
+ Main_Zone,Input,Input_Sel_Item
+ Main_Zone,Config
+ Main_Zone,Scene,Scene_Sel_Item
+
+
+
+
+
+ Param_1
+
+ 1,9,Latin-1
+
+
+
+ Name,Zone=Param_1
+
+ 1,9,Latin-1
+
+
+
+
+
+ Param_1
+
+
+
+
+
+ Input,Input_Sel=Param_1
+
+
+
+
+
+
+
+
+ Val=Param_1:Exp=Param_2:Unit=Param_3
+
+ -805,165,5
+
+
+ 1
+
+
+ dB
+
+
+
+ Volume,Lvl,Val=Param_1:Volume,Lvl,Exp=Param_2:Volume,Lvl,Unit=Param_3
+
+ -805,165,5
+
+
+ 1
+
+
+ dB
+
+
+
+
+ On
+ Off
+
+ Volume,Mute=Param_1
+
+ On
+ Off
+
+
+
+
+
+ Volume,Output_Info=Param_1
+
+ Fixed
+ Variable
+
+
+
+
+
+
+ On
+ Standby
+
+ Power_Control,Power=Param_1
+
+ On
+ Standby
+
+
+
+
+ Last
+ 120 min
+ 90 min
+ 60 min
+ 30 min
+ Off
+
+ Power_Control,Sleep=Param_1
+
+ 120 min
+ 90 min
+ 60 min
+ 30 min
+ Off
+
+
+
+
+
+
+ Play
+ Pause
+ Stop
+
+
+ Skip Fwd
+ Skip Rev
+
+
+
+ Zone_2,Power_Control,Power
+ Zone_2,Volume,Lvl
+ Zone_2,Volume,Mute
+ Zone_2,Input,Input_Sel
+ Zone_2,Config,Name,Zone
+ Zone_2,Scene,Scene_Sel
+ Zone_2,Sound_Video,Tone,Bass
+ Zone_2,Sound_Video,Tone,Treble
+ Zone_2,List_Control,Cursor
+ Zone_2,List_Control,Menu_Control
+ Zone_2,Volume,Output
+ Zone_2,Power_Control,Sleep
+ Zone_2,Play_Control,Playback
+ Zone_2,Basic_Status
+ Zone_2,Input,Input_Sel_Item
+ Zone_2,Config
+ Zone_2,Scene,Scene_Sel_Item
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+
+ Auto Up
+ Auto Down
+ Cancel
+
+ Tuning,Freq,AM,Val=Param_1:Tuning,Freq,AM,Exp=Param_2:Tuning,Freq,AM,Unit=Param_3
+
+ Auto Up
+ Auto Down
+ 531,1611,9
+
+
+
+ 0
+
+
+
+ kHz
+
+
+
+
+ Auto Up
+ Auto Down
+ Cancel
+
+ Tuning,Freq,FM,Val=Param_1:Tuning,Freq,FM,Exp=Param_2:Tuning,Freq,FM,Unit=Param_3
+
+ Auto Up
+ Auto Down
+ TP Up
+ TP Down
+ 8750,10800,5
+
+
+
+ 2
+
+
+
+ MHz
+
+
+
+
+ TP Up
+ TP Down
+ Cancel
+
+ Tuning,Freq,FM,Val=Param_1:Tuning,Freq,FM,Exp=Param_2:Tuning,Freq,FM,Unit=Param_3
+
+ Auto Up
+ Auto Down
+ TP Up
+ TP Down
+ 8750,10800,5
+
+
+
+ 2
+
+
+
+ MHz
+
+
+
+
+ Up
+ Down
+
+ Preset,Preset_Sel=Param_1
+
+
+
+
+
+
+
+ AM
+ FM
+
+ Tuning,Band=Param_1
+
+ AM
+ FM
+
+
+
+
+
+
+ Val=Param_1:Exp=Param_2:Unit=Param_3
+
+ 531,1611,9
+
+
+ 0
+
+
+ kHz
+
+
+
+ Tuning,Freq,AM,Val=Param_1:Tuning,Freq,AM,Exp=Param_2:Tuning,Freq,AM,Unit=Param_3
+
+ Auto Up
+ Auto Down
+ 531,1611,9
+
+
+
+ 0
+
+
+
+ kHz
+
+
+
+
+
+ Val=Param_1:Exp=Param_2:Unit=Param_3
+
+ 8750,10800,5
+
+
+ 2
+
+
+ MHz
+
+
+
+ Tuning,Freq,FM,Val=Param_1:Tuning,Freq,FM,Exp=Param_2:Tuning,Freq,FM,Unit=Param_3
+
+ Auto Up
+ Auto Down
+ TP Up
+ TP Down
+ 8750,10800,5
+
+
+
+ 2
+
+
+
+ MHz
+
+
+
+
+
+
+ Param_1
+
+
+
+
+
+ Preset,Preset_Sel=Param_1
+
+
+
+
+
+
+
+
+
+ Tuning,Band=Param_1
+
+ AM
+ FM
+
+
+
+
+
+ Tuning,Freq,Current,Val=Param_1:Tuning,Freq,Current,Exp=Param_2:Tuning,Freq,Current,Unit=Param_3
+
+ Auto Up
+ Auto Down
+ TP Up
+ TP Down
+ 531,1611,9
+ 8750,10800,5
+
+
+
+ 0
+ 2
+
+
+
+ kHz
+ MHz
+
+
+
+
+
+ Meta_Info,Program_Type=Param_1
+
+ 0,8,Ascii
+
+
+
+
+
+ Meta_Info,Program_Service=Param_1
+
+ 0,8,Ascii
+
+
+
+
+
+ Meta_Info,Radio_Text_A=Param_1
+
+ 0,64,Ascii
+
+
+
+
+
+ Meta_Info,Radio_Text_B=Param_1
+
+ 0,64,Ascii
+
+
+
+
+
+ Meta_Info,Clock_Time=Param_1
+
+ 0,5,Ascii
+
+
+
+
+
+
+ Signal_Info,Tuned=Param_1
+
+ Negate
+ Assert
+
+
+
+
+
+ Signal_Info,Stereo=Param_1
+
+ Negate
+ Assert
+
+
+
+
+
+
+
+ "Play Info."
+
+
+ "Play Info."
+ "Play Control","Frequency","AM"
+ "Play Control","Frequency","FM"
+ "Play Control","Preset"
+
+
+
+
+
+ Tuner,Play_Control,Search_Mode
+ Tuner,Play_Control,Preset,Preset_Sel
+ Tuner,Play_Control,Tuning,Band
+ Tuner,Play_Control,Tuning,Freq
+ Tuner,Play_Control,Auto_Freq
+ Tuner,Play_Control,Tuning,Freq,FM
+ Tuner,Play_Control,Tuning,Freq,AM
+ Tuner,Play_Control,Tuning,Freq,FM,Val
+ Tuner,Play_Control,Tuning,Freq,AM,Val
+ Tuner,Play_Info
+ Tuner,Config
+ Tuner,Play_Control,Preset,Preset_Sel_Item
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Play
+ Pause
+
+ Playback_Info=Param_1
+
+ Play
+ Stop
+
+
+
+
+ Skip Fwd
+ Skip Rev
+
+
+
+
+
+ Meta_Info,Artist=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Album=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Song=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Playback_Info=Param_1
+
+ Play
+ Stop
+
+
+
+
+
+ Album_ART,URL=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Album_ART,ID=Param_1
+
+ 0,255,1
+
+
+
+
+
+ Album_ART,Format=Param_1
+
+ BMP
+ YMF
+
+
+
+
+
+ Input_Logo,URL_S=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ "List Browse"
+ "Play Info."
+
+
+ "Play Info."
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+
+
+
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Info."
+
+
+
+
+ Play
+
+
+ Pause
+
+
+ Stop
+
+
+ Skip Fwd
+
+
+ Skip Rev
+
+
+
+ AirPlay,Play_Control,Playback
+ AirPlay,Play_Info
+ AirPlay,Config
+
+
+
+
+ Extended
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Off
+ One
+ All
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+ Off
+ Songs
+ Albums
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ Songs
+ Albums
+
+
+
+
+ Play
+ Pause
+ Stop
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+ Skip Fwd
+ Skip Rev
+
+
+
+
+
+ Meta_Info,Artist=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Album=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Song=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ Songs
+ Albums
+
+
+
+
+
+ Album_ART,URL=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Album_ART,ID=Param_1
+
+ 0,255,1
+
+
+
+
+
+ Album_ART,Format=Param_1
+
+ BMP
+ YMF
+
+
+
+
+
+
+
+
+ Param_1
+
+ 1,8,1,Line_%
+
+
+
+
+ Up
+ Down
+ Return
+ Sel
+ Return to Home
+
+
+
+ Param_1
+
+ 1,65536,1
+
+
+
+
+ Up
+ Down
+
+
+
+
+
+ Menu_Status=Param_1
+
+ Ready
+ Busy
+
+
+
+
+
+ Menu_Layer=Param_1
+
+ 1,16,1
+
+
+
+
+
+ Menu_Name=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Line_1
+
+ Current_List,Line_1,Txt=Param_1:Current_List,Line_1,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_2
+
+ Current_List,Line_2,Txt=Param_1:Current_List,Line_2,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_3
+
+ Current_List,Line_3,Txt=Param_1:Current_List,Line_3,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_4
+
+ Current_List,Line_4,Txt=Param_1:Current_List,Line_4,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_5
+
+ Current_List,Line_5,Txt=Param_1:Current_List,Line_5,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_6
+
+ Current_List,Line_6,Txt=Param_1:Current_List,Line_6,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_7
+
+ Current_List,Line_7,Txt=Param_1:Current_List,Line_7,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_8
+
+ Current_List,Line_8,Txt=Param_1:Current_List,Line_8,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+
+
+ Cursor_Position,Current_Line=Param_1
+
+ 1,65536,1
+
+
+
+
+
+ Cursor_Position,Max_Line=Param_1
+
+ 0,65536,1
+
+
+
+
+
+
+ "List Browse"
+ "Play Info."
+
+
+ "Play Info."
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+
+
+
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Info."
+
+
+
+
+ Play
+
+
+ Pause
+
+
+ Stop
+
+
+ Skip Fwd
+
+
+ Skip Rev
+
+
+
+ iPod_USB,Play_Control,Playback
+ iPod_USB,List_Control,Direct_Sel
+ iPod_USB,List_Control,Jump_Line
+ iPod_USB,List_Control,Cursor
+ iPod_USB,List_Control,Page
+ iPod_USB,List_Control,Others
+ iPod_USB,Play_Control,Play_Mode,Repeat
+ iPod_USB,Play_Control,Play_Mode,Shuffle
+ iPod_USB,Play_Control,iPod_Mode
+ iPod_USB,Play_Info
+ iPod_USB,List_Info
+ iPod_USB,Config
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Off
+ One
+ All
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+ Off
+ On
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ On
+
+
+
+
+ Play
+ Pause
+ Stop
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+ Skip Fwd
+ Skip Rev
+
+
+
+
+
+ Meta_Info,Artist=Param_1
+
+ 0,64,UTF-8
+
+
+
+
+
+ Meta_Info,Album=Param_1
+
+ 0,64,UTF-8
+
+
+
+
+
+ Meta_Info,Song=Param_1
+
+ 0,64,UTF-8
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ On
+
+
+
+
+
+ Album_ART,URL=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Album_ART,ID=Param_1
+
+ 0,255,1
+
+
+
+
+
+ Album_ART,Format=Param_1
+
+ BMP
+ YMF
+
+
+
+
+
+
+
+
+ Param_1
+
+ 1,8,1,Line_%
+
+
+
+
+ Up
+ Down
+ Return
+ Sel
+ Return to Home
+
+
+
+ Param_1
+
+ 1,65536,1
+
+
+
+
+ Up
+ Down
+
+
+
+
+
+ Menu_Status=Param_1
+
+ Ready
+ Busy
+
+
+
+
+
+ Menu_Layer=Param_1
+
+ 1,16,1
+
+
+
+
+
+ Menu_Name=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Line_1
+
+ Current_List,Line_1,Txt=Param_1:Current_List,Line_1,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_2
+
+ Current_List,Line_2,Txt=Param_1:Current_List,Line_2,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_3
+
+ Current_List,Line_3,Txt=Param_1:Current_List,Line_3,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_4
+
+ Current_List,Line_4,Txt=Param_1:Current_List,Line_4,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_5
+
+ Current_List,Line_5,Txt=Param_1:Current_List,Line_5,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_6
+
+ Current_List,Line_6,Txt=Param_1:Current_List,Line_6,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_7
+
+ Current_List,Line_7,Txt=Param_1:Current_List,Line_7,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_8
+
+ Current_List,Line_8,Txt=Param_1:Current_List,Line_8,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+
+
+ Cursor_Position,Current_Line=Param_1
+
+ 1,65536,1
+
+
+
+
+
+ Cursor_Position,Max_Line=Param_1
+
+ 0,65536,1
+
+
+
+
+
+
+ "Play Info."
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Control","Preset"
+
+
+ "List Browse"
+ "Play Info."
+
+
+
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Info."
+
+
+
+
+ Play
+
+
+ Stop
+
+
+ Skip Fwd
+
+
+ Skip Rev
+
+
+
+ USB,Play_Control,Play_Mode,Repeat
+ USB,Play_Control,Play_Mode,Shuffle
+ USB,Play_Control,Playback
+ USB,Play_Control,Preset,Preset_Sel
+ USB,List_Control,Direct_Sel
+ USB,List_Control,Jump_Line
+ USB,List_Control,Cursor
+ USB,List_Control,Page
+ USB,Play_Info
+ USB,List_Info
+ USB,Config
+ USB,Play_Control,Preset,Preset_Sel_Item
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Play
+ Stop
+
+ Playback_Info=Param_1
+
+ Play
+ Stop
+
+
+
+
+
+
+
+ Meta_Info,Station=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Album=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Song=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Playback_Info=Param_1
+
+ Play
+ Stop
+
+
+
+
+
+ Album_ART,URL=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Album_ART,ID=Param_1
+
+ 0,255,1
+
+
+
+
+
+ Album_ART,Format=Param_1
+
+ BMP
+ YMF
+
+
+
+
+
+
+
+
+ Param_1
+
+ 1,8,1,Line_%
+
+
+
+
+ Up
+ Down
+ Return
+ Sel
+ Return to Home
+
+
+
+ Param_1
+
+ 1,65536,1
+
+
+
+
+ Up
+ Down
+
+
+
+
+
+ Menu_Status=Param_1
+
+ Ready
+ Busy
+
+
+
+
+
+ Menu_Layer=Param_1
+
+ 1,16,1
+
+
+
+
+
+ Menu_Name=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Line_1
+
+ Current_List,Line_1,Txt=Param_1:Current_List,Line_1,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_2
+
+ Current_List,Line_2,Txt=Param_1:Current_List,Line_2,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_3
+
+ Current_List,Line_3,Txt=Param_1:Current_List,Line_3,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_4
+
+ Current_List,Line_4,Txt=Param_1:Current_List,Line_4,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_5
+
+ Current_List,Line_5,Txt=Param_1:Current_List,Line_5,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_6
+
+ Current_List,Line_6,Txt=Param_1:Current_List,Line_6,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_7
+
+ Current_List,Line_7,Txt=Param_1:Current_List,Line_7,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_8
+
+ Current_List,Line_8,Txt=Param_1:Current_List,Line_8,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+
+
+ Cursor_Position,Current_Line=Param_1
+
+ 1,65536,1
+
+
+
+
+
+ Cursor_Position,Max_Line=Param_1
+
+ 0,65536,1
+
+
+
+
+
+
+ "Play Info."
+ "Play Control","Preset"
+
+
+ "List Browse"
+ "Play Info."
+
+
+
+ "Play Info."
+
+
+
+
+ Play
+
+
+ Stop
+
+
+
+ NET_RADIO,Play_Control,Playback
+ NET_RADIO,List_Control,Direct_Sel
+ NET_RADIO,List_Control,Jump_Line
+ NET_RADIO,List_Control,Cursor
+ NET_RADIO,List_Control,Page
+ NET_RADIO,Play_Control,Preset,Preset_Sel
+ NET_RADIO,List_Control,Bookmark
+ NET_RADIO,Play_Info
+ NET_RADIO,List_Info
+ NET_RADIO,Config
+ NET_RADIO,Play_Control,Preset,Preset_Sel_Item
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Off
+ One
+ All
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+ Off
+ On
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ On
+
+
+
+
+ Play
+ Pause
+ Stop
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+ Skip Fwd
+ Skip Rev
+
+
+
+
+
+ Meta_Info,Artist=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Album=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Song=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ On
+
+
+
+
+
+ Album_ART,URL=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Album_ART,ID=Param_1
+
+ 0,255,1
+
+
+
+
+
+ Album_ART,Format=Param_1
+
+ BMP
+ YMF
+
+
+
+
+
+
+
+
+ Param_1
+
+ 1,8,1,Line_%
+
+
+
+
+ Up
+ Down
+ Return
+ Sel
+ Return to Home
+
+
+
+ Param_1
+
+ 1,65536,1
+
+
+
+
+ Up
+ Down
+
+
+
+
+
+ Menu_Status=Param_1
+
+ Ready
+ Busy
+
+
+
+
+
+ Menu_Layer=Param_1
+
+ 1,16,1
+
+
+
+
+
+ Menu_Name=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Line_1
+
+ Current_List,Line_1,Txt=Param_1:Current_List,Line_1,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_2
+
+ Current_List,Line_2,Txt=Param_1:Current_List,Line_2,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_3
+
+ Current_List,Line_3,Txt=Param_1:Current_List,Line_3,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_4
+
+ Current_List,Line_4,Txt=Param_1:Current_List,Line_4,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_5
+
+ Current_List,Line_5,Txt=Param_1:Current_List,Line_5,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_6
+
+ Current_List,Line_6,Txt=Param_1:Current_List,Line_6,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_7
+
+ Current_List,Line_7,Txt=Param_1:Current_List,Line_7,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+ Line_8
+
+ Current_List,Line_8,Txt=Param_1:Current_List,Line_8,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+
+
+
+
+
+
+ Cursor_Position,Current_Line=Param_1
+
+ 1,65536,1
+
+
+
+
+
+ Cursor_Position,Max_Line=Param_1
+
+ 0,65536,1
+
+
+
+
+
+
+ "Play Info."
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Control","Preset"
+
+
+ "List Browse"
+ "Play Info."
+
+
+
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Info."
+
+
+
+
+ Play
+
+
+ Pause
+
+
+ Stop
+
+
+ Skip Fwd
+
+
+ Skip Rev
+
+
+
+ SERVER,Play_Control,Play_Mode,Repeat
+ SERVER,Play_Control,Play_Mode,Shuffle
+ SERVER,Play_Control,Playback
+ SERVER,Play_Control,Preset,Preset_Sel
+ SERVER,List_Control,Direct_Sel
+ SERVER,List_Control,Jump_Line
+ SERVER,List_Control,Cursor
+ SERVER,List_Control,Page
+ SERVER,Play_Control,Play_URI
+ SERVER,Play_Info
+ SERVER,List_Info
+ SERVER,Config
+ SERVER,Play_Control,Preset,Preset_Sel_Item
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Off
+ One
+ All
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+ Off
+ On
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ On
+
+
+
+
+ Play
+ Pause
+ Stop
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+ Skip Fwd
+ Skip Rev
+
+
+
+
+
+ Meta_Info,Artist=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Album=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Meta_Info,Song=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Feature_Availability=Param_1
+
+ Ready
+ Not Ready
+
+
+
+
+
+ Playback_Info=Param_1
+
+ Play
+ Pause
+ Stop
+
+
+
+
+
+ Play_Mode,Repeat=Param_1
+
+ Off
+ One
+ All
+
+
+
+
+
+ Play_Mode,Shuffle=Param_1
+
+ Off
+ On
+
+
+
+
+
+ Album_ART,URL=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Album_ART,ID=Param_1
+
+ 0,255,1
+
+
+
+
+
+ Album_ART,Format=Param_1
+
+ BMP
+ YMF
+
+
+
+
+
+ Input_Logo,URL_S=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+
+
+
+ Param_1
+
+ 1,8,1,Line_%
+
+
+
+
+
+ Line=Param_1:Keyword=Param_2
+
+ 1,8,1,Line_%
+
+
+ 0,30,Ascii
+
+
+
+
+ Up
+ Down
+ Return
+ Sel
+ Return to Home
+
+
+
+ Param_1
+
+ 1,65536,1
+
+
+
+
+ Up
+ Down
+
+
+
+
+
+ Menu_Status=Param_1
+
+ Ready
+ Busy
+
+
+
+
+
+ Menu_Layer=Param_1
+
+ 1,16,1
+
+
+
+
+
+ Menu_Name=Param_1
+
+ 0,128,UTF-8
+
+
+
+
+
+ Line_1
+
+ Current_List,Line_1,Txt=Param_1:Current_List,Line_1,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+ Line_2
+
+ Current_List,Line_2,Txt=Param_1:Current_List,Line_2,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+ Line_3
+
+ Current_List,Line_3,Txt=Param_1:Current_List,Line_3,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+ Line_4
+
+ Current_List,Line_4,Txt=Param_1:Current_List,Line_4,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+ Line_5
+
+ Current_List,Line_5,Txt=Param_1:Current_List,Line_5,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+ Line_6
+
+ Current_List,Line_6,Txt=Param_1:Current_List,Line_6,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+ Line_7
+
+ Current_List,Line_7,Txt=Param_1:Current_List,Line_7,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+ Line_8
+
+ Current_List,Line_8,Txt=Param_1:Current_List,Line_8,Attribute=Param_2
+
+ 0,128,UTF-8
+
+
+ Container
+ Unplayable Item
+ Item
+ Unselectable
+ Keyword
+
+
+
+
+
+
+ Cursor_Position,Current_Line=Param_1
+
+ 1,65536,1
+
+
+
+
+
+ Cursor_Position,Max_Line=Param_1
+
+ 0,65536,1
+
+
+
+
+
+
+ "Play Info."
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Control","Preset"
+
+
+ "List Browse"
+ "Play Info."
+
+
+
+ "Play Control","Shuffle"
+ "Play Control","Repeat"
+ "Play Info."
+
+
+
+
+ Play
+
+
+ Pause
+
+
+ Stop
+
+
+ Skip Fwd
+
+
+ Skip Rev
+
+
+
+ Napster,Play_Control,Play_Mode,Repeat
+ Napster,Play_Control,Play_Mode,Shuffle
+ Napster,Play_Control,Playback
+ Napster,Play_Control,Preset,Preset_Sel
+ Napster,List_Control,Direct_Sel
+ Napster,List_Control,Jump_Line
+ Napster,List_Control,Cursor
+ Napster,List_Control,Page
+ Napster,List_Control,Direct_Sel_with_Keyword
+ Napster,Play_Info
+ Napster,List_Info
+ Napster,Config
+ Napster,Play_Control,Preset,Preset_Sel_Item
+
+
+
\ No newline at end of file
diff --git a/klanglicht-core/pom.xml b/klanglicht-core/pom.xml
index b3cb5fa..5a2e6a6 100644
--- a/klanglicht-core/pom.xml
+++ b/klanglicht-core/pom.xml
@@ -16,56 +16,6 @@
${revision}
-
-
-
- org.apache.commons
- commons-lang3
- 3.12.0
-
-
- commons-codec
- commons-codec
- 1.15
-
-
- com.google.guava
- guava
- 31.1-jre
-
-
-
-
- com.fasterxml.jackson.core
- jackson-core
- ${version.jackson}
-
-
- com.fasterxml.jackson.core
- jackson-annotations
- ${version.jackson}
-
-
- com.fasterxml.jackson.core
- jackson-databind
- ${version.jackson}
-
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-xml
- ${version.jackson}
-
-
- com.fasterxml.jackson.module
- jackson-module-kotlin
- ${version.jackson}
-
-
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
- ${version.jackson}
-
-
io.github.java-native
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterface.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterface.kt
index dc8ea41..f764e99 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterface.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterface.kt
@@ -1,5 +1,7 @@
package de.visualdigits.kotlin.klanglicht.dmx
+import de.visualdigits.kotlin.klanglicht.model.dmx.DMXInterfaceType
+import de.visualdigits.kotlin.klanglicht.model.dmx.DmxFrame
import jssc.SerialPort
import jssc.SerialPortException
import org.apache.commons.lang3.StringUtils
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/Color.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/Color.kt
index b8784d3..53104c7 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/Color.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/Color.kt
@@ -1,6 +1,8 @@
package de.visualdigits.kotlin.klanglicht.model.color
-interface Color {
+import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
+
+interface Color> : Parameter {
fun value(): Long
@@ -17,6 +19,4 @@ interface Color {
fun toRGBW(): RGBWColor
fun toRGBA(): RGBAColor
-
- fun toColorParameter(): ColorParameter
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/ColorParameter.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/ColorParameter.kt
deleted file mode 100644
index 288c97b..0000000
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/ColorParameter.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-package de.visualdigits.kotlin.klanglicht.model.color
-
-import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
-import org.apache.commons.lang3.StringUtils
-
-
-data class ColorParameter(
- val red: Int = 0,
- val green: Int = 0,
- val blue: Int = 0,
- val white: Int = 0,
- val amber: Int = 0,
-) : Parameter(), Color {
-
- init {
- parameterMap.putAll(mapOf(
- "Red" to red,
- "Green" to green,
- "Blue" to blue,
- "White" to white,
- "Amber" to amber
- ))
- }
-
- inline fun color(): T {
- return when (T::class) {
- RGBWAColor::class -> RGBWAColor(red, green, blue, white, amber) as T
- RGBWColor::class -> RGBWColor(red, green, blue, white) as T
- RGBAColor::class -> RGBAColor(red, green, blue, amber) as T
- else -> RGBColor(red, green, blue) as T
- }
- }
-
- fun mix(other: Color, factor: Double): ColorParameter {
- val mixedColor = color().mix(other, factor)
- return ColorParameter(
- red = mixedColor.red,
- green = mixedColor.green,
- blue = mixedColor.blue,
- white = mixedColor.white
- )
- }
-
- override fun value(): Long = red.toLong() shl 16 or (green.toLong() shl 8) or blue.toLong()
-
- override fun hex(): String = StringUtils.leftPad(java.lang.Long.toHexString(value()), 6, '0')
-
- override fun web(): String = "#${hex()}"
-
- override fun ansiColor(): String = "\u001B[39m\u001B[48;2;$red;$green;${blue}m \u001B[0m"
-
- override fun toRGB(): RGBColor {
- return color()
- }
-
- override fun toHSV(): HSVColor {
- return color().toHSV()
- }
-
- override fun toRGBW(): RGBWColor {
- return color()
- }
-
- override fun toRGBA(): RGBAColor {
- return color()
- }
-
- override fun toColorParameter(): ColorParameter {
- return this
- }
-}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/HSVColor.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/HSVColor.kt
index 05850c1..2609dd1 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/HSVColor.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/HSVColor.kt
@@ -1,6 +1,9 @@
package de.visualdigits.kotlin.klanglicht.model.color
+import de.visualdigits.kotlin.klanglicht.model.parameter.IntParameter
+import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
import org.apache.commons.lang3.StringUtils
+import java.lang.IllegalArgumentException
import kotlin.math.floor
import kotlin.math.roundToInt
@@ -11,7 +14,7 @@ class HSVColor(
var s: Int = 0,
/** 0 -100 */
var v: Int = 0
-) : Color {
+) : Color {
override fun toString(): String {
return "[" + StringUtils.join(listOf(h, s, v), ", ") + "]"
@@ -21,6 +24,21 @@ class HSVColor(
return "RGBColor(hex='${web()}', h=$h, s=$s , v=$v)"
}
+ override fun parameterMap(): Map {
+ val rgbColor = toRGB()
+ return mapOf(
+ "Red" to rgbColor.red,
+ "Green" to rgbColor.green,
+ "Blue" to rgbColor.blue,
+ )
+ }
+
+ override fun fade(other: Parameter<*>, factor: Double): HSVColor {
+ return if (other is HSVColor) {
+ other.toRGB().fade(other.toRGB(), factor).toHSV()
+ } else throw IllegalArgumentException("Cannot fade different parameter type")
+ }
+
override fun toRGB(): RGBColor {
val h = (this.h / 360.0)
val s = (this.s / 100.0)
@@ -51,10 +69,6 @@ class HSVColor(
)
}
- inline fun mix(other: Color, factor: Double): T {
- return toRGB().mix(other, factor)
- }
-
override fun value(): Long {
return toRGB().value()
}
@@ -82,8 +96,4 @@ class HSVColor(
override fun toRGBA(): RGBAColor {
return toRGB().toRGBA()
}
-
- override fun toColorParameter(): ColorParameter {
- return toRGB().toColorParameter()
- }
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/NamedParameter.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/NamedParameter.kt
deleted file mode 100644
index 27cad0d..0000000
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/NamedParameter.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package de.visualdigits.kotlin.klanglicht.model.color
-
-import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
-
-class NamedParameter(
- val name: String,
- val value: Int = 0
-) : Parameter() {
-
- init {
- parameterMap.put(name, value)
- }
-}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBAColor.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBAColor.kt
index 03392a8..bc35fbb 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBAColor.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBAColor.kt
@@ -1,6 +1,8 @@
package de.visualdigits.kotlin.klanglicht.model.color
+import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
import org.apache.commons.lang3.StringUtils
+import java.lang.IllegalArgumentException
import kotlin.math.min
import kotlin.math.roundToInt
import java.lang.Long.decode
@@ -10,7 +12,7 @@ class RGBAColor(
green: Int = 0,
blue: Int = 0,
var amber: Int = 0
-) : RGBColor(red, green, blue) {
+) : RGBBaseColor(red, green, blue) {
companion object {
const val AMBER_RED = 255.0
@@ -35,12 +37,22 @@ class RGBAColor(
return "RGBColor(hex='${web()}', r=$red, g=$green , b=$blue, a=$amber)"
}
- override fun toRGB(): RGBColor {
- return RGBColor(
- red = min(255, red + (amber / AMBER_FACTOR).roundToInt()),
- green = min(255, green + (amber * AMBER_FACTOR).roundToInt()),
- blue = blue
- )
+ override fun parameterMap(): Map = mapOf(
+ "Red" to red,
+ "Green" to green,
+ "Blue" to blue,
+ "Amber" to amber
+ )
+
+ override fun fade(other: Parameter<*>, factor: Double): RGBAColor {
+ return if (other is RGBAColor) {
+ RGBAColor(
+ red = min(255, (red + factor * (other.red - red)).roundToInt()),
+ green = min(255, (green + factor * (other.green - green)).roundToInt()),
+ blue = min(255, (blue + factor * (other.blue - blue)).roundToInt()),
+ amber = min(255, (amber + factor * (other.amber - amber)).roundToInt())
+ )
+ } else throw IllegalArgumentException("Cannot fade different parameter type")
}
override fun value(): Long = (red.toLong() shl 24) or (green.toLong() shl 16) or (blue.toLong() shl 8) or amber.toLong()
@@ -53,6 +65,14 @@ class RGBAColor(
return toRGB().ansiColor()
}
+ override fun toRGB(): RGBColor {
+ return RGBColor(
+ red = min(255, red + (amber / AMBER_FACTOR).roundToInt()),
+ green = min(255, green + (amber * AMBER_FACTOR).roundToInt()),
+ blue = blue
+ )
+ }
+
override fun toHSV(): HSVColor {
return toRGB().toHSV()
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBBaseColor.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBBaseColor.kt
new file mode 100644
index 0000000..2248824
--- /dev/null
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBBaseColor.kt
@@ -0,0 +1,139 @@
+package de.visualdigits.kotlin.klanglicht.model.color
+
+import org.apache.commons.lang3.StringUtils
+import java.lang.Long.decode
+import java.lang.Long.toHexString
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.roundToInt
+
+
+abstract class RGBBaseColor>(
+ var red: Int = 0,
+ var green: Int = 0,
+ var blue: Int = 0
+) : Color {
+
+ constructor(value: Long) : this(
+ red = min(a = 255, b = (value and 0x00ff0000L shr 16).toInt()),
+ green = min(a = 255, b = (value and 0x0000ff00L shr 8).toInt()),
+ blue = min(a = 255, b = (value and 0x000000ffL).toInt())
+ )
+
+ constructor(hex: String) : this(decode(if (hex.startsWith("#") || hex.startsWith("0x")) hex else "#$hex"))
+
+ override fun toString(): String {
+ return "[" + StringUtils.join(listOf(red, green, blue), ", ") + "]"
+ }
+
+ open fun repr(): String {
+ return "RGBColor(hex='${web()}', r=$red, g=$green , b=$blue)"
+ }
+
+ override fun value(): Long = red.toLong() shl 16 or (green.toLong() shl 8) or blue.toLong()
+
+ override fun hex(): String = StringUtils.leftPad(toHexString(value()), 6, '0')
+
+ override fun web(): String = "#${hex()}"
+
+ override fun ansiColor(): String = "\u001B[39m\u001B[48;2;$red;$green;${blue}m \u001B[0m"
+
+ inline fun > convert(): T {
+ return when (T::class) {
+ RGBWColor::class -> toRGBW() as T
+ RGBAColor::class -> toRGBA() as T
+ HSVColor::class -> toHSV() as T
+ RGBBaseColor::class -> toRGB() as T
+ else -> throw IllegalStateException("Unsupported color type")
+ }
+ }
+
+ override fun toRGB(): RGBColor {
+ return RGBColor(
+ red = red,
+ green = green,
+ blue = blue
+ )
+ }
+
+ override fun toHSV(): HSVColor {
+ val r = red.toDouble() / 255
+ val g = green.toDouble() / 255
+ val b = blue.toDouble() / 255
+ val min = min(r, min(g, b))
+ val max = max(r, max(g, b))
+ val delta = max - min
+ val s: Double
+ var h: Double
+ if (max == 0.0) {
+ s = 0.0
+ h = 0.0
+ } else {
+ s = delta / max
+ h = if (r == max) {
+ (g - b) / delta
+ } else if (g == max) {
+ 2 + (b - r) / delta
+ } else {
+ 4 + (r - g) / delta
+ }
+ h *= 60.0
+ if (h < 0) {
+ h += 360.0
+ }
+ if (java.lang.Double.isNaN(h)) {
+ h = 0.0
+ }
+ }
+ return HSVColor(h.toInt(), (100 * s).toInt(), (100 * max).toInt())
+ }
+
+ override fun toRGBW(): RGBWColor {
+ val white = min(red, min(green, blue))
+ return RGBWColor(
+ red = red - white,
+ green = green - white,
+ blue = blue - white,
+ white = white
+ )
+ }
+
+ override fun toRGBA(): RGBAColor {
+ val amber: Int
+ var r = 0
+ var g = 0
+ if (red > green) {
+ amber = green
+ g = 0
+ r -= (amber / RGBAColor.AMBER_FACTOR).roundToInt()
+ } else {
+ amber = red
+ r = 0
+ g -= (amber * RGBAColor.AMBER_FACTOR).roundToInt()
+ }
+ return RGBAColor(
+ red = r - amber,
+ green = g - amber,
+ blue = blue,
+ amber = amber
+ )
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as RGBBaseColor<*>
+
+ if (red != other.red) return false
+ if (green != other.green) return false
+ return blue == other.blue
+ }
+
+ override fun hashCode(): Int {
+ var result = red
+ result = 31 * result + green
+ result = 31 * result + blue
+ return result
+ }
+}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBColor.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBColor.kt
index c44cd1d..063a9d0 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBColor.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBColor.kt
@@ -1,156 +1,30 @@
package de.visualdigits.kotlin.klanglicht.model.color
-import org.apache.commons.lang3.StringUtils
-import java.lang.Long.decode
-import java.lang.Long.toHexString
-import kotlin.math.max
+import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
+import java.lang.IllegalArgumentException
import kotlin.math.min
import kotlin.math.roundToInt
-open class RGBColor(
- var red: Int = 0,
- var green: Int = 0,
- var blue: Int = 0
-) : Color {
+class RGBColor(
+ red: Int = 0,
+ green: Int = 0,
+ blue: Int = 0
+) : RGBBaseColor(red, green, blue) {
- constructor(value: Long) : this(
- red = min(a = 255, b = (value and 0x00ff0000L shr 16).toInt()),
- green = min(a = 255, b = (value and 0x0000ff00L shr 8).toInt()),
- blue = min(a = 255, b = (value and 0x000000ffL).toInt())
+ override fun parameterMap(): Map = mapOf(
+ "Red" to red,
+ "Green" to green,
+ "Blue" to blue,
)
- override fun toString(): String {
- return "[" + StringUtils.join(listOf(red, green, blue), ", ") + "]"
- }
-
- open fun repr(): String {
- return "RGBColor(hex='${web()}', r=$red, g=$green , b=$blue)"
- }
-
- constructor(hex: String) : this(decode(if (hex.startsWith("#") || hex.startsWith("0x")) hex else "#$hex"))
-
- override fun value(): Long = red.toLong() shl 16 or (green.toLong() shl 8) or blue.toLong()
-
- override fun hex(): String = StringUtils.leftPad(toHexString(value()), 6, '0')
-
- override fun web(): String = "#${hex()}"
-
- override fun ansiColor(): String = "\u001B[39m\u001B[48;2;$red;$green;${blue}m \u001B[0m"
-
- inline fun mix(other: Color, factor: Double): T {
- val thisRGB = toRGB()
- val otherRGB = other.toRGB()
- val rgb = RGBColor(
- red = min(255, (thisRGB.red + factor * (otherRGB.red - thisRGB.red)).roundToInt()),
- green = min(255, (thisRGB.green + factor * (otherRGB.green - thisRGB.green)).roundToInt()),
- blue = min(255, (thisRGB.blue + factor * (otherRGB.blue - thisRGB.blue)).roundToInt())
- )
- return rgb.convert()
- }
-
- inline fun convert(): T {
- return when (T::class) {
- RGBWColor::class -> toRGBW() as T
- RGBAColor::class -> toRGBA() as T
- HSVColor::class -> toHSV() as T
- ColorParameter::class -> toColorParameter() as T
- else -> toRGB() as T
- }
- }
-
- override fun toRGB(): RGBColor {
- return this
- }
-
- override fun toHSV(): HSVColor {
- val r = red.toDouble() / 255
- val g = green.toDouble() / 255
- val b = blue.toDouble() / 255
- val min = min(r, min(g, b))
- val max = max(r, max(g, b))
- val delta = max - min
- val s: Double
- var h: Double
- if (max == 0.0) {
- s = 0.0
- h = 0.0
- } else {
- s = delta / max
- h = if (r == max) {
- (g - b) / delta
- } else if (g == max) {
- 2 + (b - r) / delta
- } else {
- 4 + (r - g) / delta
- }
- h *= 60.0
- if (h < 0) {
- h += 360.0
- }
- if (java.lang.Double.isNaN(h)) {
- h = 0.0
- }
- }
- return HSVColor(h.toInt(), (100 * s).toInt(), (100 * max).toInt())
- }
-
- override fun toRGBW(): RGBWColor {
- val white = min(red, min(green, blue))
- return RGBWColor(
- red = red - white,
- green = green - white,
- blue = blue - white,
- white = white
- )
- }
-
- override fun toRGBA(): RGBAColor {
- val amber: Int
- var r = 0
- var g = 0
- if (red > green) {
- amber = green
- g = 0
- r -= (amber / RGBAColor.AMBER_FACTOR).roundToInt()
- } else {
- amber = red
- r = 0
- g -= (amber * RGBAColor.AMBER_FACTOR).roundToInt()
- }
- return RGBAColor(
- red = r - amber,
- green = g - amber,
- blue = blue,
- amber = amber
- )
- }
-
- override fun toColorParameter(): ColorParameter {
- val color = toRGBW()
- return ColorParameter(
- red = color.red,
- green = color.green,
- blue = color.blue,
- white = color.white
- )
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as RGBColor
-
- if (red != other.red) return false
- if (green != other.green) return false
- return blue == other.blue
- }
-
- override fun hashCode(): Int {
- var result = red
- result = 31 * result + green
- result = 31 * result + blue
- return result
+ override fun fade(other: Parameter<*>, factor: Double): RGBColor {
+ return if (other is RGBColor) {
+ RGBColor(
+ red = min(255, (red + factor * (other.red - red)).roundToInt()),
+ green = min(255, (green + factor * (other.green - green)).roundToInt()),
+ blue = min(255, (blue + factor * (other.blue - blue)).roundToInt())
+ )
+ } else throw IllegalArgumentException("Cannot fade different parameter type")
}
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWAColor.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWAColor.kt
index d2b293b..e2915d3 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWAColor.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWAColor.kt
@@ -1,8 +1,11 @@
package de.visualdigits.kotlin.klanglicht.model.color
+import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
import org.apache.commons.lang3.StringUtils
+import java.lang.IllegalArgumentException
import kotlin.math.min
import java.lang.Long.decode
+import kotlin.math.roundToInt
class RGBWAColor(
red: Int = 0,
@@ -10,7 +13,7 @@ class RGBWAColor(
blue: Int = 0,
var white: Int = 0,
var amber: Int = 0
-) : RGBColor(red, green, blue) {
+) : RGBBaseColor(red, green, blue) {
constructor(value: Long) : this(
red = min(a = 255, b = (value and 0xff00000000L shr 32).toInt()),
@@ -30,9 +33,53 @@ class RGBWAColor(
return "RGBColor(hex='${web()}', r=$red, g=$green , b=$blue, w=$white, a=$amber)"
}
+ override fun parameterMap(): Map = mapOf(
+ "Red" to red,
+ "Green" to green,
+ "Blue" to blue,
+ "White" to white,
+ "Amber" to amber
+ )
+
+ override fun fade(other: Parameter<*>, factor: Double): RGBWAColor {
+ return if (other is RGBWAColor) {
+ RGBWAColor(
+ red = min(255, (red + factor * (other.red - red)).roundToInt()),
+ green = min(255, (green + factor * (other.green - green)).roundToInt()),
+ blue = min(255, (blue + factor * (other.blue - blue)).roundToInt()),
+ white = min(255, (white + factor * (other.white - white)).roundToInt()),
+ amber = min(255, (amber + factor * (other.amber - amber)).roundToInt())
+ )
+ } else throw IllegalArgumentException("Cannot fade different parameter type")
+ }
+
override fun value(): Long = (red.toLong() shl 32) or (green.toLong() shl 24) or (blue.toLong() shl 16) or (white.toLong() shl 8) or amber.toLong()
override fun hex(): String = StringUtils.leftPad(java.lang.Long.toHexString(value()), 10, '0')
override fun web(): String = "#${hex()}"
+
+ override fun ansiColor(): String {
+ return toRGB().ansiColor()
+ }
+
+ override fun toRGB(): RGBColor {
+ return RGBColor(
+ red = min(255, red + (amber / RGBAColor.AMBER_FACTOR).roundToInt()) + white,
+ green = min(255, green + (amber * RGBAColor.AMBER_FACTOR).roundToInt() + white),
+ blue = min(255, blue + white)
+ )
+ }
+
+ override fun toHSV(): HSVColor {
+ return toRGB().toHSV()
+ }
+
+ override fun toRGBW(): RGBWColor {
+ return toRGB().toRGBW()
+ }
+
+ override fun toRGBA(): RGBAColor {
+ return toRGB().toRGBA()
+ }
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColor.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColor.kt
index 8f7d7de..03de114 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColor.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColor.kt
@@ -1,15 +1,18 @@
package de.visualdigits.kotlin.klanglicht.model.color
+import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
import org.apache.commons.lang3.StringUtils
+import java.lang.IllegalArgumentException
import kotlin.math.min
import java.lang.Long.decode
+import kotlin.math.roundToInt
class RGBWColor(
red: Int = 0,
green: Int = 0,
blue: Int = 0,
var white: Int = 0
-) : RGBColor(red, green, blue) {
+) : RGBBaseColor(red, green, blue) {
constructor(value: Long) : this(
red = min(a = 255, b = (value and 0xff000000L shr 24).toInt()),
@@ -18,6 +21,8 @@ class RGBWColor(
white = min(a = 255, b = (value and 0x000000ffL).toInt()),
)
+ constructor(hex: String) : this(decode(if (hex.startsWith("#") || hex.startsWith("0x")) hex else "#$hex"))
+
init {
if (white == 0) {
white = min(red, min(green, blue))
@@ -27,8 +32,6 @@ class RGBWColor(
}
}
- constructor(hex: String) : this(decode(if (hex.startsWith("#") || hex.startsWith("0x")) hex else "#$hex"))
-
override fun toString(): String {
return "[" + StringUtils.join(listOf(red, green, blue, white), ", ") + "]"
}
@@ -37,12 +40,22 @@ class RGBWColor(
return "RGBColor(hex='${web()}', r=$red, g=$green , b=$blue, w=$white)"
}
- override fun toRGB(): RGBColor {
- return RGBColor(
- red = min(255, red + white),
- green = min(255, green + white),
- blue = min(255, blue + white),
- )
+ override fun parameterMap(): Map = mapOf(
+ "Red" to red,
+ "Green" to green,
+ "Blue" to blue,
+ "White" to white
+ )
+
+ override fun fade(other: Parameter<*>, factor: Double): RGBWColor {
+ return if (other is RGBWColor) {
+ RGBWColor(
+ red = min(255, (red + factor * (other.red - red)).roundToInt()),
+ green = min(255, (green + factor * (other.green - green)).roundToInt()),
+ blue = min(255, (blue + factor * (other.blue - blue)).roundToInt()),
+ white = min(255, (white + factor * (other.white - white)).roundToInt())
+ )
+ } else throw IllegalArgumentException("Cannot fade different parameter type")
}
override fun value(): Long = (red.toLong() shl 24) or (green.toLong() shl 16) or (blue.toLong() shl 8) or white.toLong()
@@ -55,6 +68,14 @@ class RGBWColor(
return toRGB().ansiColor()
}
+ override fun toRGB(): RGBColor {
+ return RGBColor(
+ red = min(255, red + white),
+ green = min(255, green + white),
+ blue = min(255, blue + white),
+ )
+ }
+
override fun toHSV(): HSVColor {
return toRGB().toHSV()
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterfaceType.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/dmx/DMXInterfaceType.kt
similarity index 55%
rename from klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterfaceType.kt
rename to klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/dmx/DMXInterfaceType.kt
index 4d43e8c..25f63d4 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterfaceType.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/dmx/DMXInterfaceType.kt
@@ -1,4 +1,4 @@
-package de.visualdigits.kotlin.klanglicht.dmx
+package de.visualdigits.kotlin.klanglicht.model.dmx
enum class DMXInterfaceType {
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DmxFrame.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/dmx/DmxFrame.kt
similarity index 97%
rename from klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DmxFrame.kt
rename to klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/dmx/DmxFrame.kt
index bcbca15..18efd30 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DmxFrame.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/dmx/DmxFrame.kt
@@ -1,4 +1,4 @@
-package de.visualdigits.kotlin.klanglicht.dmx
+package de.visualdigits.kotlin.klanglicht.model.dmx
import com.google.common.primitives.Bytes
import org.apache.commons.lang3.StringUtils
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/fixture/Fixture.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/fixture/Fixture.kt
index 0eb6ecc..1afbd12 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/fixture/Fixture.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/fixture/Fixture.kt
@@ -1,15 +1,100 @@
package de.visualdigits.kotlin.klanglicht.model.fixture
-import de.visualdigits.kotlin.klanglicht.model.color.ColorParameter
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.module.kotlin.jacksonMapperBuilder
+import de.visualdigits.kotlin.klanglicht.model.parameter.IntParameter
+import de.visualdigits.kotlin.klanglicht.model.parameter.Parameter
+import de.visualdigits.kotlin.klanglicht.model.parameter.ParameterSet
+import java.io.File
+import java.nio.file.Paths
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.round
+@JsonIgnoreProperties("channelsForCurrentMode")
data class Fixture(
val calibration: Calibration = Calibration(),
val channels: Map> = mapOf(),
- val colorPresets: Map = mapOf(),
+ val colorPresets: Map> = mapOf(),
val manufacturer: String? = null,
val model: String? = null,
val parameters: Map? = null
) {
- fun channelsForMode(mode: String):List? = channels[mode]
+
+ var channelsForCurrentMode: Map = mapOf()
+
+ companion object {
+ fun load(klanglichtDir: File, fixtureName: String): Fixture {
+ return jacksonMapperBuilder().build().readValue(
+ Paths.get(klanglichtDir.canonicalPath, "fixtures", "$fixtureName.json").toFile(),
+ Fixture::class.java
+ )
+ }
+ }
+
+ /**
+ * Returns the list of channels for the given mode (if any).
+ */
+ fun channelsForMode(mode: String): List = channels[mode] ?: listOf()
+
+
+ /**
+ * Returns whether the fixture has a pano parameter or not.
+ */
+ fun hasPano(): Boolean = channelsForCurrentMode.containsKey("Pan")
+
+ /**
+ * Returns the maximum panning angle in degrees.
+ */
+ fun maxPano(): Double = parameters?.get("maxPano")?.let { (it as Int).toDouble() }?:0.0
+
+ /**
+ * Returns the maximum value for the pano parameter according to the number of bytes supported within the current mode.
+ */
+ fun maxPanoValue(): Int = if (hasPano()) if (channelsForCurrentMode.containsKey("PanFine")) 65535 else 255 else 0
+
+ /**
+ * Returns a parameter set to be used to set the pano according to the given angle
+ */
+ fun panoParameterSet(angle: Double): ParameterSet {
+ val maxPano = maxPano()
+ val panoValue = round(maxPanoValue().toDouble() / maxPano * max(min(angle, maxPano), 0.0)).toInt()
+ return ParameterSet(
+ parameters = mutableListOf(
+ IntParameter("Pan", (panoValue and 0xff00) shr 8),
+ IntParameter("PanFine", panoValue and 0xff)
+ )
+ )
+ }
+
+
+ /**
+ * Returns whether the fixture has a tilt parameter or not.
+ */
+ fun hasTilt(): Boolean = channelsForCurrentMode.containsKey("Tilt")
+
+ /**
+ * Returns the maximum tilting angle in degrees.
+ */
+ fun maxTilt(): Double = parameters?.get("maxTilt")?.let { (it as Int).toDouble() }?:0.0
+
+ /**
+ * Returns the maximum value for the tilt parameter according to the number of bytes supported within the current mode.
+ */
+ fun maxTiltValue(): Int = if (hasTilt()) if (channelsForCurrentMode.containsKey("TiltFine")) 65535 else 255 else 0
+
+ /**
+ * Returns a parameter set to be used to set the tilt according to the given angle
+ */
+ fun tiltParameterSet(angle: Double): ParameterSet {
+ val maxTilt = maxTilt()
+ val tiltValue = round(maxTiltValue().toDouble() / maxTilt * max(min(angle, maxTilt), 0.0)).toInt()
+ return ParameterSet(
+ parameters = mutableListOf(
+ IntParameter("Tilt", (tiltValue and 0xff00) shr 8),
+ IntParameter("TiltFine", tiltValue and 0xff)
+ )
+ )
+ }
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/IntParameter.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/IntParameter.kt
new file mode 100644
index 0000000..6dc8c76
--- /dev/null
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/IntParameter.kt
@@ -0,0 +1,18 @@
+package de.visualdigits.kotlin.klanglicht.model.parameter
+
+import java.lang.IllegalArgumentException
+
+class IntParameter(
+ val name: String,
+ val value: Int = 0
+) : Parameter {
+
+ override fun parameterMap(): Map = mapOf(name to value)
+
+ override fun fade(other: Parameter<*>, factor: Double): IntParameter {
+ return if (other is IntParameter) {
+ if (name != other.name) throw IllegalArgumentException("Cannot fade different parameters")
+ IntParameter(name, ((value + (other.value - value) * factor).toInt()))
+ } else throw IllegalArgumentException("Cannot fade different parameter type")
+ }
+}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Parameter.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Parameter.kt
index 2a67b0d..9461e7b 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Parameter.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Parameter.kt
@@ -1,5 +1,8 @@
package de.visualdigits.kotlin.klanglicht.model.parameter
-abstract class Parameter(
- val parameterMap: MutableMap = mutableMapOf()
-) : MutableMap by parameterMap
+interface Parameter> {
+
+ fun parameterMap(): Map
+
+ fun fade(other: Parameter<*>, factor: Double): T
+}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/ParameterSet.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/ParameterSet.kt
index 7eb33d6..c62671c 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/ParameterSet.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/ParameterSet.kt
@@ -2,16 +2,40 @@ package de.visualdigits.kotlin.klanglicht.model.parameter
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
-@JsonIgnoreProperties("parameterObjects")
+@JsonIgnoreProperties("parameterValues")
class ParameterSet(
val baseChannel: Int = 0,
- val parameters: MutableMap = mutableMapOf(),
+ val parameters: MutableList> = mutableListOf(),
) {
- constructor(
- baseChannel: Int = 0,
- parameterObjects: Set = setOf()
- ) : this(baseChannel, parameterObjects.fold(mutableMapOf()) { a, b ->
- a.putAll(b.parameterMap)
- a
- })
+
+ val parameterMap: MutableMap = mutableMapOf()
+
+ init {
+ updateParameterValues(parameters)
+ }
+
+ private fun updateParameterValues(parameters: MutableList>) {
+ parameterMap.putAll(parameters.flatMap { param -> param.parameterMap().toList() }.toMap().toMutableMap())
+ }
+
+
+ /**
+ * Puts all parameters from the given parameter set.
+ */
+ fun join(other: ParameterSet): ParameterSet {
+ parameters.addAll(other.parameters)
+ updateParameterValues(other.parameters)
+ return this
+ }
+
+ fun fade(other: ParameterSet, factor: Double): ParameterSet {
+ return ParameterSet(
+ baseChannel = baseChannel,
+ parameters = parameters
+ .zip(other.parameters)
+ .map { it.first.fade(it.second, factor) }
+ .toMutableList()
+ )
+ }
}
+
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/RotationParameter.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/RotationParameter.kt
new file mode 100644
index 0000000..9bba529
--- /dev/null
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/RotationParameter.kt
@@ -0,0 +1,54 @@
+package de.visualdigits.kotlin.klanglicht.model.parameter
+
+import de.visualdigits.kotlin.klanglicht.model.fixture.Fixture
+import java.lang.IllegalArgumentException
+import kotlin.math.*
+
+class RotationParameter(
+
+ /** The fixture for this rotation (needed to calculate raw values). */
+ val fixture: Fixture,
+
+ val panDegrees: Double,
+
+ val tiltDegrees: Double
+) : Parameter {
+
+ private val DEG2RAD: Double = (Math.PI / 180.0)
+
+ private val RAD2DEG: Double = (180.0 / Math.PI)
+
+ override fun parameterMap(): Map =
+ fixture.panoParameterSet(panDegrees).parameterMap + fixture.tiltParameterSet(tiltDegrees).parameterMap
+
+
+ override fun fade(other: Parameter<*>, factor: Double): RotationParameter {
+ return if (other is RotationParameter) {
+
+ // use great circle to determine intermediate steps
+ // adapted from page http://compastic.blogspot.co.uk/2011/07/how-to-draw-great-circle-on-map-in.html
+ // which was adapted from page http://maps.forum.nu/gm_flight_path.html
+
+ val lat1: Double = tiltDegrees * DEG2RAD
+ val lon1: Double = panDegrees * DEG2RAD
+ val lat2: Double = other.tiltDegrees * DEG2RAD
+ val lon2: Double = other.panDegrees * DEG2RAD
+
+ val d = 2 * asin(sqrt(sin((lat1 - lat2) / 2).pow(2.0) + cos(lat1) * cos(lat2) * sin((lon1 - lon2) / 2).pow(2.0)))
+
+ val A = sin((1 - factor) * d) / sin(d)
+ val B = sin(factor * d) / sin(d)
+ val x = A * cos(lat1) * cos(lon1) + B * cos(lat2) * cos(lon2)
+ val y = A * cos(lat1) * sin(lon1) + B * cos(lat2) * sin(lon2)
+ val z = A * sin(lat1) + B * sin(lat2)
+
+ val latN = atan2(z, sqrt(x.pow(2.0) + y.pow(2.0)))
+ val lonN = atan2(y, x)
+
+ val panDegrees: Double = lonN * RAD2DEG
+ val tiltDegrees: Double = latN * RAD2DEG
+
+ RotationParameter(fixture, panDegrees, tiltDegrees)
+ } else throw IllegalArgumentException("Cannot fade different parameter type")
+ }
+}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Scene.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Scene.kt
index d52eba4..48e157d 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Scene.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/parameter/Scene.kt
@@ -5,7 +5,7 @@ import java.io.File
class Scene(
val name: String,
- val parameterSet: Set
+ val parameterSet: List
) {
companion object {
private val mapper = jacksonMapperBuilder().build()
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/preferences/Preferences.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/preferences/Preferences.kt
index ba17e02..3ae089b 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/preferences/Preferences.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/preferences/Preferences.kt
@@ -1,8 +1,9 @@
package de.visualdigits.kotlin.klanglicht.model.preferences
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.module.kotlin.jacksonMapperBuilder
import de.visualdigits.kotlin.klanglicht.dmx.DMXInterface
-import de.visualdigits.kotlin.klanglicht.dmx.DMXInterfaceType
+import de.visualdigits.kotlin.klanglicht.model.dmx.DMXInterfaceType
import de.visualdigits.kotlin.klanglicht.model.fixture.Channel
import de.visualdigits.kotlin.klanglicht.model.fixture.Fixtures
import de.visualdigits.kotlin.klanglicht.model.parameter.Scene
@@ -11,6 +12,7 @@ import java.io.File
import java.nio.file.Paths
+@JsonIgnoreProperties("klanglichtDir")
data class Preferences(
val dividerPositions: List = listOf(),
val dmxFrameTime: Long? = null,
@@ -28,6 +30,9 @@ data class Preferences(
val uiLanguage: String? = null,
val yamahaReceiverUrl: String? = null
) {
+
+ var klanglichtDir: File? = null
+
companion object {
private val mapper = jacksonMapperBuilder().build()
@@ -43,6 +48,8 @@ data class Preferences(
Paths.get(klanglichtDir.canonicalPath, "preferences", preferencesFileName).toFile(),
Preferences::class.java
)
+ preferences?.klanglichtDir = klanglichtDir
+
val fixtures = Fixtures.load(klanglichtDir)
val stage = Stage.load(klanglichtDir, preferences?.stageSetupName!!)
stage.fixtures.forEach { stageFixture ->
@@ -52,7 +59,7 @@ data class Preferences(
}
}
}
- dmxInterface = DMXInterface.load(preferences?.dmxInterfaceType?:DMXInterfaceType.Dummy)
+ dmxInterface = DMXInterface.load(preferences?.dmxInterfaceType?: DMXInterfaceType.Dummy)
dmxInterface?.open(preferences?.dmxPort!!)
}
return preferences!!
@@ -73,7 +80,7 @@ data class Preferences(
scene.parameterSet.forEach { parameterSet ->
val bc = parameterSet.baseChannel
val bytes = (fixtures[bc]?.map { channel ->
- (parameterSet.parameters[channel.name]?:0).toByte()
+ (parameterSet.parameterMap[channel.name]?:0).toByte()
}?:listOf())
.toByteArray()
dmxInterface?.dmxFrame!!.set(bc, bytes)
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/Stage.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/Stage.kt
index 7cc4d63..be05a4e 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/Stage.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/Stage.kt
@@ -1,20 +1,35 @@
package de.visualdigits.kotlin.klanglicht.model.stage
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.module.kotlin.jacksonMapperBuilder
+import de.visualdigits.kotlin.klanglicht.model.fixture.Fixture
import java.io.File
import java.nio.file.Paths
+@JsonIgnoreProperties("fixturesResolved")
data class Stage(
val name: String = "",
val fixtures: List = listOf()
) {
+
companion object {
fun load(klanglichtDir: File, stageName: String): Stage {
- return jacksonMapperBuilder().build().readValue(
+ val stage = jacksonMapperBuilder().build().readValue(
Paths.get(klanglichtDir.canonicalPath, "stages", "$stageName.json").toFile(),
Stage::class.java
)
+
+ stage.fixtures.forEach { stageFixture ->
+ val fixtureName = "${stageFixture.manufacturer}_${stageFixture.model}"
+ stageFixture.fixture = Fixture.load(klanglichtDir, fixtureName)
+ stageFixture.fixture?.channelsForCurrentMode =
+ stageFixture.fixture
+ ?.channelsForMode(stageFixture.mode)
+ ?.associate { Pair(it.name!!, it) }
+ ?:mapOf()
+ }
+ return stage
}
}
}
diff --git a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/StageFixture.kt b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/StageFixture.kt
index ffa8511..8b0e1bb 100644
--- a/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/StageFixture.kt
+++ b/klanglicht-core/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/StageFixture.kt
@@ -1,9 +1,13 @@
package de.visualdigits.kotlin.klanglicht.model.stage
+import de.visualdigits.kotlin.klanglicht.model.fixture.Fixture
+
data class StageFixture(
val baseChannel: Int = 0,
val manufacturer: String = "",
val mode: String = "",
val model: String = ""
-)
+) {
+ var fixture: Fixture? = null
+}
diff --git a/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterfaceTest.kt b/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterfaceTest.kt
index fb3641e..8db44b2 100644
--- a/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterfaceTest.kt
+++ b/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/dmx/DMXInterfaceTest.kt
@@ -1,12 +1,13 @@
package de.visualdigits.kotlin.klanglicht.dmx
-import de.visualdigits.kotlin.klanglicht.model.color.ColorParameter
-import de.visualdigits.kotlin.klanglicht.model.color.NamedParameter
import de.visualdigits.kotlin.klanglicht.model.color.RGBColor
+import de.visualdigits.kotlin.klanglicht.model.color.RGBWColor
+import de.visualdigits.kotlin.klanglicht.model.parameter.IntParameter
import de.visualdigits.kotlin.klanglicht.model.parameter.ParameterSet
+import de.visualdigits.kotlin.klanglicht.model.parameter.RotationParameter
import de.visualdigits.kotlin.klanglicht.model.parameter.Scene
import de.visualdigits.kotlin.klanglicht.model.preferences.Preferences
-import kotlinx.coroutines.*
+import de.visualdigits.kotlin.klanglicht.model.stage.Stage
import org.junit.jupiter.api.Test
import java.io.File
import kotlin.math.ceil
@@ -29,15 +30,13 @@ internal class DMXInterfaceTest {
fun testInterfaceFromModel1() {
val scene = Scene(
name = "test",
- parameterSet = setOf(
+ parameterSet = listOf(
ParameterSet(
baseChannel = 15,
- parameters = mutableMapOf(
- "MasterDimmer" to 255,
- "Stroboscope" to 0,
- "Red" to 255,
- "Green" to 0,
- "Blue" to 0
+ parameters = mutableListOf(
+ IntParameter("MasterDimmer", 255),
+ IntParameter("Stroboscope", 0),
+ RGBColor(255, 0, 0)
)
)
)
@@ -50,15 +49,13 @@ internal class DMXInterfaceTest {
fun testBlackout() {
val scene = Scene(
name = "test",
- parameterSet = setOf(
+ parameterSet = listOf(
ParameterSet(
baseChannel = 15,
- parameters = mutableMapOf(
- "MasterDimmer" to 0,
- "Stroboscope" to 0,
- "Red" to 0,
- "Green" to 0,
- "Blue" to 0
+ parameters = mutableListOf(
+ IntParameter("MasterDimmer", 0),
+ IntParameter("Stroboscope", 0),
+ RGBColor()
)
)
)
@@ -69,65 +66,96 @@ internal class DMXInterfaceTest {
@Test
fun testMovinghead() {
-// val repeater = Repeater.instance(prefs)
+ val stage = Stage.load(prefs.klanglichtDir!!, "home-lab-movinghead")
+
val repeater = Repeater(prefs)
repeater.start()
- val color1 = RGBColor(
- red = 255,
- green = 0,
- blue = 0
- )
- val color2 = RGBColor(
- red = 0,
- green = 255,
- blue = 0
- )
- fade(48, color1, color2, 2000)
+ testReset()
+
+ Thread.sleep(2000)
+
+ fade(stage)
repeater.join()
}
@Test
- fun testInterfaceFromModel2() {
- val color1 = RGBColor(
- red = 255,
- green = 0,
- blue = 0
- )
- val color2 = RGBColor(
- red = 0,
- green = 255,
- blue = 0
+ fun testReset() {
+ val scene = Scene(
+ name = "test",
+ parameterSet = listOf(
+ ParameterSet(
+ baseChannel = 35,
+ parameters = mutableListOf(
+ IntParameter("Speed", 0),
+ IntParameter("Pan", 0),
+ IntParameter("PanFine", 0),
+ IntParameter("Tilt", 0),
+ IntParameter("TiltFine", 0),
+ RGBWColor()
+ )
+ )
+ )
)
- val fadeDuration = 2000 // millis
+ prefs.setScene(scene)
+ }
+
+ @Test
+ fun testRotation() {
+ val stage = Stage.load(prefs.klanglichtDir!!, "home-lab-movinghead")
+ val stageFixture = stage.fixtures.first()
+ val fixture = stageFixture.fixture!!
+
+ println(fixture.panoParameterSet(0.0).parameters.map { it.parameterMap().toString() })
+ println(fixture.panoParameterSet(90.0).parameters.map { it.parameterMap().toString() })
+ println(fixture.panoParameterSet(180.0).parameters.map { it.parameterMap().toString() })
+ println(fixture.panoParameterSet(360.0).parameters.map { it.parameterMap().toString() })
+ println(fixture.panoParameterSet(540.0).parameters.map { it.parameterMap().toString() })
- fade(15, color1, color2, fadeDuration)
+ println(fixture.tiltParameterSet(0.0).parameters.map { it.parameterMap().toString() })
+ println(fixture.tiltParameterSet(90.0).parameters.map { it.parameterMap().toString() })
+ println(fixture.tiltParameterSet(180.0).parameters.map { it.parameterMap().toString() })
}
private fun fade(
- baseChannel: Int,
- color1: RGBColor,
- color2: RGBColor,
- fadeDuration: Int
+ stage: Stage,
) {
+ val stageFixture = stage.fixtures.first()
+ val baseChannel = stageFixture.baseChannel
+ val fixture = stageFixture.fixture!!
+
+ val fadeDuration = 3000
+
+ val parameterSet1 = ParameterSet(
+ baseChannel = baseChannel,
+ parameters = mutableListOf(
+ RGBWColor(128, 0, 0, 0),
+ IntParameter("Speed", 0),
+ RotationParameter(fixture, 0.0, 0.0)
+ )
+ )
+
+ val parameterSet2 = ParameterSet(
+ baseChannel = baseChannel,
+ parameters = mutableListOf(
+ RGBWColor(0, 128, 0, 0),
+ IntParameter("Speed", 0),
+ RotationParameter(fixture, 80.0, 60.0)
+ )
+ )
+
val dmxFrameTime = prefs.dmxFrameTime!! // millis
val steps = ceil(fadeDuration.toDouble() / dmxFrameTime.toDouble()).toInt()
val step = 1.0 / steps
- for (f in 0..steps + 1) {
+ for (f in 0..steps) {
val factor = step * f
- val color = color1.mix(color2, min(1.0, factor))
+ val frame = parameterSet1.fade(parameterSet2, factor)
+// println(frame.parameters.map { it.parameterMap().toString() })
val scene = Scene(
- name = "test",
- parameterSet = setOf(
- ParameterSet(
- baseChannel = baseChannel,
- parameterObjects = setOf(
- NamedParameter("MasterDimmer", 255),
- NamedParameter("Stroboscope", 0),
- color
- )
- )
+ name = "frame_$f",
+ parameterSet = listOf(
+ frame
)
)
prefs.setScene(scene)
diff --git a/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColorTest.kt b/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColorTest.kt
index aee8ab5..4700b74 100644
--- a/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColorTest.kt
+++ b/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/model/color/RGBWColorTest.kt
@@ -49,7 +49,7 @@ internal class RGBWColorTest {
fun mixTestTwoColors() {
val color1 = RGBWColor("#ff000000")
val color2 = RGBWColor("#0000ff00")
- val mixed = color1.mix(color2, 0.5)
+ val mixed = color1.fade(color2, 0.5)
assertEquals("#80008000", mixed.web())
}
@@ -58,14 +58,14 @@ internal class RGBWColorTest {
// tests that two colors containing white in different notations end up with white regardless of the facor
val color1 = RGBWColor("#ffffff00")
val color2 = RGBWColor("#000000ff")
- assertEquals("#000000ff", color1.mix(color2, 0.1).web())
- assertEquals("#000000ff", color1.mix(color2, 0.2).web())
- assertEquals("#000000ff", color1.mix(color2, 0.3).web())
- assertEquals("#000000ff", color1.mix(color2, 0.4).web())
- assertEquals("#000000ff", color1.mix(color2, 0.5).web())
- assertEquals("#000000ff", color1.mix(color2, 0.6).web())
- assertEquals("#000000ff", color1.mix(color2, 0.7).web())
- assertEquals("#000000ff", color1.mix(color2, 0.8).web())
- assertEquals("#000000ff", color1.mix(color2, 0.9).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.1).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.2).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.3).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.4).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.5).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.6).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.7).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.8).web())
+ assertEquals("#000000ff", color1.fade(color2, 0.9).web())
}
}
diff --git a/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/StageTest.kt b/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/StageTest.kt
new file mode 100644
index 0000000..8be0484
--- /dev/null
+++ b/klanglicht-core/src/test/kotlin/de/visualdigits/kotlin/klanglicht/model/stage/StageTest.kt
@@ -0,0 +1,22 @@
+package de.visualdigits.kotlin.klanglicht.model.stage
+
+import de.visualdigits.kotlin.klanglicht.model.preferences.Preferences
+import org.junit.jupiter.api.Test
+import java.io.File
+
+class StageTest {
+
+ private val prefs = Preferences.instance(
+ klanglichtDir = File(ClassLoader.getSystemResource(".klanglicht").toURI()),
+ preferencesFileName = System.getenv("preferencesFileName")?:"preferences.json"
+ )
+
+ @Test
+ fun testStage() {
+ val stage = Stage.load(prefs.klanglichtDir!!, "home-lab-movinghead")
+ stage.fixtures.forEach { stageFixture ->
+ val fixture = stageFixture.fixture!!
+ println("${stageFixture.manufacturer}_${stageFixture.model}_${stageFixture.mode} [${stageFixture.baseChannel}] hasPano: ${fixture.hasPano()} [max value ${fixture.maxPanoValue()}] hasTilt: ${fixture.hasTilt()} [max value ${fixture.maxTiltValue()}]")
+ }
+ }
+}
diff --git a/klanglicht-core/src/test/resources/.klanglicht/preferences/preferences.json b/klanglicht-core/src/test/resources/.klanglicht/preferences/preferences.json
index 666613c..cf365ec 100644
--- a/klanglicht-core/src/test/resources/.klanglicht/preferences/preferences.json
+++ b/klanglicht-core/src/test/resources/.klanglicht/preferences/preferences.json
@@ -1,5 +1,5 @@
{
- "dmxPort" : "COM5",
+ "dmxPort" : "COM8",
"dmxInterfaceType" : "Dummy",
"dmxFrameTime" : 40,
"remoteUrl" : null,
diff --git a/klanglicht-core/src/test/resources/.klanglicht/preferences/preferences_home.json b/klanglicht-core/src/test/resources/.klanglicht/preferences/preferences_home.json
new file mode 100644
index 0000000..423d846
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/preferences/preferences_home.json
@@ -0,0 +1,67 @@
+{
+ "dmxPort" : "COM8",
+ "dmxInterfaceType" : "Serial",
+ "dmxFrameTime" : 40,
+ "remoteUrl" : null,
+ "lightmanagerUrl" : "http://192.168.178.28",
+ "yamahaReceiverUrl" : "http://192.168.178.21",
+ "stageSetupName" : "wohnzimmer_full",
+ "stageParameters": {
+ "shellyDevices": {
+ "Starwars": {
+ "model": "shelly-rgbw",
+ "ipAddress": "192.168.178.54",
+ "gain": 30
+ },
+ "Rgbw": {
+ "model": "shelly-rgbw",
+ "ipAddress": "192.168.178.48",
+ "gain": 1
+ },
+ "Bar": {
+ "model": "shelly-rgbw",
+ "ipAddress": "192.168.178.55",
+ "gain": 20
+ },
+ "Flur": {
+ "model": "shelly-1",
+ "ipAddress": "192.168.178.38",
+ "gain": 0
+ },
+ "Schlafzimmer": {
+ "model": "shelly-1",
+ "ipAddress": "192.168.178.40",
+ "gain": 0
+ },
+ "Wohnzimmer": {
+ "model": "shelly-2.5",
+ "ipAddress": "192.168.178.37",
+ "gain": 0
+ },
+ "Kristall": {
+ "model": "plug-s",
+ "ipAddress": "192.168.178.51",
+ "gain": 0
+ },
+ "Regal": {
+ "model": "shelly-plug-s",
+ "ipAddress": "192.168.178.39",
+ "gain": 0
+ }
+ },
+ "dmxDevices": {
+ "1": {
+ "gain": 0.5
+ },
+ "15": {
+ "gain": 0.5
+ },
+ "21": {
+ "gain": 1.0
+ },
+ "29": {
+ "gain": 0.5
+ }
+ }
+ }
+}
diff --git a/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_anakin-vs-obiwan.png b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_anakin-vs-obiwan.png
new file mode 100644
index 0000000..7580f44
Binary files /dev/null and b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_anakin-vs-obiwan.png differ
diff --git a/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_darth-vader_1.jpg b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_darth-vader_1.jpg
new file mode 100644
index 0000000..ebd5315
Binary files /dev/null and b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_darth-vader_1.jpg differ
diff --git a/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_darth-vader_2.jpg b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_darth-vader_2.jpg
new file mode 100644
index 0000000..9fb91b2
Binary files /dev/null and b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_darth-vader_2.jpg differ
diff --git a/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_starwars_1.jpg b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_starwars_1.jpg
new file mode 100644
index 0000000..14a464e
Binary files /dev/null and b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_starwars_1.jpg differ
diff --git a/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_stormtrooper.png b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_stormtrooper.png
new file mode 100644
index 0000000..e127ade
Binary files /dev/null and b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_stormtrooper.png differ
diff --git a/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_yoda.jpg b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_yoda.jpg
new file mode 100644
index 0000000..f3a2e93
Binary files /dev/null and b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_yoda.jpg differ
diff --git a/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_yoda_crop.jpg b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_yoda_crop.jpg
new file mode 100644
index 0000000..289ca3d
Binary files /dev/null and b/klanglicht-core/src/test/resources/.klanglicht/resources/themes/StarWars/images/bg_yoda_crop.jpg differ
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-movinghead.json b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-movinghead.json
new file mode 100644
index 0000000..7931c03
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-movinghead.json
@@ -0,0 +1,14 @@
+{
+ "name": "home-lab-rgb-movinghead",
+ "fixtures": [{
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 35
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 48
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-movinghead.json b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-movinghead.json
new file mode 100644
index 0000000..a88c3a6
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-movinghead.json
@@ -0,0 +1,29 @@
+{
+ "name": "home-lab-rgb-movinghead",
+ "fixtures": [{
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 1
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 15
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 29
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 35
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 48
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-rgbw-movinghead.json b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-rgbw-movinghead.json
new file mode 100644
index 0000000..5ccfa90
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-rgbw-movinghead.json
@@ -0,0 +1,39 @@
+{
+ "name": "home-lab-rgb-rgbw-movinghead",
+ "fixtures": [{
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 1
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 7
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 15
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 21
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 29
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 35
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 48
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-rgbw.json b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-rgbw.json
new file mode 100644
index 0000000..8fde00b
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb-rgbw.json
@@ -0,0 +1,29 @@
+{
+ "name": "home-lab-rgb-rgbw-movinghead",
+ "fixtures": [{
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 1
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 7
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 15
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 21
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 29
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb.json b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb.json
new file mode 100644
index 0000000..144609a
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgb.json
@@ -0,0 +1,19 @@
+{
+ "name": "home-lab-rgb",
+ "fixtures": [{
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 1
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 15
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 29
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgbw-movinghead.json b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgbw-movinghead.json
new file mode 100644
index 0000000..19f71ea
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgbw-movinghead.json
@@ -0,0 +1,24 @@
+{
+ "name": "home-lab-rgbw-movinghead",
+ "fixtures": [{
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 7
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 21
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 35
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 48
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgbw.json b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgbw.json
new file mode 100644
index 0000000..cea4901
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/home-lab-rgbw.json
@@ -0,0 +1,14 @@
+{
+ "name": "home-lab-rgbw",
+ "fixtures": [{
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 7
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 21
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/wohnzimmer.json b/klanglicht-core/src/test/resources/.klanglicht/stages/wohnzimmer.json
new file mode 100644
index 0000000..25a6604
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/wohnzimmer.json
@@ -0,0 +1,29 @@
+{
+ "name" : "wohnzimmer",
+ "fixtures" : [ {
+ "manufacturer" : "Cameo",
+ "model" : "Flat PAR Can RGB 10 IR",
+ "mode" : "6-Channel Mode",
+ "baseChannel" : 1
+ }, {
+ "manufacturer" : "Cameo",
+ "model" : "Flat PAR Can RGBW",
+ "mode" : "8-Channel Mode",
+ "baseChannel" : 7
+ }, {
+ "manufacturer" : "Cameo",
+ "model" : "Flat PAR Can RGB 10 IR",
+ "mode" : "6-Channel Mode",
+ "baseChannel" : 15
+ }, {
+ "manufacturer" : "Cameo",
+ "model" : "Flat PAR Can RGBW",
+ "mode" : "8-Channel Mode",
+ "baseChannel" : 21
+ }, {
+ "manufacturer" : "Cameo",
+ "model" : "Flat PAR Can RGB 10 IR",
+ "mode" : "6-Channel Mode",
+ "baseChannel" : 29
+ } ]
+}
diff --git a/klanglicht-core/src/test/resources/.klanglicht/stages/wohnzimmer_full.json b/klanglicht-core/src/test/resources/.klanglicht/stages/wohnzimmer_full.json
new file mode 100644
index 0000000..fb5bc69
--- /dev/null
+++ b/klanglicht-core/src/test/resources/.klanglicht/stages/wohnzimmer_full.json
@@ -0,0 +1,39 @@
+{
+ "name": "home-lab-rgb-rgbw-movinghead",
+ "fixtures": [{
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 48
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 1
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 7
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 15
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGBW",
+ "mode": "8-Channel Mode",
+ "baseChannel": 21
+ }, {
+ "manufacturer": "Cameo",
+ "model": "Flat PAR Can RGB 10 IR",
+ "mode": "6-Channel Mode",
+ "baseChannel": 29
+ }, {
+ "manufacturer": "Renkforce",
+ "model": "Moving Head GM107",
+ "mode": "13-Channel Mode",
+ "baseChannel": 35
+ }]
+}
\ No newline at end of file
diff --git a/klanglicht-yamaha/pom.xml b/klanglicht-yamaha/pom.xml
new file mode 100644
index 0000000..edb3482
--- /dev/null
+++ b/klanglicht-yamaha/pom.xml
@@ -0,0 +1,45 @@
+
+
+ 4.0.0
+ jar
+
+
+ de.visualdigits.kotlin
+ klanglicht-kt
+ ${revision}
+ ../pom.xml
+
+
+ klanglicht-yamaha
+ ${revision}
+
+
+ 12.1
+
+
+
+
+
+ io.github.openfeign
+ feign-okhttp
+ ${version.feign}
+
+
+ io.github.openfeign
+ feign-gson
+ ${version.feign}
+
+
+ io.github.openfeign
+ feign-slf4j
+ ${version.feign}
+
+
+ io.github.openfeign.form
+ feign-form
+ 3.8.0
+
+
+
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/feign/YamahaAvantageReceiverClient.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/feign/YamahaAvantageReceiverClient.kt
new file mode 100644
index 0000000..bd32eb0
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/feign/YamahaAvantageReceiverClient.kt
@@ -0,0 +1,80 @@
+package de.visualdigits.kotlin.klanglicht.feign
+
+import com.fasterxml.jackson.core.JsonProcessingException
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import de.visualdigits.kotlin.klanglicht.model.yamahaavantage.deviceinfo.DeviceInfo
+import de.visualdigits.kotlin.klanglicht.model.yamahaavantage.ResponseCode
+import de.visualdigits.kotlin.klanglicht.model.yamahaavantage.SoundProgramList
+import de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features.Features
+import java.net.URL
+import java.nio.charset.StandardCharsets
+
+
+class YamahaAvantageReceiverClient(val yamahaReceiverUrl: String) {
+
+ fun deviceInfo(): DeviceInfo {
+ val deviceInfo = URL("$yamahaReceiverUrl/v1/system/getDeviceInfo").readText(StandardCharsets.UTF_8)
+ return mapper.readValue(deviceInfo, DeviceInfo::class.java)
+ }
+
+ fun features(): Features {
+ val features = URL("$yamahaReceiverUrl/YamahaExtendedControl/v1/system/getFeatures").readText(StandardCharsets.UTF_8)
+ return mapper.readValue(features, Features::class.java)
+ }
+
+ fun soundProgramList(): SoundProgramList {
+ val soundProgramList = URL("$yamahaReceiverUrl/YamahaExtendedControl/v1/main/getSoundProgramList").readText(StandardCharsets.UTF_8)
+ return mapper.readValue(soundProgramList, SoundProgramList::class.java)
+ }
+
+ fun setVolume(volume: Int) {
+ URL("$yamahaReceiverUrl/YamahaExtendedControl/v1/main/setVolume?volume=$volume").readText(StandardCharsets.UTF_8)
+ }
+
+ fun setSurroundProgram(program: String): ResponseCode {
+ println("Setting program '${mapPrograms[program]}'")
+ return try {
+ mapPrograms[program]
+ ?.let { URL("$yamahaReceiverUrl/YamahaExtendedControl/v1/main/setSoundProgram?program=$it").readText(StandardCharsets.UTF_8) }
+ ?.let { mapper.readValue(it, ResponseCode::class.java) }
+ ?: ResponseCode(0)
+
+ } catch (e: JsonProcessingException) {
+ throw IllegalStateException("Could not read from api", e)
+ }
+ }
+
+ companion object {
+
+ private val mapper = jacksonObjectMapper()
+
+ private val mapPrograms: MutableMap = HashMap()
+
+
+ init {
+ mapPrograms["Standard"] = "standard"
+ mapPrograms["Sci-Fi"] = "sci-fi"
+ mapPrograms["Spectacle"] = "spectacle"
+ mapPrograms["Adventure"] = "adventure"
+ mapPrograms["Drama"] = "drama";
+ mapPrograms["Sports"] = "sports";
+ mapPrograms["Music Video"] = "music_video";
+ mapPrograms["Action Game"] = "action_game";
+ mapPrograms["Roleplaying Game"] = "roleplaying_game";
+ mapPrograms["Mono Movie"] = "mono_movie";
+
+ mapPrograms["The Roxy Theatre"] = "roxy_theatre"
+ mapPrograms["The Bottom Line"] = "bottom_line"
+ mapPrograms["Cellar Club"] = "cellar_club";
+ mapPrograms["Chamber"] = "chamber";
+ mapPrograms["Hall in Munich"] = "munich"
+ mapPrograms["Hall in Vienna"] = "vienna"
+
+ mapPrograms["2ch Stereo"] = "all_ch_stereo"
+ mapPrograms["7ch Stereo"] = "all_ch_stereo"
+ mapPrograms["Straight"] = "straight";
+
+ mapPrograms["Surround Decoder"] = "surr_decoder"
+ }
+ }
+}
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/ResponseCode.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/ResponseCode.kt
new file mode 100644
index 0000000..f2a49e1
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/ResponseCode.kt
@@ -0,0 +1,9 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+
+class ResponseCode(
+ @JsonProperty("response_code") val responseCode: Int = 0
+)
+
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/SoundProgramList.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/SoundProgramList.kt
new file mode 100644
index 0000000..f1f522f
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/SoundProgramList.kt
@@ -0,0 +1,9 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class SoundProgramList(
+ @JsonProperty("response_code") val responseCode: Int = 0,
+ @JsonProperty("sound_program_list") val soundProgramList: List = listOf()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/deviceinfo/AnalyticsInfo.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/deviceinfo/AnalyticsInfo.kt
new file mode 100644
index 0000000..975618a
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/deviceinfo/AnalyticsInfo.kt
@@ -0,0 +1,6 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.deviceinfo
+
+
+data class AnalyticsInfo(
+ val uuid: String = ""
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/deviceinfo/DeviceInfo.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/deviceinfo/DeviceInfo.kt
new file mode 100644
index 0000000..bc0016a
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/deviceinfo/DeviceInfo.kt
@@ -0,0 +1,24 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.deviceinfo
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class DeviceInfo(
+ @JsonProperty("response_code") val responseCode: Int = 0,
+ @JsonProperty("model_name") val modelName: String = "",
+ val destination: String = "",
+ @JsonProperty("device_id") val deviceId: String = "",
+ @JsonProperty("system_id") val systemId: String = "",
+ @JsonProperty("system_version") val systemVersion: Double = 0.0,
+ @JsonProperty("api_version") val apiVersion: Double = 0.0,
+ @JsonProperty("netmodule_generation") val netmoduleGeneration: Int = 0,
+ @JsonProperty("netmodule_version") val netmoduleVersion: String = "",
+ @JsonProperty("netmodule_checksum") val netmoduleChecksum: String = "",
+ @JsonProperty("serial_number") val serialNumber: String = "",
+ @JsonProperty("category_code") val categoryCode: Int = 0,
+ @JsonProperty("operation_mode") val operationMode: String = "",
+ @JsonProperty("update_error_code") val updateErrorCode: String = "",
+ @JsonProperty("net_module_num") val netModuleNum: Int = 0,
+ @JsonProperty("update_data_type") val updateDataType: Int = 0,
+ @JsonProperty("analytics_info") val analyticsInfo: AnalyticsInfo = AnalyticsInfo()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Bluetooth.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Bluetooth.kt
new file mode 100644
index 0000000..a7d8f3c
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Bluetooth.kt
@@ -0,0 +1,9 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Bluetooth(
+ @JsonProperty("update_cancelable") val updateCancelable: Boolean = false,
+ @JsonProperty("tx_connectivity_type_max") val txConnectivityTypeMax: Int = 0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Ccs.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Ccs.kt
new file mode 100644
index 0000000..c1ddda2
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Ccs.kt
@@ -0,0 +1,8 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Ccs(
+ val supported: Boolean = false
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Distribution.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Distribution.kt
new file mode 100644
index 0000000..2f07dc3
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Distribution.kt
@@ -0,0 +1,12 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Distribution(
+ val version: Double = 0.0,
+ @JsonProperty("compatible_client") val compatibleClient: List = listOf(),
+ @JsonProperty("client_max") val clientMax: Int = 0,
+ @JsonProperty("server_zone_list") val serverZoneList: List = listOf(),
+ @JsonProperty("mc_surround") val mcSurround: McSurround = McSurround()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Features.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Features.kt
new file mode 100644
index 0000000..cc115c7
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Features.kt
@@ -0,0 +1,14 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Features(
+ @JsonProperty("response_code") val responseCode: Int = 0,
+ val system: System = System(),
+ val zone: List = listOf(),
+ val tuner: Tuner = Tuner(),
+ val netusb: Netusb = Netusb(),
+ val distribution: Distribution = Distribution(),
+ val ccs: Ccs = Ccs()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Input.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Input.kt
new file mode 100644
index 0000000..6805501
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Input.kt
@@ -0,0 +1,12 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Input(
+ val id: String = "",
+ @JsonProperty("distribution_enable") val distributionEnable: Boolean = false,
+ @JsonProperty("rename_enable") val renameEnable: Boolean = false,
+ @JsonProperty("account_enable") val accountEnable: Boolean = false,
+ @JsonProperty("play_info_type") val playInfoType: String = ""
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/MasterRole.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/MasterRole.kt
new file mode 100644
index 0000000..ca0d899
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/MasterRole.kt
@@ -0,0 +1,10 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class MasterRole(
+ @JsonProperty("surround_pair") val surroundPair: Boolean = false,
+ @JsonProperty("stereo_pair") val stereoPair: Boolean = false,
+ @JsonProperty("subwoofer_pair") val subwooferPair: Boolean = false
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/McPlaylist.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/McPlaylist.kt
new file mode 100644
index 0000000..2ca146c
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/McPlaylist.kt
@@ -0,0 +1,9 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class McPlaylist(
+ val size: Int = 0,
+ val num: Int = 0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/McSurround.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/McSurround.kt
new file mode 100644
index 0000000..f6310a0
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/McSurround.kt
@@ -0,0 +1,11 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class McSurround(
+ val version: Double = 0.0,
+ @JsonProperty("func_list") val funcList: List = listOf(),
+ @JsonProperty("master_role") val masterRole: MasterRole = MasterRole(),
+ @JsonProperty("slave_role") val slaveRole: SlaveRole = SlaveRole()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Netusb.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Netusb.kt
new file mode 100644
index 0000000..473a9d1
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Netusb.kt
@@ -0,0 +1,15 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Netusb(
+ @JsonProperty("func_list") val funcList: List = listOf(),
+ val preset: PresetX = PresetX(),
+ @JsonProperty("recent_info") val recentInfo: RecentInfo = RecentInfo(),
+ @JsonProperty("play_queue") val playQueue: PlayQueue = PlayQueue(),
+ @JsonProperty("mc_playlist") val mcPlaylist: McPlaylist = McPlaylist(),
+ @JsonProperty("net_radio_type") val netRadioType: String = "",
+ val tidal: Tidal = Tidal(),
+ val qobuz: Qobuz = Qobuz()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/PlayQueue.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/PlayQueue.kt
new file mode 100644
index 0000000..73796d9
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/PlayQueue.kt
@@ -0,0 +1,8 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class PlayQueue(
+ val size: Int = 0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Preset.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Preset.kt
new file mode 100644
index 0000000..2dac0f9
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Preset.kt
@@ -0,0 +1,9 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Preset(
+ val type: String = "",
+ val num: Int = 0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/PresetX.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/PresetX.kt
new file mode 100644
index 0000000..f5b5c92
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/PresetX.kt
@@ -0,0 +1,8 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class PresetX(
+ val num: Int = 0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Qobuz.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Qobuz.kt
new file mode 100644
index 0000000..27f4467
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Qobuz.kt
@@ -0,0 +1,8 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Qobuz(
+ @JsonProperty("login_type") val loginType: String = ""
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RangeStep.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RangeStep.kt
new file mode 100644
index 0000000..eb31e52
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RangeStep.kt
@@ -0,0 +1,11 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class RangeStep(
+ val id: String = "",
+ val min: Double = 0.0,
+ val max: Double = 0.0,
+ val step: Double = 0.0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RangeStepX.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RangeStepX.kt
new file mode 100644
index 0000000..544046c
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RangeStepX.kt
@@ -0,0 +1,11 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class RangeStepX(
+ val id: String = "",
+ val min: Int = 0,
+ val max: Int = 0,
+ val step: Int = 0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RecentInfo.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RecentInfo.kt
new file mode 100644
index 0000000..b04a8c2
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/RecentInfo.kt
@@ -0,0 +1,8 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class RecentInfo(
+ val num: Int = 0
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/SlaveRole.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/SlaveRole.kt
new file mode 100644
index 0000000..586ac1d
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/SlaveRole.kt
@@ -0,0 +1,10 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class SlaveRole(
+ @JsonProperty("surround_pair_l_or_r") val surroundPairLOrR: Boolean = false,
+ @JsonProperty("surround_pair_lr") val surroundPairLr: Boolean = false,
+ @JsonProperty("subwoofer_pair") val subwooferPair: Boolean = false
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/System.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/System.kt
new file mode 100644
index 0000000..221a7b5
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/System.kt
@@ -0,0 +1,14 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class System(
+ @JsonProperty("func_list") val funcList: List = listOf(),
+ @JsonProperty("zone_num") val zoneNum: Int = 0,
+ @JsonProperty("input_list") val inputList: List = listOf(),
+ val bluetooth: Bluetooth = Bluetooth(),
+ @JsonProperty("web_control_url") val webControlUrl: String = "",
+ @JsonProperty("party_volume_list") val partyVolumeList: List = listOf(),
+ @JsonProperty("hdmi_standby_through_list") val hdmiStandbyThroughList: List = listOf()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Tidal.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Tidal.kt
new file mode 100644
index 0000000..27760a0
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Tidal.kt
@@ -0,0 +1,8 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Tidal(
+ val mode: String = ""
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Tuner.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Tuner.kt
new file mode 100644
index 0000000..5aa28d7
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Tuner.kt
@@ -0,0 +1,10 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Tuner(
+ @JsonProperty("func_list") val funcList: List = listOf(),
+ @JsonProperty("range_step") val rangeStep: List = listOf(),
+ val preset: Preset = Preset()
+)
diff --git a/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Zone.kt b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Zone.kt
new file mode 100644
index 0000000..fd5ee71
--- /dev/null
+++ b/klanglicht-yamaha/src/main/kotlin/de/visualdigits/kotlin/klanglicht/model/yamahaavantage/features/Zone.kt
@@ -0,0 +1,22 @@
+package de.visualdigits.kotlin.klanglicht.model.yamahaavantage.features
+
+
+import com.fasterxml.jackson.annotation.JsonProperty
+
+data class Zone(
+ val id: String = "",
+ @JsonProperty("func_list") val funcList: List = listOf(),
+ @JsonProperty("input_list") val inputList: List = listOf(),
+ @JsonProperty("sound_program_list") val soundProgramList: List? = listOf(),
+ @JsonProperty("surr_decoder_type_list") val surrDecoderTypeList: List? = listOf(),
+ @JsonProperty("tone_control_mode_list") val toneControlModeList: List = listOf(),
+ @JsonProperty("link_control_list") val linkControlList: List = listOf(),
+ @JsonProperty("link_audio_delay_list") val linkAudioDelayList: List? = listOf(),
+ @JsonProperty("range_step") val rangeStep: List = listOf(),
+ @JsonProperty("scene_num") val sceneNum: Int = 0,
+ @JsonProperty("cursor_list") val cursorList: List? = listOf(),
+ @JsonProperty("menu_list") val menuList: List? = listOf(),
+ @JsonProperty("actual_volume_mode_list") val actualVolumeModeList: List = listOf(),
+ @JsonProperty("ccs_supported") val ccsSupported: List? = listOf(),
+ @JsonProperty("zone_b") val zoneB: Boolean? = false
+)
diff --git a/klanglicht-yamaha/src/test/kotlin/de/visualdigits/kotlin/klanglicht/feign/YamahaAvantageReceiverClientTest.kt b/klanglicht-yamaha/src/test/kotlin/de/visualdigits/kotlin/klanglicht/feign/YamahaAvantageReceiverClientTest.kt
new file mode 100644
index 0000000..d62579a
--- /dev/null
+++ b/klanglicht-yamaha/src/test/kotlin/de/visualdigits/kotlin/klanglicht/feign/YamahaAvantageReceiverClientTest.kt
@@ -0,0 +1,37 @@
+package de.visualdigits.kotlin.klanglicht.feign
+
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+
+internal class YamahaAvantageReceiverClientTest {
+
+ private val URL = "http://192.168.178.46"
+
+ @Test
+ fun testSet() {
+ val client = YamahaAvantageReceiverClient(URL)
+ val responseCode = client.setSurroundProgram("Sci-Fi")
+ assertEquals(0, responseCode.responseCode)
+ }
+
+ @Test
+ fun testInfo() {
+ val client = YamahaAvantageReceiverClient(URL)
+ val deviceInfo = client.deviceInfo()
+ println(deviceInfo)
+ }
+
+ @Test
+ fun testFeatures() {
+ val client = YamahaAvantageReceiverClient(URL)
+ val features = client.features()
+ println(features)
+ }
+
+ @Test
+ fun testSoundProgramList() {
+ val client = YamahaAvantageReceiverClient(URL)
+ val soundProgramList = client.soundProgramList()
+ println(soundProgramList)
+ }
+}
diff --git a/pom.xml b/pom.xml
index 1d09166..a1774fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,7 @@
klanglicht-core
klanglicht-rest
+ klanglicht-yamaha
@@ -56,6 +57,55 @@
1.5.0
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+
+
+ commons-codec
+ commons-codec
+ 1.15
+
+
+ com.google.guava
+ guava
+ 31.1-jre
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${version.jackson}
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${version.jackson}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${version.jackson}
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+ ${version.jackson}
+
+
+ com.fasterxml.jackson.module
+ jackson-module-kotlin
+ ${version.jackson}
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ ${version.jackson}
+
+
org.slf4j