Big refactor
Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
This commit is contained in:
		
							parent
							
								
									2202ba2fc0
								
							
						
					
					
						commit
						bed25ca03c
					
				
					 10 changed files with 461 additions and 132 deletions
				
			
		
							
								
								
									
										27
									
								
								internal/patterns/common.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								internal/patterns/common.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| package patterns | ||||
| 
 | ||||
| func Even(number int) bool { | ||||
| 	return number %2 == 0 | ||||
| } | ||||
| 
 | ||||
| func FillPanel(w int, h int, r byte, g byte, b byte) [][]RGBcolor { | ||||
| 	grid := make([][]RGBcolor, w) | ||||
| 	for i := 0; i < w; i++ { | ||||
| 		grid[i] = make([]RGBcolor, h) | ||||
| 	} | ||||
| 	for x := 0; x < w; x++ { | ||||
| 		for y := 0; y < h; y++ { | ||||
| 			var rgb [3]byte | ||||
| 			rgb[0] = r | ||||
| 			rgb[1] = g | ||||
| 			rgb[2] = b | ||||
| 			grid[x][y] = rgb | ||||
| 		} | ||||
| 	} | ||||
| 	return grid | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| func FillPanelRGB(w int, h int, colour RGBcolor) [][]RGBcolor { | ||||
| 	return FillPanel(w,h,colour[0],colour[1],colour[2]) | ||||
| } | ||||
							
								
								
									
										49
									
								
								internal/patterns/experiment.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								internal/patterns/experiment.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| package patterns | ||||
| 
 | ||||
| import "math" | ||||
| 
 | ||||
| var sineoffset int = 0 | ||||
| var lastSineSpeed uint16 = 0 | ||||
| 
 | ||||
| func Sinewave(w int, h int, bgColor RGBcolor, fgColor RGBcolor, speed uint16) [][]RGBcolor  { | ||||
| 	if speed != lastSineSpeed { | ||||
| 		lastSineSpeed = speed | ||||
| 		sineoffset = 0 | ||||
| 	} | ||||
|     sineoffset += int(speed/40) | ||||
| 	background := FillPanelRGB(w,h,bgColor) | ||||
| 	for x := 0; x < w; x++ { | ||||
| 		y := int(math.Round((math.Sin(float64(x+sineoffset))+1) / 2 * float64(h-1))) | ||||
| 		background[x][y] = fgColor | ||||
| 	} | ||||
| 	return background | ||||
| } | ||||
| 
 | ||||
| var lastSinePos int = 0 | ||||
| 
 | ||||
| func SineChase(w int, h int, bgColor RGBcolor, fgColor RGBcolor, speed uint16) [][]RGBcolor  { | ||||
| 	if speed != lastSineSpeed { | ||||
| 		lastSineSpeed = speed | ||||
| 		lastSinePos = 0 | ||||
| 	} | ||||
| 	background := FillPanelRGB(w,h,bgColor) | ||||
| 	y := int(math.Round((math.Sin(float64(lastSinePos))+1) / 2 * float64(h-1))) | ||||
| 	background[lastSinePos][y] = fgColor | ||||
| 	lastSinePos += 1 | ||||
| 	if lastSinePos >= w { | ||||
| 		lastSinePos = 0 | ||||
| 	} | ||||
| 	return background | ||||
| } | ||||
| 
 | ||||
| func ZigZag(w int, h int) [][]RGBcolor  { | ||||
| 	var bgColor = [3]byte{0,0,0} | ||||
| 	var fgColor = [3]byte{255,0,0} | ||||
| 	//var a = [5]int{2, 4, 6, 8, 10} | ||||
| 	background := FillPanelRGB(w,h,bgColor) | ||||
| 	for x := 0; x < w; x++ { | ||||
| 		y := x % (h-1) | ||||
| 		background[x][y] = fgColor | ||||
| 	} | ||||
| 	return background | ||||
| } | ||||
							
								
								
									
										16
									
								
								internal/patterns/gradient.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								internal/patterns/gradient.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| package patterns | ||||
| 
 | ||||
| // gradient returns from fromX to toX fading from (fromR,fromG,fromB) to (toR,toG,toB) | ||||
| // at least that's the idea. | ||||
| func Gradient(fromR byte, fromG byte, fromB byte, toR byte, toG byte, toB byte, fromX int, toX int) []byte { | ||||
| 	ret := make([]byte, toX*3) | ||||
| 	var stepR float32 = (float32(toR) - float32(fromR)) / (float32(toX) - float32(fromX)) | ||||
| 	var stepG float32 = (float32(toG) - float32(fromG)) / (float32(toX) - float32(fromX)) | ||||
| 	var stepB float32 = (float32(toB) - float32(fromB)) / (float32(toX) - float32(fromX)) | ||||
| 	for i := fromX; i < toX*3; i += 3 { | ||||
| 		ret[i] = fromR + byte(float32(i/3)*stepR) | ||||
| 		ret[i+1] = fromG + byte(float32(i/3)*stepG) | ||||
| 		ret[i+2] = fromB + byte(float32(i/3)*stepB) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
							
								
								
									
										27
									
								
								internal/patterns/plaincolour.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								internal/patterns/plaincolour.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| package patterns | ||||
| 
 | ||||
| import "math/rand" | ||||
| import "time" | ||||
| 
 | ||||
| func RedPanel(w int, h int) [][]RGBcolor { | ||||
| 	return FillPanel(w, h, 255, 0, 0) | ||||
| } | ||||
| 
 | ||||
| var lastColour RGBcolor | ||||
| var lastIteration uint16 = 0 | ||||
| 
 | ||||
| func RandomColourPanel(w int, h int, speed uint16) [][]RGBcolor { | ||||
| 	if lastIteration > 0 { | ||||
| 		lastIteration -= 40 | ||||
| 	} | ||||
| 	if lastIteration <= 0 { | ||||
| 		r := rand.New(rand.NewSource(time.Now().UnixNano())) | ||||
| 		var newColour RGBcolor | ||||
| 		newColour[0] = byte(r.Intn(255)) | ||||
| 		newColour[1] = byte(r.Intn(255)) | ||||
| 		newColour[2] = byte(r.Intn(255)) | ||||
| 		lastColour = newColour | ||||
| 		lastIteration = speed | ||||
| 	} | ||||
| 	return FillPanel(w, h, lastColour[0], lastColour[1], lastColour[2]) | ||||
| } | ||||
							
								
								
									
										68
									
								
								internal/patterns/plasma.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								internal/patterns/plasma.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| package patterns | ||||
| 
 | ||||
| import "math" | ||||
| 
 | ||||
| type RGBcolor = [3]byte | ||||
| 
 | ||||
| func plasmaRGBFromVal(val byte) (byte, byte, byte) { | ||||
| 	var r byte | ||||
| 	var g byte | ||||
| 	var b byte | ||||
| 	if val < 85 { | ||||
| 		r = val * 3 | ||||
| 		g = 255 - r | ||||
| 		b = 0 | ||||
| 	} else if val < 170 { | ||||
| 		b = (val - 85) * 3 | ||||
| 		r = 255 - b | ||||
| 		g = 0 | ||||
| 	} else { | ||||
| 		g = (val - 170) * 3 | ||||
| 		b = 255 - g | ||||
| 		r = 0 | ||||
| 	} | ||||
| 	return r, g, b | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| func LinearPlasma(l int) []byte { | ||||
| 	line := make([]byte, l*3) | ||||
| 	for i := 0; i < l*3; i += 3 { | ||||
| 		val := byte(i % 256) | ||||
| 		r, g, b := plasmaRGBFromVal(val) | ||||
| 		line[i] = r | ||||
| 		line[i+1] = g | ||||
| 		line[i+2] = b | ||||
| 	} | ||||
| 	return line | ||||
| } | ||||
| 
 | ||||
| var offset float64 = 0.5 | ||||
| 
 | ||||
| func PlasmaPanel(w int, h int, speed uint16) [][]RGBcolor { | ||||
| 	grid := make([][]RGBcolor, w) | ||||
| 	for i := 0; i < w; i++ { | ||||
| 		grid[i] = make([]RGBcolor, h) | ||||
| 	} | ||||
| 	scale := math.Pi * 2.0 / float64(w) | ||||
| 	step := float64(5 * speed / 40) | ||||
| 	offset -= step | ||||
| 	if offset < 0 { | ||||
| 		offset += 1.0 | ||||
| 	} | ||||
| 	for y := 0; y < h; y++ { | ||||
| 		for x := 0; x < w; x++ { | ||||
| 			u := math.Cos((float64(x) + offset) * scale) | ||||
| 			v := math.Cos((float64(y) + offset) * scale) | ||||
| 			w := math.Cos((float64(w) + offset) * scale) | ||||
| 			e := (u + v + w + 3.0) / 6.0 | ||||
| 			r, g, b := plasmaRGBFromVal(byte((offset + e) * 255)) | ||||
| 			var rgb [3]byte | ||||
| 			rgb[0] = r | ||||
| 			rgb[1] = g | ||||
| 			rgb[2] = b | ||||
| 			grid[x][y] = rgb | ||||
| 		} | ||||
| 	} | ||||
| 	return grid | ||||
| } | ||||
							
								
								
									
										17
									
								
								internal/patterns/staticpatterns.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								internal/patterns/staticpatterns.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| package patterns | ||||
| 
 | ||||
| func AlternateRGBLinear(R0 byte, G0 byte, B0 byte, R1 byte, G1 byte, B1 byte, fromX int, toX int) []byte { | ||||
| 	ret := make([]byte, toX*3) | ||||
| 	for i := fromX; i < toX*3; i += 3 { | ||||
| 		if Even(i) { | ||||
| 			ret[i] = R0 | ||||
| 			ret[i+1] = G0 | ||||
| 			ret[i+2] = B0 | ||||
| 		} else { | ||||
| 			ret[i] = R1 | ||||
| 			ret[i+1] = G1 | ||||
| 			ret[i+2] = B1 | ||||
| 		} | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
							
								
								
									
										7
									
								
								internal/queue/queue.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								internal/queue/queue.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| package queue | ||||
| 
 | ||||
| type QueueItem struct { | ||||
| 	Effect string | ||||
| 	Duration uint16 | ||||
| 	Speed uint16 //only used by some patterns | ||||
| } | ||||
							
								
								
									
										88
									
								
								internal/remapping/remapping.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										88
									
								
								internal/remapping/remapping.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,88 @@ | |||
| package remapping | ||||
| 
 | ||||
| type RGBcolor = [3]byte | ||||
| 
 | ||||
| func Even(number int) bool { | ||||
| 	return number %2 == 0 | ||||
| } | ||||
| 
 | ||||
| func Slice512(s []byte) [512]byte { | ||||
| 	var ret [512]byte | ||||
| 	for i := range s { | ||||
| 		if i < 512 { | ||||
| 			ret[i] = s[i] | ||||
| 		} | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func SliceUnlenthed(s [512]byte) []byte { | ||||
| 	ret := make([]byte, 512) | ||||
| 	for i := range s { | ||||
| 		ret[i] = s[i] | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func SliceRearrange(rowwidth int, rows int, alternaterows bool, inslice []byte) [][]byte { | ||||
| 	var flippedslice []byte | ||||
| 	if alternaterows { | ||||
| 		flippedslice = make([]byte, len(inslice)+3) | ||||
| 		for r := 0; r < rows; r++ { | ||||
| 			rowzero := (r * rowwidth * 3) | ||||
| 			if Even(r) { | ||||
| 				for c := 0; c < (rowwidth)*3; c += 3 { | ||||
| 					flippedslice[rowzero+c] = inslice[rowzero+c] | ||||
| 					flippedslice[rowzero+c+1] = inslice[rowzero+c+1] | ||||
| 					flippedslice[rowzero+c+2] = inslice[rowzero+c+2] | ||||
| 				} | ||||
| 			} else { | ||||
| 				x := rowwidth * 3 | ||||
| 				for c := 0; c < (rowwidth)*3; c += 3 { | ||||
| 					x = x - 3 | ||||
| 					flippedslice[rowzero+x] = inslice[rowzero+c] | ||||
| 					flippedslice[rowzero+x+1] = inslice[rowzero+c+1] | ||||
| 					flippedslice[rowzero+x+2] = inslice[rowzero+c+2] | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		flippedslice = inslice | ||||
| 	} | ||||
| 	currentUniverse := 0 | ||||
| 	currentUniversePosition := 0 | ||||
| 	universes := make([][]byte, (len(flippedslice)/510)+1) | ||||
| 	currentUniverseSlice := make([]byte, 511) | ||||
| 	currentRowReverse := false | ||||
| 	for i := range flippedslice { | ||||
| 		if currentUniversePosition >= 510 { | ||||
| 			universes[currentUniverse] = currentUniverseSlice | ||||
| 			if !currentRowReverse { | ||||
| 				currentRowReverse = true | ||||
| 			} else { | ||||
| 				currentRowReverse = false | ||||
| 			} | ||||
| 			currentUniverse += 1 | ||||
| 			currentUniversePosition = 0 | ||||
| 			currentUniverseSlice = make([]byte, 511) | ||||
| 		} | ||||
| 		currentUniverseSlice[currentUniversePosition] = flippedslice[i] | ||||
| 		currentUniversePosition += 1 | ||||
| 	} | ||||
| 	universes[currentUniverse] = currentUniverseSlice | ||||
| 	return universes | ||||
| } | ||||
| 
 | ||||
| func XYGridToLinear(w int, h int, grid [][]RGBcolor) []byte { | ||||
| 	ret := make([]byte, w*h*3) | ||||
| 	i := 0 | ||||
| 	for y := 0; y < h; y++ { | ||||
| 		for x := 0; x < w; x++ { | ||||
| 			ret[i] = grid[x][y][0] | ||||
| 			ret[i+1] = grid[x][y][1] | ||||
| 			ret[i+2] = grid[x][y][2] | ||||
| 			i += 3 | ||||
| 		} | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
							
								
								
									
										70
									
								
								internal/webserver/webserver.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										70
									
								
								internal/webserver/webserver.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| package webserver | ||||
| 
 | ||||
| import ( | ||||
| 
 | ||||
| 	"github.com/gorilla/handlers" | ||||
| 	"github.com/gorilla/mux" | ||||
| 	queue "git.martyn.berlin/martyn/LEDController/internal/queue" | ||||
| 
 | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"time" | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| func HealthHandler(response http.ResponseWriter, request *http.Request) { | ||||
| 	response.Header().Add("Content-type", "text/plain") | ||||
| 	fmt.Fprint(response, "I'm okay jack!") | ||||
| } | ||||
| 
 | ||||
| func NotFoundHandler(response http.ResponseWriter, request *http.Request) { | ||||
| 	response.WriteHeader(404) | ||||
| 	fmt.Fprint(response, "I'm lost!") | ||||
| } | ||||
| 
 | ||||
| func RootHandler(response http.ResponseWriter, request *http.Request) { | ||||
| 	response.Header().Add("Content-type", "text/plain") | ||||
| 	fmt.Fprint(response, "Not implemented") | ||||
| } | ||||
| 
 | ||||
| var globalQueue chan queue.QueueItem; | ||||
| 
 | ||||
| func PatternHandler(response http.ResponseWriter, request *http.Request) { | ||||
| 	vars := mux.Vars(request) | ||||
| 	response.Header().Add("Content-type", "text/plain") | ||||
| 	var e queue.QueueItem | ||||
| 	e.Effect = vars["pattern"] | ||||
| 	i, _ := strconv.Atoi(vars["duration"]) | ||||
| 	e.Duration = uint16(i) | ||||
| 	_, found := vars["speed"] | ||||
| 	if found { | ||||
| 		i, _ := strconv.Atoi(vars["speed"]) | ||||
| 		e.Speed = uint16(i) | ||||
| 		fmt.Printf("Speed passed %d\n",e.Speed) | ||||
| 	} else { | ||||
| 		e.Speed = 40 | ||||
| 	} | ||||
| 	globalQueue <- e | ||||
| 	fmt.Fprint(response, "OKAY") | ||||
| } | ||||
| 
 | ||||
| func HandleHTTP(queueChannel chan queue.QueueItem) { | ||||
| 	globalQueue = queueChannel | ||||
| 	r := mux.NewRouter() | ||||
| 	loggedRouter := handlers.LoggingHandler(os.Stdout, r) | ||||
| 	r.NotFoundHandler = http.HandlerFunc(NotFoundHandler) | ||||
| 	r.HandleFunc("/", RootHandler) | ||||
| 	r.HandleFunc("/healthz", HealthHandler) | ||||
| 	r.HandleFunc("/pattern/{pattern}/{duration}", PatternHandler) | ||||
| 	r.HandleFunc("/pattern/{pattern}/{duration}/{speed}", PatternHandler) | ||||
| 	http.Handle("/", r) | ||||
| 	srv := &http.Server{ | ||||
| 		Handler:      loggedRouter, | ||||
| 		Addr:         "0.0.0.0:5353", | ||||
| 		WriteTimeout: 15 * time.Second, | ||||
| 		ReadTimeout:  15 * time.Second, | ||||
| 	} | ||||
| 	fmt.Println("Listening on 0.0.0.0:5353") | ||||
| 	srv.ListenAndServe() | ||||
| } | ||||
							
								
								
									
										224
									
								
								main.go
									
										
									
									
									
								
							
							
						
						
									
										224
									
								
								main.go
									
										
									
									
									
								
							|  | @ -1,154 +1,114 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"time" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	webserver "git.martyn.berlin/martyn/LEDController/internal/webserver" | ||||
| 	queue "git.martyn.berlin/martyn/LEDController/internal/queue" | ||||
| 	remapping "git.martyn.berlin/martyn/LEDController/internal/remapping" | ||||
| 	patterns "git.martyn.berlin/martyn/LEDController/internal/patterns" | ||||
| 
 | ||||
| 	"github.com/Hundemeier/go-sacn/sacn" | ||||
| ) | ||||
| 
 | ||||
| func even(number int) bool { | ||||
|     return number%2 == 0 | ||||
| } | ||||
| type RGBcolor = [3]byte | ||||
| 
 | ||||
| func slice_rearrange(rowwidth int, rows int, alternaterows bool, inslice []byte) [][]byte { | ||||
| 	var flippedslice []byte | ||||
| 	if alternaterows { | ||||
| 		flippedslice = make([]byte, len(inslice)+3) | ||||
| 		for r := 0; r < rows; r++ { | ||||
| 			rowzero := (r*rowwidth*3) | ||||
| 			if even(r) { | ||||
| 				for c := 0; c < (rowwidth)*3; c+=3 { | ||||
| 					flippedslice[rowzero+c] = inslice[rowzero+c] | ||||
| 					flippedslice[rowzero+c+1] = inslice[rowzero+c+1] | ||||
| 					flippedslice[rowzero+c+2] = inslice[rowzero+c+2] | ||||
| 				} | ||||
| 			} else { | ||||
| 				x := rowwidth*3 | ||||
| 				for c := 0; c < (rowwidth)*3; c+=3 { | ||||
| 					x = x-3 | ||||
| 					fmt.Println(x) | ||||
| 					flippedslice[rowzero+x] = inslice[rowzero+c] | ||||
| 					flippedslice[rowzero+x+1] = inslice[rowzero+c+1] | ||||
| 					flippedslice[rowzero+x+2] = inslice[rowzero+c+2]/* | ||||
| 					flippedslice[rowzero+c] = inslice[rowzero+(((rowwidth-1)*3)-c)] | ||||
| 					flippedslice[rowzero+c+1] = inslice[rowzero+(((rowwidth-1)*3)-c)-1] | ||||
| 					flippedslice[rowzero+c+2] = inslice[rowzero+(((rowwidth-1)*3)-c)-2]*/ | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		flippedslice = inslice | ||||
| 	} | ||||
| 	currentUniverse := 0 | ||||
| 	currentUniversePosition := 0 | ||||
| 	universes := make([][]byte, (len(flippedslice)/510)+1) | ||||
| 	currentUniverseSlice := make([]byte, 511) | ||||
| 	currentRowReverse := false; | ||||
| 	for i := range(flippedslice) { | ||||
| 		if currentUniversePosition >= 510 { | ||||
| 			fmt.Println("Reached end of universe!") | ||||
| 			universes[currentUniverse] = currentUniverseSlice | ||||
| 			if (!currentRowReverse) { | ||||
| 				currentRowReverse = true | ||||
| 			} else { | ||||
| 				currentRowReverse = false | ||||
| 			} | ||||
| 			currentUniverse += 1 | ||||
| 			currentUniversePosition = 0 | ||||
| 			currentUniverseSlice = make([]byte, 511) | ||||
| 		} | ||||
| 		currentUniverseSlice[currentUniversePosition] = flippedslice[i] | ||||
| 		currentUniversePosition += 1 | ||||
| 	} | ||||
| 	universes[currentUniverse] = currentUniverseSlice | ||||
|   	return universes | ||||
| } | ||||
| var currentFrame [2][512]byte | ||||
| var channels [2]chan<-[512]byte  | ||||
| var sema = make(chan struct{}, 1) // a binary semaphore guarding currentFrame | ||||
| 
 | ||||
| func alternate(R0 byte, G0 byte, B0 byte, R1 byte, G1 byte, B1 byte, fromX int, toX int) []byte { | ||||
| 	ret := make([]byte, toX*3); | ||||
| 	for i := fromX; i < toX*3; i+=3 { | ||||
| 		if even(i) { | ||||
| 			ret[i] = R0 | ||||
| 			ret[i+1] = G0 | ||||
| 			ret[i+2] = B0 | ||||
| 		} else { | ||||
| 			ret[i] = R1 | ||||
| 			ret[i+1] = G1 | ||||
| 			ret[i+2] = B1 | ||||
| var currentEffect queue.QueueItem; | ||||
| var globalEffectChannel = make(chan queue.QueueItem, 1024) | ||||
| 
 | ||||
| func foreverLoop() { | ||||
| 	for /*ever*/ { | ||||
| 		time.Sleep(40 * time.Millisecond) //25fps | ||||
| 		for u := 0; u < 2; u++ { | ||||
| 			sema <- struct{}{} // acquire token | ||||
| 			channels[u] <- currentFrame[u] | ||||
| 			<- sema | ||||
| 		} | ||||
| 	} | ||||
|     return ret | ||||
| } | ||||
| 
 | ||||
| // gradient returns from fromX to toX fading from (fromR,fromG,fromB) to (toR,toG,toB) | ||||
| // at least that's the idea. | ||||
| func gradient(fromR byte, fromG byte, fromB byte, toR byte, toG byte, toB byte, fromX int, toX int) []byte { | ||||
| 	ret := make([]byte, toX*3); | ||||
| 	var stepR float32 = (float32(toR) - float32(fromR)) / (float32(toX) - float32(fromX)) | ||||
| 	var stepG float32 = (float32(toG) - float32(fromG)) / (float32(toX) - float32(fromX)) | ||||
| 	var stepB float32 = (float32(toB) - float32(fromB)) / (float32(toX) - float32(fromX)) | ||||
| 	for i := fromX; i < toX*3; i+=3 { | ||||
| 		ret[i] = fromR+byte(float32(i/3)*stepR) | ||||
| 		ret[i+1] = fromG+byte(float32(i/3)*stepG) | ||||
| 		ret[i+2] = fromB+byte(float32(i/3)*stepB) | ||||
| 	} | ||||
|     return ret | ||||
| } | ||||
| 
 | ||||
| func slice512(s []byte) [512]byte { | ||||
| 	var ret [512]byte | ||||
| 	for i := range(s) { | ||||
| 		if i < 512 { | ||||
| 			ret[i] = s[i] | ||||
| 		} | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func sliceUnlenthed(s [512]byte) []byte { | ||||
| 	ret := make([]byte, 512) | ||||
| 	for i := range(s) { | ||||
| 		ret[i] = s[i] | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	go func() { | ||||
| 		fmt.Printf("Starting webserver on port %s\n", "5353") | ||||
| 		webserver.HandleHTTP(globalEffectChannel) | ||||
| 	}() | ||||
| 	//instead of "" you could provide an ip-address that the socket should bind to | ||||
| 	trans, err := sacn.NewTransmitter("", [16]byte{1, 2, 3}, "test") | ||||
| 	trans, err := sacn.NewTransmitter("", [16]byte{1, 2}, "test") | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	 | ||||
| 	//activates the first universe | ||||
| 	ch1, err := trans.Activate(1) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	ch2, err := trans.Activate(2) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	//deactivate the channel on exit | ||||
| 	defer close(ch1) | ||||
| 	defer close(ch2) | ||||
| 
 | ||||
| 	//set a unicast destination, and/or use multicast | ||||
| 	trans.SetMulticast(1, false)//this specific setup will not multicast on windows,  | ||||
| 	//because no bind address was provided | ||||
| 	 | ||||
| 	//set some example ip-addresses | ||||
| 	trans.SetDestinations(1, []string{"192.168.1.139"}) | ||||
| 	trans.SetMulticast(2, false)//this specific setup will not multicast on windows,  | ||||
| 	trans.SetDestinations(2, []string{"192.168.1.139"}) | ||||
| 	 | ||||
| 	//send some random data for 10 seconds | ||||
| 	for i := 0; i < 20; i++ { | ||||
| 		channels := slice_rearrange(68,4,true,gradient(255,255,255,0,0,0,0,272)) | ||||
| 		ch1 <- slice512(channels[0]) | ||||
| 		ch2 <- slice512(channels[1]) | ||||
| 		time.Sleep(500 * time.Millisecond) | ||||
| 	//activates the universes | ||||
| 	for i := 0; i < 2; i++ { | ||||
| 		channels[i], err =  trans.Activate(uint16(i+1)) | ||||
| 		//deactivate the channel on exit | ||||
| 		defer close(channels[i]) | ||||
| 		trans.SetMulticast(uint16(i+1), false) //this specific setup will not multicast on windows, | ||||
| 		trans.SetDestinations(uint16(i+1), []string{"192.168.1.139"}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 	// Plasma for start frame | ||||
| 	rearranged := remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.PlasmaPanel(68, 4, 40))) | ||||
| 	currentFrame[0] = remapping.Slice512(rearranged[0]) | ||||
| 	currentFrame[1]	= remapping.Slice512(rearranged[1]) | ||||
| 	var e queue.QueueItem | ||||
| 	e.Effect = "red" | ||||
| 	e.Duration = 40 * 50 | ||||
| 	globalEffectChannel <- e | ||||
| 	e.Effect = "plasma" | ||||
| 	e.Duration = 0 | ||||
| 	e.Speed = 40 | ||||
| 	globalEffectChannel <- e | ||||
| 
 | ||||
| 	go func() { | ||||
| 		for /*ever*/ { | ||||
| 			if currentEffect.Duration > 0 { | ||||
| 				currentEffect.Duration -= 40 | ||||
| 			} else { | ||||
| 				if len(globalEffectChannel) > 0 { | ||||
| 					currentEffect = <- globalEffectChannel | ||||
| 				} | ||||
| 			} | ||||
| 			var rearranged [][]byte | ||||
| 			switch currentEffect.Effect { | ||||
| 				case "line": | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.ZigZag(68, 4))) | ||||
| 				case "plasma": | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.PlasmaPanel(68, 4, currentEffect.Speed))) | ||||
| 				case "red": | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, false, remapping.XYGridToLinear(68, 4, patterns.RedPanel(68,4))) | ||||
| 				case "random": | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, false, remapping.XYGridToLinear(68, 4, patterns.RandomColourPanel(68,4,currentEffect.Speed))) | ||||
| 				case "linearplasma": | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, false, patterns.LinearPlasma(68*4)) | ||||
| 				case "gradientred": | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, false, patterns.Gradient(255, 0, 0, 0, 0, 255, 0, 68*4)) | ||||
| 				case "sine": | ||||
| 					var black patterns.RGBcolor | ||||
| 					var red patterns.RGBcolor | ||||
| 					red[0] = 255 | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.Sinewave(68, 4, black, red, currentEffect.Speed))) | ||||
| 				case "sinechase": | ||||
| 					var black patterns.RGBcolor | ||||
| 					var red patterns.RGBcolor | ||||
| 					red[0] = 255 | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.SineChase(68, 4, black, red, currentEffect.Speed))) | ||||
| 			    default: | ||||
| 					rearranged = remapping.SliceRearrange(68, 4, false, remapping.XYGridToLinear(68, 4, patterns.FillPanel(68,4, 128,0,128))) | ||||
| 			} | ||||
| 			//rearranged := remapping.SliceRearrange(68,4,true,linearPlasma(68*4)) | ||||
| 			sema <- struct{}{} // acquire token | ||||
| 			currentFrame[0] = remapping.Slice512(rearranged[0]) | ||||
| 			currentFrame[1]	= remapping.Slice512(rearranged[1]) | ||||
| 			<- sema | ||||
| 			time.Sleep(40 * time.Millisecond) | ||||
| 		} | ||||
| 	}() | ||||
| 	foreverLoop(); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue