+ Aurora generates graphics for up to 4 lasers. Pick 4 between all possible effects. Say you want 3 starfields and some word in the middle ?
+ Aurora generators :
+
+ Vertical line : scanning effect.
+ Horizontal line : scanning effect.
+ Wave : Simple wave form.
+ Circle : Simple circle form
+ Starfield : One different Starfield/laser
+ Text : One word per laser.
+ Live face tracking : Display your wiredframed face using your phone/webcam.
+
+
+
+
+
+
Aurora full interface
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/concepts.html b/doc/concepts.html
new file mode 100644
index 0000000..26a2afc
--- /dev/null
+++ b/doc/concepts.html
@@ -0,0 +1,135 @@
+
+
+
+
+ LJ Laser server
+
+
+
+
+
+
+
+
+
+
+
"Plugins" : points generators (to one or more lasers). Lot examples comes with LJ : planetarium, 3D anaglyph animations,... See plugins page.
+
A "tracer" per etherdream/laser : take its given point list, correct geometry, recompute in laser controller coordinates, send it and report the etherdream status to the "manager".
+
A "manager" that talk to all tracers (which point list to draw, new geometry correction, setup parameters,...), handle I/Os (UI functions, OSC commands,...) and manage plugins (launch, checks,...)
+
A web GUI in html, css, and vanilla js. No html server or js framework here : it's complex enough. This GUI has a simulator, but one can used a builtin python simulator (pysimu) or an included etherdream/laser emulator ("visualiser" from nannou) to work without physical lasers !!
+
A network available database (redis) as backbone. "Plugins" send directly their points lists to redis and each "tracer" is instructed to get one of the available points list in redis.
+
+
+
+ Add polylines to layers
+
+
+ Sprites : "Polyline" (i.e : 4 closed points to draw a square) or "rPolyline" (with built in parameters to resize, rotate, translate,...).
+
+ "Layers" : Store multiple Polylines or rPolylines. No layers limits. "Layer" = "Point List".
+
+ "Destinations" : To what Scene/laser send a given layer. One layer can have multiple destinations (to duplicate content on different lasers). Destinations can be fixed or relative (like rPolyline with builtin resize, rotations,...).
+
+
+
+
+ Virtual scenes with different or same layers.
+
+
+ Up to 4 Virtual scenes for up to 4 lasers. You choose at anytime wich scene is actually drawn by lasers. Look, scene 3 uses the exact same man on one layer, but this layer is registered on 4 "relative destinations"(with different builtin resize parameter, one destination per laser).
+
+
+ "Objects" : Store parameters for a category. Imagine in a game suddenly all NPC turn to red. A"FixedObject"store parameters used in polylines, a"RelativeObject" store also additionnal parameters like rPolylines parameters.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/custom404.html b/doc/custom404.html
new file mode 100644
index 0000000..f41e8f4
--- /dev/null
+++ b/doc/custom404.html
@@ -0,0 +1,13 @@
+
+
+ Custom 404
+
+
+
+
+
This is an example of a customized 404 error page.
NOTE - This page is for the previous Ether Dream 1. Check the current website.
+
+ The Ether Dream DMX interface is an add-on board for the Ether Dream
+ that allows it to control external DMX devices and receive DMX input. New firmware
+ allows the Ether Dream to work as a DMX-to-OSC and OSC-to-DMX bridge, for compatibility
+ with a wide variety of other software.
+
+
+
+
Features
+
+
3-pin and 5-pin XLR connectors available
+
DMX in, thru (electrically connected to in), and out
+
Optional full electrical isolation for noise and damage resistance
+
Driver support in Ether Dream DLLM
+
Standard OSC interface
+
Future: control of laser output via DMX commands
+
Works with any production Ether Dream with firmware v0.5.0 or later, available from the Downloads page
+
+
+
Connection Diagram
+
+ Use the included 6-pin jumper cable to connect the DMX board to one of the serial expansion headers on the Ether Dream.
+ Match pin 1 on the Ether Dream to pin 1 on the DMX board. Serial expansion header #1 correponds to DMX universe 1, and
+ likewise for 2 and 3. Only header 1 can currently be used for input.
+
+ This is a work-in-progress developer-oriented guide to the hardware features and software architecture
+ of the Ether Dream DAC. For setup and usage tips, see the User
+ Guide.
+
+
+
Hardware
+
+
+ Starting at the Ethernet connector on the board and moving counterclockwise, the
+ hardware features and connectors on the board are:
+
+
+
Ethernet connector - includes link and activity LEDs
+
USB connector. This is currently used only for firmware upgrades.
+
Status LED. This LED blinks when the board is in bootloader mode, and
+ is on normally.
+
MicroSD slot. This will be used, in future software updates, for settings
+ and playback of stored shows.
+
External power jack. This is a 2.1mm/5.5mm barrel connector, center-positive,
+ accepting 8V-25V DC.
+
Power supply screw terminals. Ground is on the left (towards the outside of
+ the board), positive is on the right (towards the inside of the board).
+ The two power inputs are isolated from one another with diodes; if both
+ are connected, power will be drawn only from the one with the higher voltage.
+
GPIO header. This connects extra pins from the microcontroller. Pin 1 is closest
+ to the power jack. The pinout is:
+
+
1 - P1[8] / PWM1[1] / CAP1[0]
2 - +5.5v supply
+
3 - P1[19] / MCOA0 / CAP1[1]
4 - P1[22] / MCOB0 / MAT1[0]
+
5 - P1[26] / MCOB1 / PWM1[6] / CAP0[0]
6 - P1[29] / MCOB[2] / PCAP1[1] / MAT0[1]
+
7 - +3.3v supply
8 - P0[15] / TXD1 / SCK0 / SCK
+
9 - ground
10 - P0[17] / CTS1 / MISO0 / MISO
+
11 - P0[18] / DCD1 / MOSI0 / MOSI
12 - P0[16] / RXD1 / SSEL0 / SSEL
+
+
+
Serial header #2. Pinout:
+
+
1 - P0[10] / TXD2 / SDA2 / MAT3[0]
2 - +5.5v supply
+
3 - P0[11] / RXD2 / SCL2 / MAT3[1]
4 - +3.3v supply
+
5 - P1[28] / MCOA2 / PCAP1[0] / MAT0[0]
6 - ground
+
+
+
Interlock LED (yellow). This LED is on whenever the interlock relay is closed.
+
ILDA DB-25 connector.
+
Behind the DB-25 connector: 2x13 pin header wired identically to the DB-25.
+
Emission LED (green). Whenever the DAC is producing output, this LED is on.
+
20-pin ARM JTAG header. Pin 1 is towards the power connectors.
+
1x6 pin serial debug header. This is intended to be used for debug purposes with a
+ TTL serial adapter, such as this unit
+ available from sparkfun. Pin 1 is closest to the Ethernet connector. The pinout is:
+
+
1 - P2[10]/EINT0/NMI
+
2 - P0[2] / TXD0 / AD0[7]
+
3 - P0[3] / RXD0 / AD0[6]
+
4 - unconnected
+
5 - unconnected
+
6 - ground
+
+
+
Serial header #1. Pinout:
+
+
1 - P2[0] / PWM1[1] / TXD1
2 - +5.5v supply
+
3 - P2[1] / PWM1[2] / RXD1
4 - +3.3v supply
+
5 - P2[2] / PWM1[3] / CTS1
6 - ground
+
+
+
Serial header #3. Pinout:
+
+
1 - P0[25] / AD0[2] / I2SRX_SDA / TXD3
2 - +5.5v supply
+
3 - P0[26] / AD0[3] / AOUT / RXD3
4 - +3.3v supply
+
5 - P2[3] / PWM1[4] / DCD1
6 - ground
+
+
+
+
Configuration
+
+ The Ether Dream requires no network configuration. By default, it will attempt to acquire
+ an IP address with DHCP; if no DHCP server is found, it will instead choose a link-local
+ 169.254.x.x address. Once it has an address, it will begin advertising its presence with
+ UDP broadcast packets on port 7654. The playback DLL looks for these broadcasts to find
+ DACs on the network.
+
+ The Ether Dream firmware, available on github,
+ builds on a standard Linux system with the free CodeSourcery ARM toolchain. The README in the
+ repository describes the needed tools.
+
Firmware Updates
+ There are three ways of updating the Ether Dream's firmware:
+
+
USB
+
+ The Ether Dream board comes with a USB bootloader in the first 16kB of Flash. (Source
+ for the bootloader is in the boot/ directory of the source tree.) This bootloader
+ implements the standard DFU protocol; the dfu-util project provides a PC-side tool.
+
+
+ The bootloader runs on every power-up, but normally immediately jumps to the main firmware.
+ If the firmware is corrupt or the DAC has been forced into bootloader mode, it will
+ instead run and appear as a USB DFU device. This mode is indicated by the LED
+ next to the USB connector flashing rapidly. There are
+ two ways to force the DAC to run in bootloader mode:
+
+
Hold P0[18] low during power-on.
+
Send a special USB control request while the normal firmware is running.
+ There is a tool to
+ do this in the source repository.
+
The pin to force bootloader mode, P0[18], is located next to a ground pin on the 2x6
+ expansion header. Connect a jumper across these pins and then apply power to run
+ the bootloader.
+
+
+
+ On the host PC, if dfu-util is installed, running "make bl" in the firmware directory
+ will automatically update the firmware of an attached DAC. Either force the DAC into
+ bootloader mode and run "make bl", or "make bl" while the DAC is running its usual
+ firmware; in the latter case, the DAC will be rebooted into bootloader mode and then
+ updated.
+
+
+
Serial
+
There is a built-in ROM bootloader on the LPC1758 which runs over UART0,
+ connected to the 1x6 header on the board. It enters if P2[10] is held low when
+ power is applied. When the ROM bootloader is running, both LEDs on the board will
+ be very dimly lit. The lpc21isp
+ tool talks to the DAC in this mode.
+
+
+ P2[10] on the LPC1758 is connected to RTS on the 6-pin serial header. Running "make
+ flash" in the firmware directory and then applying power to the DAC will
+ update the firmware and USB bootloader over serial.
+
+
This method is somewhat slower than the USB bootloader and so is not generally
+ recommended - it is useful primarily for installing the firmware into a
+ previously-unprogrammed DAC. Also, note that the 6-pin serial header is logic-level;
+ it is 5-volt-tolerant but must not be connected directly to an RS-232 port.
+
+
+
JTAG
+
The LPC1758 Flash can be reprogrammed over JTAG with openocd. See the
+ user's manual for the microcontroller and the openocd documentation for details.
+ Communication with the DAC happens over TCP on port 7765. The DAC will only
+ communicate with one host at a time; another device that connects while the DAC
+ has an established control connection will have its connection attempt rejected.
+
+ If the host does not send anything to the device for one second, the device will close
+ the TCP connection. TODO: The 1-second timeout is not implemented, but will be
+ in the future.
+
+
+ The DAC has a USB interface as well. This is used for firmware updates. TODO:
+ In the future, the USB interface may also emulate a standard USB CDC-ECM network
+ device. This would allow the same communication protocol to be spoken over USB. In
+ this mode, the DAC would choose a link-local IP address.
+
+
+ In this document, protocol messages are described as structs. Fields are packed
+ together with no padding (__attribute__((packed)) or #pragma pack(1));
+ standard C typedefs such as uint8_t, uint32_t, int32_t, etc. have
+ their usual meanings, and multi-byte values are transmitted little-endian
+ ("host" byte order on x86 and ARM): the most significant byte appears first.
+
+
+
State Machines
+
+
+ There are three distinct state machines within the DAC: light engine, playback, and source. The light
+ engine states are:
+
+
+
0: Ready.
+
1: Warmup. In the case where the DAC is also used for thermal control of laser apparatus,
+ this is the state that is entered after power-up.
+
2: Cooldown. Lasers are off but thermal control is still active.
+
3: Emergency stop. An emergency stop has been triggered, either by an E-stop input on the DAC,
+ an E-stop command over the network, or a fault such as over-temperature.
+
+
+ TODO: Since thermal control is not implemented yet, it is not defined how
+ transitions to and from the "Warmup" and "Cooldown" states occur.
+
+
+ The DAC has one playback system, which buffers data and sends it to the analog output
+ hardware at its current point rate. At any given time, the playback system is connected
+ to a source. Usually, the source is the network streamer, which uses the protocol described
+ in this document; however, other sources exist, such as a built-in abstract generator and
+ file playback from SD card. The playback system is in one of the following states:
+
+
+
0: Idle. This is the default state. No points may be added to the buffer. No output is
+ generated; all analog outputs are at 0v, and the shutter is controlled by the data source.
+
1: Prepared. The buffer will accept points. The output is the same as in the Idle state.
+
2: Playing. Points are being sent to the output.
+
+
+
Status Responses
+
+
Periodically, and as part of ACK packets, the DAC sends to the host information on its
+ current playback status. The status struct is:
+ The light_engine_state field gives the current state of the light engine. If the light engine
+ is Ready, light_engine_flags will be 0. Otherwise, bits in light_engine_flags will be set as follows:
+
+
+
[0]: Emergency stop occurred due to E-Stop packet or invalid command.
+
[1]: Emergency stop occurred due to E-Stop input to projector.
+
[2]: Emergency stop input to projector is currently active.
+
[3]: Emergency stop occurred due to overtemperature condition.
+
[4]: Overtemperature condition is currently active.
+
[5]: Emergency stop occurred due to loss of Ethernet link.
+
[15:5]: Future use.
+
+
+
Similarly, playback_state gives the state of the playback system. The playback_flags field may
+ be nonzero during normal operation. Its bits are defined as follows:
+
+
[0]: Shutter state: 0 = closed, 1 = open.
+
[1]: Underflow. 1 if the last stream ended with underflow, rather than a
+ Stop command. Reset to zero by the Prepare command.
+
[2]: E-Stop. 1 if the last stream ended because the E-Stop state was entered.
+ Reset to zero by the Prepare command.
+
+
+ The buffer_fullness field contains the number of points currently buffered.
+ point_rate is the number of points per second for which the DAC is configured (if Prepared or
+ Playing), or zero if the DAC is idle. point_count is the number of points that the DAC has
+ actually emitted since it started playing (if Playing), or zero (if Prepared or Idle).
+
+
+ The currently-selected data source is specified in the source field:
+
+
+
0: Network streaming (the protocol defined in the rest of this document).
+
1: ILDA playback from SD card.
+
2: Internal abstract generator.
+
+
+
Broadcast
+
+ Regardless of the data source being used, each DAC broadcasts a status/ID datagram over UDP to
+ its local network's broadcast address once per second. This datagram is formed as follows:
+
+ When a host first connects to the device, the device immediately sends it a status reply,
+ as if the host had sent a ping packet (described later). The host sends to the device a
+ series of commands. All commands receive a response from the DAC; responses are described
+ after the list of commands. The commands are as follows:
+
+
+
Prepare Stream
+
Single byte: 'p' (0x70)
+
This command causes the playback system to enter the Prepared state. The DAC resets its buffer to
+ be empty and sets "point_count" to 0. This command may only be sent if the light engine is Ready
+ and the playback system is Idle. If so, the DAC replies with ACK; otherwise, it replies with NAK - Invalid.
This causes the DAC to begin producing output. point_rate is the number of points per second to be
+ read from the buffer. If the playback system was Prepared and there was data in the buffer, then the
+ DAC will reply with ACK; otherwise, it replies with NAK - Invalid.
+
TODO: The low_water_mark parameter is currently unused.
This adds a new point rate to the point rate buffer. Point rate changes are read out of the buffer when
+ a point with an appropriate flag is played; see the Write Data command. If the DAC is not Prepared or
+ Playing, it replies with NAK - Invalid. If the point rate buffer is full, it replies with NAK - Full.
+ Otherwise, it replies with ACK.
This provides data for the DAC to add to its buffer. The data values are full-scale (for instance,
+ for color channels, 65535 is full output); the least-significant bits of each word will be ignored
+ if the DAC’s resolution is less than 16 bits. The DAC will reply with ACK if the incoming packet
+ can fully fit in its buffer, or NAK - Full if it cannot. It is valid for npoints to be zero; in
+ this case, no point will be added to the buffer, but the packet will still be ACKed (as long as
+ the DAC is Prepared or Playing.)
+
The "control" field has the following fields defined:
+
+
[15]: Change point rate. If this bit is set, and there are any values in the point rate change
+ buffer, then a new rate is read out of the buffer and set as the current playback rate. If the
+ buffer is empty, the point rate is not changed.
+
Other bits: reserved for future expansion to support extra TTL outputs, etc.
+
+
+
Stop
+
Single byte: 's' (0x73)
+
The stop command causes the DAC to immediately stop playing and return to the Idle state. It is
+ ACKed if the DAC was Playing or Prepared; otherwise it is replied to with NAK - Invalid.
+
+
Emergency Stop
+
Single byte: 0x00 or 0xFF. (The DAC will recognize either one.)
+
The e-stop command causes the light engine to enter the E-Stop state, regardless
+ of its previous state. It is always ACKed.
+
Any unrecognized command will also be trested as E-stop; however, software should not send
+ undefined commands deliberately, since they may be defined in the future.
+
+
Clear E-Stop
+
Single byte: 'c' (0x63)
+
If the light engine was in E-Stop state due to an emergency stop command (either from a local
+ stop condition or over the network), then this command resets it to be Ready. It is ACKed if the
+ DAC was previously in E-Stop; otherwise it is replied to with a NAK - Invalid. If the condition
+ that caused the emergency stop is still active (E-Stop input still asserted, temperature still
+ out of bounds, etc.), then a NAK - Stop Condition is sent.
+
+
Ping
+
Single byte: '?' (0x3F)
+
The DAC will reply to this with an ACK packet. This serves as a keep-alive for the connection when
+ the DAC is not actively streaming.
In the case of ACK/NAK responses, "command" echoes back the command to which the response is sent.
+ (Commands are always sent in order, so this field exists for sanity-checking on the host side.)
+ The response field can be one of the following:
+
+
ACK - 'a' (0x61) - The previous command was accepted.
+
NAK - Full - 'F' (0x46) - The write command could not be performed because there was not
+ enough buffer space when it was received.
+
NAK - Invalid - 'I' (0x49) - The command contained an invalid command byte or parameters.
+
NAK - Stop Condition - '!' (0x21) - An emergency-stop condition still exists.
+
+ Congratulations! Ether Dream is the most flexible, powerful, and open DAC available
+ today. It is designed to enable easy live playback from PC software and to serve
+ as a platform for experimentation and development.
+
+
+
+
Quick Start
+
+ To get started with your Ether Dream, just connect its output to your
+ projector, its Ethernet connection to your network or computer, and then
+ the power supply to a source of 9-25v DC or to the included adapter.
+ The green LED next to the USB connector will light to
+ indicate that power is on, and the yellow LED next to the ILDA connector
+ will light to indicate that the interlock is now closed.
+
+
+ If you're connecting to a home network with a router or DHCP server, no
+ other configuration will be needed - any computer on the network will
+ be able to reach the Ether Dream. If you connect the Ether Dream directly
+ to your computer, make sure that it is set to obtain its IP address
+ automatically.
+
+
+ To make sure that your computer can communicate properly with your Ether
+ Dream, a diagnostic tool is available on the
+ Downloads page.
+
+
Note: you may need to disable or adjust the settings on your firewall
+ software to be able to communicate with the Ether Dream. The driver DLL
+ uses TCP port 7765 and UDP port 7654.
+
+
+ LSX, ILD SÔS, and other software using the
+ universal DAC interface library written by drlava have native
+ Ether Dream support. However, a software update may be needed - support was only added to the library
+ in late October 2011. Contact drlava for an updated build of LSX or ILD SÔS. Other software that works with ezauddac.dll can be set up to use an Ether Dream by making a backup of
+ its ezauddac.dll and renaming EtherDream.dll (from the Downloads page) to ezauddac.dll.
+
+
Once the driver DLL is installed, just start up the software and the Ether Dream will
+ automatically be detected.
+
+
+
Hardware
+
+
+ Starting at the Ethernet connector on the board and moving counterclockwise, the
+ indicators and connectors on the board are:
+
+
+
Ethernet connector - includes link and activity LEDs.
+
USB connector. This is currently used only for firmware upgrades.
+
Status LED. This LED blinks when the board is in bootloader mode, and
+ is on normally.
+
MicroSD slot. This is used for configuration and for playback of stored
+ content.
+
External power jack. This is a 2.1mm/5.5mm barrel connector, center-positive,
+ accepting 8V-25V DC at 300mA.
+
Power supply screw terminals. Ground is on the left (towards the outside of
+ the board), positive is on the right (towards the inside of the board).
+ The two power inputs are isolated from one another with diodes; if both
+ are connected, power will be drawn only from the one with the higher voltage.
+
GPIO header. This connects extra pins from the microcontroller.
+
Serial header for future expansion (#2).
+
Interlock LED (yellow). This LED is on whenever the interlock relay is closed.
+
ILDA DB-25 connector.
+
Behind the DB-25 connector: 2x13 pin header wired identically to the DB-25. This
+ can be used when the Ether Dream is built into a projector.
+
Emission LED (green). Whenever the DAC is producing output, this LED is on.
+
2x10-pin programming/debug header (JTAG).
+
1x6 pin programming/debug header (serial).
+
Serial header for future expansion (#1).
+
Serial header for future expansion (#3).
+
+
+
+
Live Playback
+
+ Ether Dream supports a standard frame-based API and should work "out of the box" with existing
+ playback software, once drivers are installed.
+
+
+ In the event of a momentary glitch in its data stream, the Ether Dream driver will automatically
+ restart playback. If an Ether Dream unit detects that its network link is physically
+ disconnected, it will go into an 'emergency-stop' mode and stop output until the network is
+ restored.
+
+
+
+
DMX
+
+ With an extra adapter board, the expansion connectors on the Ether Dream can transmit and receive
+ DMX signals to interface with lighting equipment. The Ether Dream can simultaneously drive three
+ DMX universes, relaying commands from Ethernet to DMX, and also receive on one universe, sending
+ information from DMX to Ethernet.
+
+
+ Each of the serial expansion headers on the diagram above can connect to a DMX adapter board. The
+ firmware supports both transmitting and receiving DMX from connector #1, and transmitting only
+ from conectors #2 and #3.
+
+
+ DMX output is enabled and controlled with OSC messages. When the Ether Dream receives a message
+ for a given DMX universe, it will enable output for that universe and start continuously sending
+ DMX data to an attached interface board. The DMX output can be controlled in any of several ways:
+
+
+
/dmxn/channelvalue...
+
+ Update one or more channels. For example, to set DMX channel 42 on universe 1 to 200, send an
+ OSC message to /dmx1/42 containing the number 200. If multiple values are sent, they
+ will be assigned to sequential DMX channels: for instance, sending 200, 250 to /dmx1/10
+ will set channel 10 to 200 and channel 11 to 250. One OSC message can change up to 50 channels. The
+ rest of the channels in the universe will not be changed.
+
+
/dmxnchannelvalue...
+
+ Alternately, the first channel to update can be sent as a numerical parameter, instead of in the
+ target path of the OSC message. Send 7, 100, 100 to /dmx2 to set channels 7 and 8
+ of universe 2 both to 100. As above, up to 50 channels can be specified, and only the specified
+ channels will be changed.
+
+
/dmxnblob
+
+ To change all 512 channels in a universe with a single OSC command, the Ether Dream will accept an OSC
+ blob (data) parameter. The first byte (index 0) in the blob sets DMX channel 0, the next sets
+ channel 1, and so on. The blob must be the only parameter and must be exactly 512 bytes long.
+
+
+
+ DMX input is enabled by sending a message with a string and a number to /dmx1/input. The
+ string specifies the IP address (must be a numeric IP address, not a hostname) to relay DMX updates to,
+ and the number is a port number. DMX updates will be sent as OSC messages to /dmx1 containing
+ a single blob - the same format as described above for DMX output.
+
+
+ If the address given is "me" and the port is 0, then messages will be sent back to the same
+ host and port that the /dmx1/input command was received one. If the address is blank and
+ the port is 0, then DMX input will be disabled.
+
+
+ This code will set the first four channels of an Ether Dream's DMX universe 1 to 255:
+
On startup, commands are loaded from the autoplay.txt on the SD card, if present.
+
+
+
OSC is a simple UDP-based protocol for
+ sending control messages; it is usually used for audio, to control synthesizers, mixers,
+ etc., but is flexible enough to support laser applications as well. Bridges exist
+ between OSC and MIDI or DMX. An OSC message is sent to an address, like
+ /channel/1/volume or /ilda/pps, and contains some data:
+ zero or more numbers, strings, True/False values, etc.
+
+
+ The Ether Dream listens for OSC messages on UDP port 60000. When it sends a response to
+ a message, it will send that response to port 60001 on the originating host. There
+ are many OSC-handling programs and OSC plugins, as well as libraries for most programming
+ languages, available on the Internet.
+
+
+ Most of the OSC parameter endpoints implemented on the Ether Dream take some
+ sort of data. Those labeled as "integer" or "float" expect a value in the given range.
+ OSC endpoints specified as "message" can be sent a message with either no data or with an
+ integer value, but will ignore the message if the value is zero. This allows them to
+ be controlled by a pushbutton on a control surface that sends OSC messages - a pushbutton
+ will send a nonzero value when it is pressed, and then send 0 when it is released.
+
+
+
/ilda/playfilename - string
+
Writing a string to this address causes the DAC to switch to file playback mode and
+ begin playing filename from the SD card.
+
NOTE: Playing a file by name can currently only be done via autoplay.txt, not
+ via OSC.
+
+
/ilda/n/play - message
+
As /ilda/playfilename, but plays the nth file found on the SD card.
+ Works over OSC.
+
+
/ilda/fpsfps - integer
+
Switch to file playback mode and set the frame rate limit to fps.
+
+
/ilda/ppspps - integer
+
Switch to file playback mode and set the point rate to pps.
+
+
/ilda/repeatvalue - integer
+
Switch to file playback mode. If value is nonzero, then files played will be repeated
+ until a stop command is received; if zero, playback stops at the end of a file.
+
+
/stop - message
+
Stop playing the current file.
+
+
/geom/tl, /geom/tr, /geom/bl, /geom/brxy - float, range [-1, 1]
+
Set the position of a corner of the image within the overall projection field. Values range from -1 to 1. This
+ can apply any arbitrary perspective transform to the input image.
+
The output bottom left is (-1, -1); the output top right is (1, 1). For example, to leave the image
+ unchanged, set the values as:
+
/geom/tl -1 1
+
/geom/tr 1 1
+
/geom/bl -1 -1
+
/geom/br 1 -1
+
+
/geom/sizesize, /geom/offsetoffset-xoffset-y
+
These parameters provide a shortcut to setting per-corner positions when only size
+ and position adjustments are needed. To set the image at 50% size and in the top right
+ corner of the projection field, set:
+
/geom/size 0.5
+
/geom/offset 0.5 0.5
+
+
/geom/rdelay, /geom/gdelay, /geom/bdelaypoints - integer, 0 to 15
+
Set the delay on the red, green, or blue color channel to points points.
+
+
+
+
+ As an example, the following autoplay.txt file might be used to play a prerecorded show
+ automatically when the DAC is powered up:
+
Control layout files for TouchOSC, a third-party iPhone/iPad app, are available
+ in the Ether Dream source repository under the tools/ directory - j4cDAC.touchosc is for iPad, and
+j4cDAC-phone.touchosc is for iPhone.
+
+
+
Development
+ The Ether Dream firmware, available on github,
+ builds on a standard Linux system with the free CodeSourcery ARM toolchain. The README in the
+ repository describes the needed tools.
+
+
+ LJ is network based. The user interface runs in a browser, in a tablet for example, letting you free to move ! With more than one laser you should think laser server and run LJ on a dedicated computer.
+
+ Some LJ features :
+
+
Live kpps modification for each DAC.
+
Color balancing and Intensity control.
+
Lasers alignment like in videomapping.
+
LJ can script or be scripted (OSC & websockets).
+
Status update every 0.5 seconds : DACs states, number of points sent,...
+
A compiled version (os x and linux) of nannou.org etherdream+laser emulator is included.
+
"Optimisation" points automatically added, can be changed live for glitch art.
+
Some fancy examples are available : 3D anaglyph, Laser Pong,...
+
Midi and audio reactive, look midigen.py and fft3.py.
+
Openpose skeletons animations laser player.
+
Maxwell laser synth emulation plugin.
+
Resolume OSC client.
+
Artnet receiver.
+
...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/images/.DS_Store b/doc/images/.DS_Store
new file mode 100644
index 0000000..5531dff
Binary files /dev/null and b/doc/images/.DS_Store differ
diff --git a/doc/images/Untitled-7.png b/doc/images/Untitled-7.png
new file mode 100644
index 0000000..46bf2fc
Binary files /dev/null and b/doc/images/Untitled-7.png differ
diff --git a/doc/images/align.jpg b/doc/images/align.jpg
new file mode 100644
index 0000000..d9c4ff3
Binary files /dev/null and b/doc/images/align.jpg differ
diff --git a/doc/images/aurora.png b/doc/images/aurora.png
new file mode 100644
index 0000000..92c01ae
Binary files /dev/null and b/doc/images/aurora.png differ
diff --git a/doc/images/banner.jpg b/doc/images/banner.jpg
new file mode 100644
index 0000000..500bbfc
Binary files /dev/null and b/doc/images/banner.jpg differ
diff --git a/doc/images/banner.png b/doc/images/banner.png
new file mode 100644
index 0000000..7b849d0
Binary files /dev/null and b/doc/images/banner.png differ
diff --git a/doc/images/calig.jpg b/doc/images/calig.jpg
new file mode 100644
index 0000000..31eebc5
Binary files /dev/null and b/doc/images/calig.jpg differ
diff --git a/doc/images/calig.png b/doc/images/calig.png
new file mode 100644
index 0000000..b4887e4
Binary files /dev/null and b/doc/images/calig.png differ
diff --git a/doc/images/display.png b/doc/images/display.png
new file mode 100644
index 0000000..7ea4aa5
Binary files /dev/null and b/doc/images/display.png differ
diff --git a/doc/images/layer.png b/doc/images/layer.png
new file mode 100644
index 0000000..b4bbff3
Binary files /dev/null and b/doc/images/layer.png differ
diff --git a/doc/images/lj.png b/doc/images/lj.png
new file mode 100644
index 0000000..48bc244
Binary files /dev/null and b/doc/images/lj.png differ
diff --git a/doc/images/lj2.png b/doc/images/lj2.png
new file mode 100644
index 0000000..36ef71c
Binary files /dev/null and b/doc/images/lj2.png differ
diff --git a/doc/images/ljlogo.png b/doc/images/ljlogo.png
new file mode 100644
index 0000000..bb9e003
Binary files /dev/null and b/doc/images/ljlogo.png differ
diff --git a/doc/images/plugin.png b/doc/images/plugin.png
new file mode 100644
index 0000000..b8801a2
Binary files /dev/null and b/doc/images/plugin.png differ
diff --git a/doc/images/plugins.jpg b/doc/images/plugins.jpg
new file mode 100644
index 0000000..361af8e
Binary files /dev/null and b/doc/images/plugins.jpg differ
diff --git a/doc/images/pose.jpg b/doc/images/pose.jpg
new file mode 100644
index 0000000..a2d36c3
Binary files /dev/null and b/doc/images/pose.jpg differ
diff --git a/doc/images/satearth.jpg b/doc/images/satearth.jpg
new file mode 100644
index 0000000..f629bef
Binary files /dev/null and b/doc/images/satearth.jpg differ
diff --git a/doc/images/scenes.png b/doc/images/scenes.png
new file mode 100644
index 0000000..5e96e68
Binary files /dev/null and b/doc/images/scenes.png differ
diff --git a/doc/images/simu.png b/doc/images/simu.png
new file mode 100644
index 0000000..3ccdfd9
Binary files /dev/null and b/doc/images/simu.png differ
diff --git a/doc/images/status.png b/doc/images/status.png
new file mode 100644
index 0000000..5e87de3
Binary files /dev/null and b/doc/images/status.png differ
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..0acc6c2
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,104 @@
+
+
+
+
+ LJ Laser Server
+
+
+
+
+
+
+
+
+
+
+
LJ comes with different plugins. They are handy and nice code example but not necessary, you can generate your pointlists and send them directly to redis keys.
+ Plugins list :
+
+ Square : A very basic example to understand how to easily program your own plugin.
+ Custom1 : A copy of square, you can modify.
+ Planetarium : A 4 lasers planetarium.
+ fft3 : Example how to make LJ audio reactive.
+ LaserPong : Our laser Pong is back !
+ pySimu : A full speed laser simulator.
+ Pose : Display json openpose skeleton animations ans starfields.
+ Textcycl : Cycle some words with adjustable length on one laser.
+ LiveWords : Fill the input form and it's displayed. One word / laser.
+
+ Anaglyph : A green/red rotating cube. Try it with green/red 3D glasses !
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/pointslists.html b/doc/pointslists.html
new file mode 100644
index 0000000..098b870
--- /dev/null
+++ b/doc/pointslists.html
@@ -0,0 +1,108 @@
+
+
+
+
+ LJ Laser Server
+
+
+
+
+
+
+
+
+
+
+
+ LJ is network based. The user interface runs in a browser, in a tablet for example, letting you free to move ! With more than one laser you should think laser server and run LJ on a dedicated computer.
+
+
+
/pl/Scene/lasernumber : "[(x,y,color),(x1,y1,color),...]" The live list of points drawn.
+
x : (0-600).
+
y : (0-600).
+
color : integer of the Hex value of the color, like FFFFFF. Conversion RGB in python from r,g,b values : int('0x%02x%02x%02x' % (r,g,b),0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/references.html b/doc/references.html
new file mode 100644
index 0000000..a0cdec6
--- /dev/null
+++ b/doc/references.html
@@ -0,0 +1,149 @@
+
+
+
+
+ LJ Laser Server
+
+
+
+
+
+
+
+
+
+
+
/pl/Scene/lasernumber : "[(x,y,color),(x1,y1,color),...]"" The live list of points. Tracer continously ask redis for key.
+
/resampler/lasernumber : "[(1.0,8), (0.25,3),(0.75,3),(1.0,10)]"" a string for resampling rules.
+
/clientkey : "/pl/SceneNumber/".
+
/EDH/lasernumber : Internal. Order for tracer to update its homography.
+
+
- Tracer control :
+
/order : 0 : Draw Normal pointlists _1 : Get the new EDH _2 : Draw BLACK _3 : Draw GRID point list _4 : Resampler Change _5 : Client Key Change. _6 : Max Intensity Change _7 : kpps change _8 : color balance change.
+
/kpps : 0- DAC output speed to laser, then order 7. Depends of actual angle.
+
/intensity : 0-255 Laser output power, then order 6 (for alignement,...).
+
/red : 0-100 % of full red, then order 8.
+
/green : 0-100 % of full green, then order 8.
+
/blue : 0-100 % of full blue, then order 8 .
+
+
- DAC status report :
+
/lstt/lasernumber : last status playback_state (0: idle 1: prepare 2: playing).
+
/cap/lasernumber : number of empty points sent to fill etherdream buffer (up to 1799).
+
/lack/lasernumber : "a": ACK "F": Full "I": invalid. 64 or 35 for no connection.
+
+ OSC commands
+
+
/scale/X/lasernumber value (0-200).
+
/scale/Y/lasernumber value (0-200).
+
/client : change client displayed for Current Laser.
+
/noteon : <8 change client displayed for Current Laser. 23 < /noteon < 32 : PL number displayed on webUI simulator.
+
/grid/lasernumber value : (0 or 1) switch given laser with grid display on or off.
+
/black/lasernumber value : (0 or 1) set given laser to black on or off.
+
/emergency value : (0 or 1) set all lasers to black on or off.
+
/ip/lasernumber value : change given laser IP i.e '192.168.1.1'.
+
/kpps/lasernumber value : Live change of kpps.
+
/angle/lasernumber value : angle correction for given laser by value (0-360).
+
/intens/lasernumber value : increase/decrease intensity for given laser by value
+
/resampler/lasernumber lsteps : change resampling strategy (glitch art) for given laser lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]".
+
/mouse/lasernumber value : (0 or 1).
+
/swap/X/lasernumber value : (0 or 1).
+
/swap/Y/lasernumber value : (0 or 1).
+
/loffset/X/lasernumber value : change X offset of given laser to value (-32000/32000).
+
/loffset/Y/lasernumber value : change Y offset of given laser to value (-32000/32000).
+
/intens/lasernumber value : increase/decrease intensity for given laser by value
+
/order : 0 : Draw Normal pointlists _1 : Get the new EDH _2 : Draw BLACK _3 : Draw GRID point list _4 : Resampler Change _5 : Client Key Change. _6 : Max Intensity Change _7 : kpps change _8 : color balance change.
+
/planet : will be forwarded to planetarium client.
+
/nozoid : will be forwarded to nozoid client.
+
/scene/scenenumber/start : 0 or 1
+
/regen : regen webui index html page..
+
/plugins/start : pluginame.
+
/plugins/stop : pluginame.
+
/pl/clientnumber/lasernumber value : value is the pointlist to draw as string type. For string format see redis keys.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ethertools/dac3.py b/ethertools/dac3.py
index 3c50adc..87d821b 100755
--- a/ethertools/dac3.py
+++ b/ethertools/dac3.py
@@ -129,6 +129,7 @@ class DAC(object):
def __init__(self, host, port = 7765):
"""Connect to the DAC over TCP."""
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ print(host,port)
conn.connect((host, port))
conn.settimeout(1)
self.conn = conn
diff --git a/ethertools/watchLJ.py b/ethertools/watchLJ.py
old mode 100644
new mode 100755
diff --git a/libs3/LPD8.py b/libs3/LPD8.py
index 38de7f5..f49f1b7 100644
--- a/libs3/LPD8.py
+++ b/libs3/LPD8.py
@@ -39,7 +39,7 @@ import sys
import os
ljpath = r'%s' % os.getcwd().replace('\\','/')
-from . import midi3, launchpad
+from . import midi3, gstt, launchpad
#import midimacros, maxwellmacros
import traceback
@@ -230,25 +230,34 @@ class LPD8AddQueue(object):
# Modes :
#
-# Load Matrix only macros (for the moment) in macros.json
+# Load Matrix only macros (for the moment) in LPD8.json
def LoadMacros():
- global macros
+ global macros, nbmacro
- print()
- print("Loading LPD8 Macros...")
+ #print()
+ #print("Loading LPD8 Macros...")
- if os.path.exists('libs/matrix.json'):
- #print('File libs/matrix.json exits')
- f=open("libs/matrix.json","r")
+ if os.path.exists('LPD8.json'):
+ #print('File is LPD8.json')
+ f=open("LPD8.json","r")
+ elif os.path.exists('../LPD8.json'):
+ #print('File is ../lpd8.json')
+ f=open("../LPD8.json","r")
+
+ elif os.path.exists('libs3/LPD8.json'):
+ #print('File is libs/lpd8.json')
+ f=open("libs3/LPD8.json","r")
+
+ elif os.path.exists(ljpath+'/../../libs3/LPD8.json'):
+ #print('File is '+ljpath+'/../../libs/lpd8.json')
+ f=open(ljpath+"/../../libs3/LPD8.json","r")
- elif os.path.exists(ljpath+'/../../libs/matrix.json'):
- #print('File '+ljpath+'/../../libs/matrix.json exits')
- f=open(ljpath+"/../../libs/matrix.json","r")
s = f.read()
macros = json.loads(s)
- print((len(macros['OS']),"Macros"))
- print("Loaded.")
+ #print(len(macros['OS']),"Macros")
+ nbmacro = len(macros[gstt.lpd8Layers[gstt.lpd8Layer]])
+ #print("Loaded.")
# return macroname number for given type 'OS', 'Maxwell'
diff --git a/libs3/alink.py b/libs3/alink.py
index d97c953..5fb1cd8 100644
--- a/libs3/alink.py
+++ b/libs3/alink.py
@@ -4,7 +4,10 @@
'''
-Ableton Link
+alink v0.1
+Ableton Link bridge to OSC & Redis
+
+v0.2 available in miredis
LICENCE : CC
Sam Neurohack
diff --git a/libs3/artnet.py b/libs3/artnet.py
index 0624d58..d8ebce5 100644
--- a/libs3/artnet.py
+++ b/libs3/artnet.py
@@ -51,7 +51,7 @@ ljpath = r'%s' % os.getcwd().replace('\\','/')
#import from LJ
sys.path.append(ljpath +'/libs/')
-import lj23layers as lj
+import lj
#
# Init
@@ -285,8 +285,10 @@ try:
if data[0:7] != "Art-Net" or data[7] != "\0":
print("artnet package")
+ print('data',data)
#lj.WebStatus("Artnet package")
continue
+
OSCframe()
if ord(data[8]) != 0x00 or ord(data[9]) != 0x50:
diff --git a/libs3/bhorunicornhat.py b/libs3/bhorunicornhat.py
index c7815ef..574cde3 100644
--- a/libs3/bhorunicornhat.py
+++ b/libs3/bhorunicornhat.py
@@ -30,7 +30,7 @@ CC NC BY
'''
import colorsys,time
-import midi3,bhoreal,launchpad
+from . import midi3,bhoreal,launchpad
# For Launchpad mini
mididest = "launchpad"
diff --git a/libs3/cli.py b/libs3/cli.py
index 06f47c8..3a68bbe 100644
--- a/libs3/cli.py
+++ b/libs3/cli.py
@@ -31,7 +31,7 @@ def handle():
argsparser.add_argument("-a","--align",help="Reset laser 0 alignement values",action="store_true")
argsparser.add_argument("-i","--iport",help="port number for builtin LJ OSC server (8002 by default)",type=int)
argsparser.add_argument("-n","--nozoidIP",help="IP for llstr' Nozoid OSC server port 8003 ('127.0.0.1' by default)",type=str)
- argsparser.add_argument("-b","--bhoroscIP",help="IP for OSC output ('127.0.0.1' by default)",type=str)
+ argsparser.add_argument("-b","--oscserverip",help="IP for OSC output ('127.0.0.1' by default)",type=str)
argsparser.add_argument("-o","--oport",help="OSC output port number (8001 by default)",type=int)
argsparser.add_argument("-w","--webui",help="Regen the webui",action="store_true")
@@ -99,7 +99,7 @@ def handle():
# Redis Computer IP
if args.redisIP != None:
- gstt.LjayServerIP = args.redisIP
+ gstt.RediServerIP = args.redisIP
@@ -116,8 +116,8 @@ def handle():
Settings.Write()
- if args.bhoroscIP != None:
- gstt.oscIPin = args.bhoroscIP
+ if args.oscserverip != None:
+ gstt.oscIPin = args.oscserverip
else:
gstt.oscIPin = '127.0.0.1'
diff --git a/libs3/commands.py b/libs3/commands.py
index e80363b..c9adc5d 100644
--- a/libs3/commands.py
+++ b/libs3/commands.py
@@ -25,6 +25,7 @@ UpdateAllwww()
/grid/lasernumber value (0 or 1) : switch given laser with grid display on or off
/black/lasernumber value (0 or 1) : set given laser to black on or off
+/emergency value (0 or 1) : set all lasers to black on or off
/ip/lasernumber value : change given laser IP i.e '192.168.1.1'
@@ -94,14 +95,15 @@ Bob could use /pl/2/0 and /pl/2/1 and Lisa could use /pl/2/2 and /pl/2/3.
import types, time, socket, math
from libs3 import gstt
import redis
+from libs3 import OSC3
from libs3 import settings, plugins, homographyp,log
-r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0)
-#r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-')
+r = redis.StrictRedis(host=gstt.RediServerIP , port=6379, db=0)
+#r = redis.StrictRedis(host=gstt.RediServerIP , port=6379, db=0, password='-+F816Y+-')
-GenericCommands = ["start","align","ljclient","scene","addest","deldest","dest","clientnumber","vcvrack","fft","mitraille","faceosc","midigen","viewgen","audiogen","noteon","cc","ljpong","ljwars","mouse","emergency","simu","status","run","nozoid","planet","live","words","ai","bank0","pose","lj","cycl","glyph","pong","maxw","custom1","square","regen","trckr","aurora","line1","ForwardUI","settings","debug","pl","plugins"]
+GenericCommands = ["start", "align", "ljclient", "scene", "addest", "deldest", "dest", "clientnumber", "vcvrack", "fft", "mitraille", "faceosc", "midigen", "viewgen", "audiogen", "noteon", "cc", "ljpong", "ljwars", "mouse", "emergency", "simu", "status", "run", "nozoid", "planet", "live", "words", "ai", "bank0", "pose", "lj", "cycl", "glyph", "pong", "maxw", "custom1", "square", "regen", "trckr", "aurora", "line1", "ForwardUI", "settings", "debug", "pl", "plugins"]
def UserOn(laser):
@@ -125,6 +127,7 @@ def BlackOn(laser):
print("Black for laser ", laser)
plugins.sendWSall("/status Black on laser " + str(laser))
+ sendOSCUI('/black/'+str(laser),1)
r.set('/order/'+str(laser), 2)
@@ -132,9 +135,11 @@ def GridOn(laser):
print("Grid for laser ", laser)
plugins.sendWSall("/status Grid on laser " + str(laser))
+ sendOSCUI('/grid/'+str(laser),1)
r.set('/order/'+str(laser), 3)
+
def Resampler(laser,args):
# lsteps is a string like : "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
@@ -178,8 +183,8 @@ def SceneChange(newscene):
# Change current laser and send "/scim lasernumber to each plugin"
def NoteOn(note):
- print("NoteOn", note)
+ print("NoteOn", note)
# Change laser client
if note < 8:
LasClientChange(note)
@@ -197,6 +202,11 @@ def NoteOn(note):
print("Current Laser switched to", gstt.Laser)
plugins.sendWSall("/status Laser " + str(gstt.Laser))
plugins.SendAll(["/scim", str(gstt.Laser), 1])
+ print("sending cropper data..")
+ plugins.sendWSall("/loffset/X/" + str(gstt.Laser) +" " +str(gstt.centerX[gstt.Laser]))
+ plugins.sendWSall("/loffset/Y/" + str(gstt.Laser) +" " +str(gstt.centerY[gstt.Laser]))
+ plugins.sendWSall("/scale/X/" + str(gstt.Laser) +" " + str(gstt.zoomX[gstt.Laser]))
+ plugins.sendWSall("/scale/Y/" + str(gstt.Laser) +" " +str(gstt.zoomY[gstt.Laser]))
def Scim(path, tags, args, source):
@@ -231,6 +241,7 @@ def ForwardUI(path, tags, args, source):
print("OSC /forwardui to WebUI :", line)
print('from path', path, 'args', args)
plugins.sendWSall(line)
+ sendOSCUI('/status',line)
def CC(number, value):
@@ -244,14 +255,14 @@ def Mouse(x1,y1,x2,y2):
def handler(oscpath, args):
- print("OSC handler in commands.py got /"+ str(oscpath)+ " with args :",args)
+ #print("OSC handler in commands.py got /"+ str(oscpath)+ " with args :",args)
if gstt.debug > 0:
print("OSC handler in commands.py got /"+ str(oscpath)+ " with args :",args)
+
# 2 incoming cases : generic or specific for a given lasernumber :
-
#
# Generic : Commands without a laser number
#
@@ -277,9 +288,6 @@ def handler(oscpath, args):
r.set(oscpath, args[0])
-
-
-
#/scene/scenenumber/start 0 or 1
if oscpath[1] == "scene":
@@ -333,7 +341,8 @@ def handler(oscpath, args):
print("Black requested for laser ", laser)
BlackOn(laser)
print("EMERGENCY MODE")
- plugins.sendWSall("/status EMERGENCY MODE")
+ plugins.sendWSall("/status EMERGENCY MODE")
+
else:
for laser in range(gstt.lasernumber):
print("Back to normal for laser ", laser)
@@ -458,20 +467,19 @@ def handler(oscpath, args):
print("No grid for laser ", laser)
UserOn(laser)
-
# /ip/lasernumber value
if oscpath[1] == "ip":
print("New IP for laser ", laser)
gstt.lasersIPS[laser]= args[0]
settings.Write()
-
# /kpps/lasernumber value
# Live change of kpps is not implemented in newdac.py. Change will effect next startup.
if oscpath[1] == "kpps":
print("New kpps for laser ", laser, " next startup", int(args[0]))
gstt.kpps[laser]= int(args[0])
settings.Write()
+ sendOSCUI('/kpps/' + str(laser), args[0])
r.set('/kpps/' + str(laser), str(args[0]))
r.set('/order/'+str(laser), 7)
@@ -479,6 +487,7 @@ def handler(oscpath, args):
if oscpath[1] == "angle":
print("New Angle modification for laser ", oscpath[2], ":", float(args[0]))
gstt.finANGLE[laser] = math.radians(float(args[0]))
+ sendOSCUI('/angle/' + str(laser), gstt.finANGLE[laser])
NewEDH(laser)
print("New angle", gstt.finANGLE[laser])
@@ -486,10 +495,11 @@ def handler(oscpath, args):
if oscpath[1] == "intens":
print("LJ2 : New intensity requested for laser ", laser, ":", int(args[0]))
plugins.sendWSall("/status Intensity " + str(args[0]))
+ sendOSCUI('/intens/' + str(laser), args[0])
r.set('/intensity/' + str(laser), str(args[0]))
r.set('/order/'+str(laser), 6)
-
+
# /resampler/lasernumber lsteps
# lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
@@ -535,42 +545,91 @@ def handler(oscpath, args):
gstt.swapY[laser]= 1
NewEDH(laser)
+
# /loffset/X/lasernumber value
if oscpath[1] == "loffset" and oscpath[2] == "X":
- if -32000 < int(args[0]) < 32000:
+ if -32000 < float(args[0]) < 32000:
print("offset/X laser", laser, "modified to", args[0])
- gstt.centerX[laser] = int(args[0])
+ gstt.centerX[laser] = float(args[0])
NewEDH(laser)
+
# /loffset/Y/lasernumber value
if oscpath[1] == "loffset" and oscpath[2] == "Y":
- if -32000 < int(args[0]) < 32000:
+ if -32000 < float(args[0]) < 32000:
print("offset/Y laser", laser, "modified to", args[0])
- gstt.centerY[laser] = int(args[0])
+ gstt.centerY[laser] = float(args[0])
NewEDH(laser)
# /scale/X/lasernumber value
if oscpath[1] == "scale" and oscpath[2] == "X":
- gstt.zoomX[laser] = int(args[0])
+ gstt.zoomX[laser] = float(args[0])
print("scale/X laser", laser , "modified to", gstt.zoomX[laser])
NewEDH(laser)
# /scale/Y/lasernumber value
if oscpath[1] == "scale" and oscpath[2] == "Y":
- gstt.zoomY[laser] = int(args[0])
+ gstt.zoomY[laser] = float(args[0])
print("scale/Y laser", laser, "modified to", gstt.zoomY[laser])
NewEDH(laser)
+# OSC UI feedback
+def sendOSCUI(oscaddress,oscargs=''):
+
+ if gstt.TouchOSCUI == True:
+ oscmsg = OSC3.OSCMessage()
+ oscmsg.setAddress(oscaddress)
+ oscmsg.append(oscargs)
+
+ oscui = OSC3.OSCClient()
+ oscui.connect((gstt.TouchOSCIP, 8001))
+ #print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001")
+ if gstt.debug >0:
+ print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001")
+
+ try:
+ oscui.sendto(oscmsg, (gstt.TouchOSCIP, 8001))
+ oscmsg.clearData()
+
+ except:
+ print ('Connection to OSC UI refused : died ?')
+ pass
+
+def UpdateOSCUI(laserid):
+
+ sendOSCUI("/ip/" + str(laserid), str(gstt.lasersIPS[laserid]))
+ sendOSCUI("/kpps/" + str(laserid), str(gstt.kpps[laserid]))
+
+ sendOSCUI("/intens/" + str(laserid), str(gstt.intens[laserid]))
+ sendOSCUI("/red/" + str(laserid), str(gstt.red[laserid]))
+ sendOSCUI("/green/" + str(laserid), str(gstt.green[laserid]))
+ sendOSCUI("/blue/" + str(laserid), str(gstt.blue[laserid]))
+
+ sendOSCUI("/loffset/X/" + str(laserid), str(gstt.centerX[laserid]))
+ sendOSCUI("/loffset/Y/" + str(laserid), str(gstt.centerY[laserid]))
+ sendOSCUI("/scale/X/" + str(laserid), str(gstt.zoomX[laserid]))
+ sendOSCUI("/scale/Y/" + str(laserid), str(gstt.zoomY[laserid]))
+ sendOSCUI("/angle/" + str(laserid), str(gstt.finANGLE[laserid]))
+ sendOSCUI("/type/" + str(laserid), str(gstt.lasertype[laserid]))
+
+ if gstt.swapX[laserid] == 1:
+ sendOSCUI("/swap/X/" + str(laserid), 1)
+ else:
+ sendOSCUI("/swap/X/" + str(laserid), 0)
+ if gstt.swapY[laserid] == 1:
+ sendOSCUI("/swap/Y/" + str(laserid), 1)
+ else:
+ sendOSCUI("/swap/Y/" + str(laserid), 0)
+
#
# Different useful codes for some commands
#
-
def Updatepage(file_name):
print("updating", file_name)
diff --git a/libs3/gstt.py b/libs3/gstt.py
index 78ec2e2..188e4c2 100644
--- a/libs3/gstt.py
+++ b/libs3/gstt.py
@@ -29,10 +29,14 @@ LaserNumber = 4
SceneNumber = 0
MaxScenes = 3
-screen_size = [400,400]
-xy_center = [screen_size[0]/2,screen_size[1]/2]
-LjayServerIP = '192.168.1.13'
+ScreenX = [-1500,1500]
+ScreenY = [-1500,1500]
+screen_size = [400,400]
+#xy_center = [screen_size[0]/2,screen_size[1]/2]
+xy_center = [0,0]
+
+RediServerIP = '192.168.1.13'
oscIPin = '192.168.1.15'
nozoscIP = '192.168.1.15'
wwwIP = '192.168.1.15'
@@ -60,8 +64,12 @@ dacnumber = 0
# ** Will be overridden by LJ.conf file values **
kpps = [25000,25000,25000,25000]
lasertype = ["LOCAL","LOCAL","LOCAL","LOCAL"]
+dacfamily = ["etherdream","etherdream","etherdream","etherdream"]
intensity = [-1,-1,-1,-1]
-
+intens = [-1,-1,-1,-1]
+red = [100,100,100,100]
+green = [100,100,100,100]
+blue = [100,100,100,100]
# gstt.GridDisplay : if = 1 Curve points actually sent to PL are replaced by a grid
GridDisplay = [0,0,0,0]
@@ -141,11 +149,31 @@ warpdest = [[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]],
[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]]
]
-BeatstepLayer = 1
-BeatstepLayers = ['XY','Live',"Align","Zregulators"]
-TouchOSCPort = 8101
+BhorealLayer = 0
+BhorealLayers = ['Maxwell1','Maxwell2','Maxwell3']
+
+LaunchpadLayer = 0
+LaunchpadLayers = ['Maxwell1','Maxwell2','OS']
+
+BeatstepLayer = 0
+BeatstepLayers = ['XY','TraRot',"HueInt","Zregulators"]
+
+BCRLayer = 0
+BCRLayers = ['Main','Second']
+
+SequencerLayer = 3
+SequencerLayers = ['XY','TraRot',"HueInt","Zregulators"]
+
+lpd8Layer = 0
+lpd8Layers = ['Maxwell1','Maxwell2','Maxwell3','OS']
+
+
+TouchOSCUI = False
+TouchOSCPort = 8001
+# TouchOSCIP is now auto assigned when /connect is received
TouchOSCIP = '192.168.2.67' # iPad 1
+#TouchOSCIP = '192.168.2.67' # iPad 1
#TouchOSCIP = '192.168.2.156' # iPad mini
#TouchOSCIP = '192.168.43.146' # iPad mini @ fuzz
#TouchOSCIP = '192.168.151.213' # CCN
diff --git a/libs3/homographyp.py b/libs3/homographyp.py
index 3d4cc24..249cb17 100644
--- a/libs3/homographyp.py
+++ b/libs3/homographyp.py
@@ -10,7 +10,7 @@ v0.7.0
LICENCE : CC
Sam Neurohack
-Homographies for align + swap corrections and warp corrections
+Homographies for LJ settings corrections and DISABLED warp corrections
Align + swap homography if found with 4 original points and corrected coordinates
Warp correction is disabled for the moment. Should be computed at warp edition : set 1 curve 1
@@ -67,11 +67,12 @@ import math
from scipy.linalg import svd,lstsq
import ast
from libs3 import gstt
+from libs3 import commands
#from globalVars import xy_center
import redis
-r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
+r = redis.StrictRedis(host=gstt.RediServerIP, port=6379, db=0)
def find(points1,points2):
if points1.shape[0] != points2.shape[0] : raise ValueError("The number of input and output points mismatches")
@@ -160,32 +161,49 @@ def apply(H,points):
# Align and axis swap corrections
# Reference points
-pointsref = np.array([(300.0, 400.0), (500.0, 400.0), (500.0, 200.0), (300.0, 200.0)])
+pointsref = np.array([(-1500.0, 1500.0), (1500.0, 1500.0), (1500.0, -1500.0), (-1500.0, -1500.0)])
+# wad : pointsref = np.array([(300.0, 400.0), (500.0, 400.0), (500.0, 200.0), (300.0, 200.0)])
+ScreenX = [-1500,1500]
+ScreenY = [-1500,1500]
-def EDpoint(mylaser, xxx_todo_changeme):
+# Compute refpoint transformation in EtherDream space according to settings webpage (= LJ.conf)
+def EDpoint(mylaser, refpt):
- #print "current point : ", pygamex, pygamey
- (pygamex,pygamey) = xxx_todo_changeme
+ XX = refpt[0]
+ YY = refpt[1]
+ CosANGLE = math.cos(gstt.finANGLE[mylaser])
+ SinANGLE = math.sin(gstt.finANGLE[mylaser])
+
+ #if zoom is a percentage of 65535 etherdream space
+ #x = (((XX * CosANGLE) - (YY * SinANGLE))) * gstt.zoomX[mylaser] * 65535 + gstt.centerX[mylaser]
+ #y = (((XX * SinANGLE) + (YY * CosANGLE))) * gstt.zoomY[mylaser] * 65535 + gstt.centerY[mylaser]
+
+ x = (((XX * CosANGLE) - (YY * SinANGLE))) * gstt.zoomX[mylaser] + gstt.centerX[mylaser]
+ y = (((XX * SinANGLE) + (YY * CosANGLE))) * gstt.zoomY[mylaser] + gstt.centerY[mylaser]
+ '''
+ Was :
+ (pygamex,pygamey) = refpt
XX = pygamex - gstt.xy_center[0]
YY = pygamey - gstt.xy_center[1]
CosANGLE = math.cos(gstt.finANGLE[mylaser])
SinANGLE = math.sin(gstt.finANGLE[mylaser])
-
x = (gstt.xy_center[0] + ((XX * CosANGLE) - (YY * SinANGLE)) - gstt.xy_center[0]) * gstt.zoomX[mylaser] + gstt.centerX[mylaser]
y = (gstt.xy_center[1] + ((XX * SinANGLE) + (YY * CosANGLE)) - gstt.xy_center[1]) * gstt.zoomY[mylaser] + gstt.centerY[mylaser]
+ '''
+ #print()
+ #print("EDpoint computing...")
+ #print("Reference point :",refpt[0], refpt[1])
+ #print("Projected point :", x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser])
+
+ #print("Laser :", mylaser)
+ #print("Reference center : 0 0")
+ #print("swaps :", gstt.swapX[mylaser], gstt.swapY[mylaser])
+ #print("zooms :", gstt.zoomX[mylaser], gstt.zoomY[mylaser])
+ #print("angle :", gstt.finANGLE[mylaser])
+ #print("Projection center at :", gstt.centerX[mylaser], gstt.centerY[mylaser])
- if gstt.debug >1:
-
- #print "global center :", xy_center
- print("EDpoint computing...")
- print("Laser :", mylaser, "center at : ", gstt.centerX[mylaser], gstt.centerY[mylaser])
- print("Pygame point",pygamex,",",pygamey)
- '''
- print "swaps : ", (gstt.swapX[mylaser]), str(gstt.swapY[mylaser])
- print "zooms : ", gstt.zoomX[mylaser], gstt.zoomY[mylaser]
- print "angles : ", gstt.finANGLE[mylaser]
- '''
- print("Result point : ", x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser])
+ commands.UpdateOSCUI(mylaser)
+
return [x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser]]
'''
@@ -203,7 +221,7 @@ def EDpoint((pygamex,pygamey)):
'''
-# New total homography from always the same reference points : ED (= align + swap) transform + warp transform.
+# New total homography from always the same reference points to EtherDream space according to LJ settings transform + warp DISABLED transform.
# WARP IS DISABLED. Some bug tracking is needed !
def newEDH(mylaser):
@@ -226,8 +244,10 @@ def newEDH(mylaser):
if r.set('/EDH/'+str(mylaser), np.array2string(gstt.EDH[mylaser], separator=',')) == True:
r.set('/order/'+str(mylaser), 1)
print("New EDH sent.")
+ print()
else:
print("New EDH not sent.")
+ print()
'''
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
order = r.get('/order')
diff --git a/libs3/launchpad.py b/libs3/launchpad.py
index 3ec0bca..a4185b4 100644
--- a/libs3/launchpad.py
+++ b/libs3/launchpad.py
@@ -53,12 +53,12 @@ import sys
sys.path.append('libs/')
import os
-import midi3, gstt
+from . import midi3, gstt
#import midimacros, maxwellmacros
import traceback
from queue import Queue
-import scrolldisp, maxwellccs, beatstep, bhoreal
+from . import scrolldisp, maxwellccs, bhoreal # , beatstep
#from libs import macros
import json, subprocess
from OSC3 import OSCServer, OSCClient, OSCMessage
@@ -744,17 +744,16 @@ def padCC(buttonname, state):
-
-
launchqueue = Queue()
ModeCallback = "ModeNo"
-
#
# Modes : Top lines functions
#
+
+
# Load Matrix only macros (for the moment) in launchpad.json
def LoadMacros():
global macros, nbmacro
@@ -762,9 +761,9 @@ def LoadMacros():
#print()
print("Loading Launchpad Macros...")
- if os.path.exists('libs/launchpad.json'):
- #print('File is libs/launchpad.json')
- f=open("libs/launchpad.json","r")
+ if os.path.exists('libs3/launchpad.json'):
+ #print('File is libs3/launchpad.json')
+ f=open("libs3/launchpad.json","r")
elif os.path.exists('../launchpad.json'):
#print('File is ../launchpad.json')
@@ -774,9 +773,9 @@ def LoadMacros():
#print('File is launchpad.json')
f=open("launchpad.json","r")
- elif os.path.exists(ljpath+'/../../libs/launchpad.json'):
- #print('File is '+ljpath+'/../../libs/launchpad.json')
- f=open(ljpath+"/../../libs/launchpad.json","r")
+ elif os.path.exists(ljpath+'/../../libs3/launchpad.json'):
+ #print('File is '+ljpath+'/../../libs3/launchpad.json')
+ f=open(ljpath+"/../../libs3/launchpad.json","r")
s = f.read()
macros = json.loads(s)
diff --git a/libs3/lj23layers.py b/libs3/lj.py
similarity index 98%
rename from libs3/lj23layers.py
rename to libs3/lj.py
index a6488f3..1b03f7e 100644
--- a/libs3/lj23layers.py
+++ b/libs3/lj.py
@@ -4,7 +4,7 @@
'''
-lj23layers v0.7.6 for LJ v0.8+
+lj v0.7.6 for LJ v0.8+
LJ functions (API) for python plugins/clients
@@ -279,7 +279,7 @@ def Config(redIP,client,myname):
ClientNumber = client
#print ("client configured",ClientNumber)
name = myname
- print ("lj23layers : Plugin declare its name :",name)
+ print ("lj : Plugin declare its name :",name)
#print layer
return r
@@ -355,10 +355,10 @@ def SendLJ(oscaddress,oscargs=''):
osclientlj = OSCClient()
osclientlj.connect((redisIP, 8002))
- #print("lj23layers for", name, "sending OSC message :", oscmsg, "to", redisIP, ":8002")
+ #print("lj for", name, "sending OSC message :", oscmsg, "to", redisIP, ":8002")
if gstt.debug >0:
- print("lj23layers for", name, "sending OSC message :", oscmsg, "to", redisIP, ":8002")
+ print("lj for", name, "sending OSC message :", oscmsg, "to", redisIP, ":8002")
try:
osclientlj.sendto(oscmsg, (redisIP, 8002))
@@ -384,7 +384,7 @@ def SendResol(oscaddress,oscargs):
osclientresol = OSCClient()
osclientresol.connect((oscIPresol, oscPORTresol))
- print("lj23layers sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
+ print("lj sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
try:
osclientresol.sendto(oscmsg, (oscIPresol, oscPORTresol))
oscmsg.clearData()
@@ -429,7 +429,7 @@ def OSCframe():
def OSCping(path, tags, args, source):
#def OSCping():
if gstt.debug >0:
- print(name, "lj23layers got /ping from LJ -> reply /pong", name)
+ print(name, "lj got /ping from LJ -> reply /pong", name)
SendLJ("/pong",name)
@@ -447,7 +447,7 @@ def OSCquit(path, tags, args, source):
global oscrun
oscrun = False
- print('lj23layers got /quit for',name)
+ print('lj got /quit for',name)
#WebStatus(name + " quit.")
#SendLJ("/"+name+"/start",0)
#print("Stopping OSC...")
@@ -459,7 +459,7 @@ def OSCquit(path, tags, args, source):
def OSChandler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
- print("lj23layers Default OSC Handler for",name,": msg from Client :" + str(source[0]),)
+ print("lj Default OSC Handler for",name,": msg from Client :" + str(source[0]),)
print("OSC address", path)
if len(args) > 0:
print("with args", args)
diff --git a/libs3/lj3.py b/libs3/lj3.py
index 271e678..79644be 100644
--- a/libs3/lj3.py
+++ b/libs3/lj3.py
@@ -5,7 +5,7 @@ lj3 v0.7.5 for LJ v0.8+
Some LJ functions useful for python clients
-lj3 is deprecated use lj23
+lj3 is deprecated use lj
OSC functions commented, waiting working on OSC in python3
diff --git a/libs3/maxwellccs.py b/libs3/maxwellccs.py
index 82c61ef..42b73b7 100644
--- a/libs3/maxwellccs.py
+++ b/libs3/maxwellccs.py
@@ -23,7 +23,7 @@ from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON,
PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE)
import os, json
-import midi3
+from . import midi3
if os.uname()[1]=='raspberrypi':
pass
diff --git a/libs3/midi.py b/libs3/midi.py
index 85d36d5..52cce9a 100644
--- a/libs3/midi.py
+++ b/libs3/midi.py
@@ -186,7 +186,7 @@ def OSCsend(name, oscaddress, oscargs =''):
try:
if gstt.debug > 0:
- print("Midi OSCSend : sending", oscmsg, "to", name, "at", gstt.LjayServerIP, ":", PluginPort)
+ print("Midi OSCSend : sending", oscmsg, "to", name, "at", gstt.RediServerIP, ":", PluginPort)
osclient.sendto(oscmsg, (ip, port))
oscmsg.clearData()
#if gstt.debug >0:
diff --git a/libs3/midi3.py b/libs3/midi3.py
index 0b8e37f..64e1d01 100644
--- a/libs3/midi3.py
+++ b/libs3/midi3.py
@@ -50,10 +50,9 @@ import weakref
import sys
from sys import platform
-print()
-print('Midi startup...')
+from libs3 import gstt
-import gstt, bhoreal, launchpad, LPD8
+from libs3 import bhoreal, launchpad, LPD8, beatstep
from queue import Queue
from OSC3 import OSCServer, OSCClient, OSCMessage
@@ -386,7 +385,7 @@ def OutConfig():
#
if len(OutDevice) == 0:
- print("")
+ #print("")
print("MIDIout...")
print("List and attach to available devices on host with IN port :")
@@ -416,7 +415,7 @@ def OutConfig():
OutDevice.append(OutObject(name, "launchpad", port))
print("Launchpad mini start animation")
launchpad.Here = port
- launchpad.StartLaunchPad(port)
+ launchpad.Start(port)
time.sleep(0.2)
# Search for a LPD8
diff --git a/libs3/plugins.py b/libs3/plugins.py
index 392bd1c..4d0fefb 100644
--- a/libs3/plugins.py
+++ b/libs3/plugins.py
@@ -12,6 +12,9 @@ Plugins Handler.
from OSC3 import OSCServer, OSCClient, OSCMessage
from websocket_server import WebsocketServer
from libs3 import gstt
+# ?
+from libs3 import commands
+
import os
import subprocess
import sys
@@ -24,10 +27,20 @@ def Init(wserver):
def sendWSall(message):
+
+ print("WS sending %s" % (message))
#if gstt.debug >0:
#print("WS sending %s" % (message))
WSserver.send_message_to_all(message)
+ if message[:7] == '/status':
+ commands.sendOSCUI('/status', message[8:])
+ print("plugins WSall", message)
+ if message[:5] == '/line1':
+ commands.sendOSCUI('/line1', message[6:])
+ print("plugins WSall", message)
+
+
# What is plugin's OSC port ?
def Port(name):
@@ -54,7 +67,6 @@ def Data(name):
return gstt.plugins.get(name)
-
def Kill(name):
#data = Data(name)
@@ -111,7 +123,7 @@ def Start(name):
#PluginProcess = os.execv([PluginPath[0], ljpath + "/" + PluginPath[1]])
if gstt.debug >0:
- print("LJ path :", ljpath)
+ print("LJ path :", gstt.ljpath)
print("New process pid for ", name, ":", PluginProcess.pid)
'''
@@ -153,16 +165,16 @@ def OSCsend(name, oscaddress, oscargs =''):
#sendWSall("/status Checking "+ name + "...")
osclientplugin = OSCClient()
- osclientplugin.connect((gstt.LjayServerIP, PluginPort))
+ osclientplugin.connect((gstt.RediServerIP, PluginPort))
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
try:
if gstt.debug > 0:
- print("Plugins manager : OSCsending", oscmsg,"to plugin", name, "at", gstt.LjayServerIP, ":", PluginPort)
+ print("Plugins manager : OSCsending", oscmsg,"to plugin", name, "at", gstt.RediServerIP, ":", PluginPort)
- osclientplugin.sendto(oscmsg, (gstt.LjayServerIP, PluginPort))
+ osclientplugin.sendto(oscmsg, (gstt.RediServerIP, PluginPort))
oscmsg.clearData()
if gstt.debug >0:
print(oscaddress, oscargs, "was sent to",name)
@@ -170,7 +182,7 @@ def OSCsend(name, oscaddress, oscargs =''):
except:
if gstt.debug > 0:
- print('OSCSend : Connection to plugin IP', gstt.LjayServerIP ,':', PluginPort,'refused : died ?')
+ print('OSCSend : Connection to plugin IP', gstt.RediServerIP ,':', PluginPort,'refused : died ?')
#sendWSall("/status No plugin.")
#sendWSall("/status " + name + " is offline")
#sendWSall("/" + name + "/start 0")
@@ -208,7 +220,6 @@ def Send(name, oscpath):
#if oscpath.find(name) != -1:
if oscpath[0].find(name) != -1:
-
print("pinging..", name)
# Plugin is online ?
if Ping(name):
@@ -220,7 +231,6 @@ def Send(name, oscpath):
print('')
print("Plugins manager got", oscpath, "for plugin", name, "currently online.")
-
# If start 0, try to kill plugin
if oscpath[0].find("start") != -1 and oscpath[1] == "0":
diff --git a/libs3/scrolldisp.py b/libs3/scrolldisp.py
index 856b640..3267ea2 100644
--- a/libs3/scrolldisp.py
+++ b/libs3/scrolldisp.py
@@ -38,7 +38,7 @@ bhoreal.Cls()
#from unicorn_hat_sim import unicornhat as u
-import bhorunicornhat as u
+from . import bhorunicornhat as u
import time, math, sys
class ScrollDisp:
diff --git a/libs3/settings.py b/libs3/settings.py
index 5d1ca24..8806330 100644
--- a/libs3/settings.py
+++ b/libs3/settings.py
@@ -19,10 +19,11 @@ import numpy as np
def Write():
config.set('General', 'lasernumber', str(gstt.LaserNumber))
- config.set('General', 'ljayserverip', str(gstt.LjayServerIP))
+ config.set('General', 'rediserverip', str(gstt.RediServerIP))
config.set('General', 'wwwip', str(gstt.wwwIP))
- config.set('General', 'bhoroscip', str(gstt.oscIPin))
+ config.set('General', 'oscserverip', str(gstt.oscIPin))
config.set('General', 'nozoscip', str(gstt.nozoscIP))
+ config.set('General', 'wsport', str(gstt.wsPORT))
config.set('General', 'debug', str(gstt.debug))
config.set('General', 'autostart', gstt.autostart)
@@ -30,7 +31,12 @@ def Write():
laser = 'laser' + str(i)
config.set(laser, 'ip', str(gstt.lasersIPS[i]))
config.set(laser, 'type', str(gstt.lasertype[i]))
+ config.set(laser, 'dac_family', str(gstt.dacfamily[i]))
config.set(laser, 'kpps', str(gstt.kpps[i]))
+ config.set(laser, 'intens', str(gstt.intens[i]))
+ config.set(laser, 'red', str(gstt.red[i]))
+ config.set(laser, 'green', str(gstt.green[i]))
+ config.set(laser, 'blue', str(gstt.blue[i]))
config.set(laser, 'centerx', str(gstt.centerX[i]))
config.set(laser, 'centery', str(gstt.centerY[i]))
config.set(laser, 'zoomx', str(gstt.zoomX[i]))
@@ -48,11 +54,12 @@ def Write():
def Read():
gstt.LaserNumber = config.getint('General', 'lasernumber')
- gstt.LjayServerIP= config.get('General', 'ljayserverip')
+ gstt.RediServerIP= config.get('General', 'rediserverip')
gstt.wwwIP= config.get('General', 'wwwip')
- gstt.oscIPin = config.get('General', 'bhoroscip')
- gstt.nozoscip = config.get('General', 'nozoscip')
+ gstt.oscIPin = config.get('General', 'oscserverip')
+ gstt.nozoscIP = config.get('General', 'nozoscip')
gstt.debug = config.get('General', 'debug')
+ gstt.wsPORT = config.getint('General', 'wsport')
gstt.plugins = ast.literal_eval(config.get('plugins', 'plugins'))
gstt.autostart = config.get('General', 'autostart')
@@ -61,14 +68,19 @@ def Read():
laser = 'laser' + str(i)
gstt.lasersIPS[i]= config.get(laser, 'ip')
gstt.lasertype[i]= config.get(laser, 'type')
+ gstt.dacfamily[i] = config.get(laser, 'dac_family')
gstt.kpps[i] = config.getint(laser, 'kpps')
+ gstt.intens[i] = config.getfloat(laser, 'intens')
+ gstt.red[i] = config.getint(laser, 'red')
+ gstt.green[i] = config.getint(laser, 'green')
+ gstt.blue[i] = config.getint(laser, 'blue')
#gstt.lasersPLcolor[i] = config.getint(laser, 'color')
- gstt.centerX[i]= config.getint(laser, 'centerx')
- gstt.centerY[i] = config.getint(laser, 'centery')
+ gstt.centerX[i]= config.getfloat(laser, 'centerx')
+ gstt.centerY[i] = config.getfloat(laser, 'centery')
gstt.zoomX[i] = config.getfloat(laser, 'zoomx')
gstt.zoomY[i] = config.getfloat(laser, 'zoomy')
- gstt.sizeX[i] = config.getint(laser, 'sizex')
- gstt.sizeY[i] = config.getint(laser, 'sizey')
+ gstt.sizeX[i] = config.getfloat(laser, 'sizex')
+ gstt.sizeY[i] = config.getfloat(laser, 'sizey')
gstt.finANGLE[i] = config.getfloat(laser, 'finangle')
gstt.swapX[i] = config.getint(laser, 'swapx')
gstt.swapY[i] = config.getint(laser, 'swapy')
diff --git a/libs3/tracer3.py b/libs3/tracer3.py
index 59a4800..543356c 100644
--- a/libs3/tracer3.py
+++ b/libs3/tracer3.py
@@ -88,11 +88,14 @@ import binascii
black_points = [(278.0,225.0,0),(562.0,279.0,0),(401.0,375.0,0),(296.0,454.0,0),(298.0,165.0,0)]
grid_points = [(300.0,200.0,0),(500.0,200.0,65280),(500.0,400.0,65280),(300.0,400.0,65280),(300.0,200.0,65280),(300.0,200.0,0),(200.0,100.0,0),(600.0,100.0,65280),(600.0,500.0,65280),(200.0,500.0,65280),(200.0,100.0,65280)]
-r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
-# r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-')
+r = redis.StrictRedis(host=gstt.RediServerIP, port=6379, db=0)
+# r = redis.StrictRedis(host=gstt.RediServerIP , port=6379, db=0, password='-+F816Y+-')
ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NO CONNECTION ?", '35': "NO CONNECTION ?" , '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NO CONNECTION ?", '0': "NO CONNECTION ?"}
lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?" }
+ScreenX = [-1500,1500]
+ScreenY = [-1500,1500]
+
def pack_point(laser, intensity, x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
"""Pack some color values into a struct dac_point."""
@@ -120,26 +123,26 @@ def pack_point(laser, intensity, x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags =
if x < -32767:
if gstt.debug >1:
log.err("Tracer "+ str(laser) +" : x coordinates " + str(x) + " was below -32767")
- x = -32000
+ x = -32700
if x > 32767:
if gstt.debug >1:
log.err("Tracer "+ str(laser) +" : x coordinates "+ str(x) + " was bigger than 32767")
- x = 32000
+ x = 32700
if y < -32767:
if gstt.debug >1:
log.err("Tracer "+ str(laser) +" : y coordinates "+ str(y) + " was below -32767")
- y = -32000
+ y = -32700
if y > 32767:
if gstt.debug >1:
log.err("Tracer "+ str(laser) +" : y coordinates "+ str(y) + " was bigger than 32767")
- y = 32000
+ y = 32700
return struct.pack(" 0:
print("")
- print("OSC handler in main said : path", path," oscpath ", oscpath," args", args)
+ print("OSC handler in main got : path", path," oscpath", oscpath," args", args, " source",source)
if oscpath[1] != "pong":
sendWSall(path + " " + str(args[0]))
+ commands.sendOSCUI(path,oscargs=args)
commands.handler(oscpath,args)
@@ -208,83 +206,124 @@ def PingAll():
plugins.Ping(plugin)
+'''
+gstt.lasertype[i
+gstt.sizeX[i] =
+gstt.sizeY[i] =
+'''
+'''
+# OSC UI feedback
+def sendOSCUI(oscaddress,oscargs=''):
+
+ if gstt.TouchOSCUI == True:
+ oscmsg = OSC3.OSCMessage()
+ oscmsg.setAddress(oscaddress)
+ oscmsg.append(oscargs)
+
+ oscui = OSC3.OSCClient()
+ oscui.connect((gstt.TouchOSCIP, 8001))
+ print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001")
+ if gstt.debug >0:
+ print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001")
+
+ try:
+ oscui.sendto(oscmsg, (gstt.TouchOSCIP, 8001))
+ oscmsg.clearData()
+
+ except:
+ print ('Connection to OSC UI refused : died ?')
+ pass
+ #time.sleep(0.001
+'''
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
def osc_thread():
- #while True:
- try:
- while True:
+ try:
+ while True:
- time.sleep(0.1)
- osc_frame()
- for laserid in range(0,gstt.LaserNumber): # Laser not used -> led is not lit
+ time.sleep(0.1)
+ osc_frame()
- lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?" }
- lstt = r.get('/lstt/'+ str(laserid)).decode('ascii')
- #print ("laserid", laserid,"lstt",lstt, type(lstt))
- if gstt.debug >1:
- print("DAC", laserid, "is in (lstt) :", lstt , lstate[str(lstt)])
- if lstt == "0": # Dac IDLE state(0) -> led is blue (3)
- sendWSall("/lstt/" + str(laserid) + " 3")
+ for laserid in range(0,gstt.LaserNumber): # Laser not used -> led is not lit
- if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2)
- sendWSall("/lstt/" + str(laserid) + " 2")
+ lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?" }
+ lstt = r.get('/lstt/'+ str(laserid)).decode('ascii')
+ #print ("laserid", laserid,"lstt",lstt, type(lstt))
+ commands.sendOSCUI("/stt/" + str(laserid), lstate[str(lstt)])
+ if gstt.debug >1:
+ print("DAC", laserid, "is in (lstt) :", lstt , lstate[str(lstt)])
+ if lstt == "0": # Dac IDLE state(0) -> led is blue (3)
+ sendWSall("/lstt/" + str(laserid) + " 3")
- if lstt == "2": # Dac PLAYING (2) -> led is green (1)
- sendWSall("/lstt/" + str(laserid) + " 1")
+ if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2)
+ sendWSall("/lstt/" + str(laserid) + " 2")
+
+ if lstt == "2": # Dac PLAYING (2) -> led is green (1)
+ sendWSall("/lstt/" + str(laserid) + " 1")
+
+
+ ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NOCONNECTION ?", '35': "NOCONNECTION ?" , '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NOCONNECTION", '0': "NOCONNECTION"}
+ lack= r.get('/lack/'+str(laserid)).decode('ascii')
+ commands.sendOSCUI("/ack/" + str(laserid), ackstate[str(lack)])
+ if gstt.debug >1:
+ print("DAC", laserid, "answered (lack):", lack, chr(int(lack)), ackstate[str(lack)])
+
+ if chr(int(lack)) == 'a': # Dac sent ACK ("a") -> led is green (1)
+ sendWSall("/lack/" + str(laserid) +" 1")
+
+ if chr(int(lack)) == 'F': # Dac sent FULL ("F") -> led is orange (5)
+ sendWSall("/lack/" + str(laserid) +" 5")
+
+ if chr(int(lack)) == 'I': # Dac sent INVALID ("I") -> led is yellow (4)
+ sendWSall("/lack/" + str(laserid)+" 4")
+ #print lack
-
- ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NOCONNECTION ?", '35': "NOCONNECTION ?" , '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NOCONNECTION", '0': "NOCONNECTION"}
- lack= r.get('/lack/'+str(laserid)).decode('ascii')
-
- if gstt.debug >1:
- print("DAC", laserid, "answered (lack):", lack, chr(int(lack)), ackstate[str(lack)])
-
- if chr(int(lack)) == 'a': # Dac sent ACK ("a") -> led is green (1)
- sendWSall("/lack/" + str(laserid) +" 1")
-
- if chr(int(lack)) == 'F': # Dac sent FULL ("F") -> led is orange (5)
- sendWSall("/lack/" + str(laserid) +" 5")
-
- if chr(int(lack)) == 'I': # Dac sent INVALID ("I") -> led is yellow (4)
- sendWSall("/lack/" + str(laserid)+" 4")
- #print lack
+ if lack == "64" or lack =="35": # no connection to dac -> leds are red (6)
+ sendWSall("/lack/" + str(laserid) + " 6")
+ sendWSall("/lstt/" + str(laserid) + " 6")
+ #sendWSall("/lstt/" + str(laserid) + " 0")
+ sendWSall("/points/" + str(laserid) + " 6")
- if lack == "64" or lack =="35": # no connection to dac -> leds are red (6)
- sendWSall("/lack/" + str(laserid) + " 6")
- sendWSall("/lstt/" + str(laserid) + " 6")
- #sendWSall("/lstt/" + str(laserid) + " 0")
- sendWSall("/points/" + str(laserid) + " 6")
-
- else:
- # last number of points sent to etherdream buffer
- sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid)).decode('ascii')))
+ else:
+ # last number of points sent to etherdream buffer
+ sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid)).decode('ascii')))
- #print("Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))
- #print(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)))
- sendWSall("/simul" +" "+ str(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)).decode('ascii')))
- if random.randint(0,100)>95:
- plugins.sendbroadcast()
+ #print("Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))
+ #print(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)))
+ sendWSall("/simul" +" "+ str(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)).decode('ascii')))
+ #commands.sendOSCUI("/cap/" + str(laserid), str(r.get('/cap/'+str(laserid)).decode('ascii')))
+ if random.randint(0,100)>95:
+ plugins.sendbroadcast()
- except Exception as e:
- import sys, traceback
- print('\n--------------------------')
- print('OSC Thread Exception: %s' % e)
- print('- - - - - - - - - - - - - - ')
- traceback.print_tb(sys.exc_info()[2])
- print("\n")
+ except Exception as e:
+ import sys, traceback
+ print('\n--------------------------')
+ print('OSC Thread Exception: %s' % e)
+ print('- - - - - - - - - - - - - - ')
+ traceback.print_tb(sys.exc_info()[2])
+ print("\n")
#
# Websocket part
#
-
+def get_Host_name_IP():
+ try:
+ host_name = socket.gethostname()
+ host_ip = socket.gethostbyname(host_name)
+ print("Hostname : ", host_name)
+ print("IP : ", host_ip)
+ except:
+ print("Unable to get Hostname and IP")
+ return host_ip
+
# Called for every WS client connecting (after handshake)
def new_client(client, wserver):
print("New WS client connected and was given id %d" % client['id'])
sendWSall("/status Hello " + str(client['id']))
+ #commands.sendOSCUI("/status", "Hello " + str(client['id']))
for laserid in range(0,gstt.LaserNumber):
@@ -312,7 +351,13 @@ def new_client(client, wserver):
# Called for every WS client disconnecting
def client_left(client, wserver):
- print("WS Client(%d) disconnected" % client['id'])
+
+ try:
+ print("WS Client(%d) disconnected" % client['id'])
+
+ except:
+ print("Something weird is coming from",client,"on the wire...")
+ pass
# Called for each WS received message.
@@ -334,7 +379,6 @@ def message_received(client, wserver, message):
message4plugin = False
# WS received Message is for a plugin ?
-
for plugin in list(gstt.plugins.keys()):
if oscpath[0].find(plugin) != -1:
@@ -346,9 +390,7 @@ def message_received(client, wserver, message):
else:
print("plugins detected", plugin, "offline.")
-
- # WS received message is an LJ command
-
+ # WS received message is an LJ command
if message4plugin == False:
if len(oscpath) == 1:
@@ -374,12 +416,20 @@ def sendWSall(message):
#if gstt.debug >0:
#print("WS sending %s" % (message))
wserver.send_message_to_all(message)
+
+ if gstt.TouchOSCUI == True:
+ if message[:7] == '/status':
+ print("Main WSall", message, message[:6])
+ commands.sendOSCUI('/status', message[8:])
+ if message[:5] == '/line1':
+ print("Main WSall", message, message[:6])
+ commands.sendOSCUI('/line1', message[6:])
+
'''
-print ""
-print "Midi Configuration"
-midi.InConfig()
-midi.OutConfig()
+print ("")
+log.info("Midi Configuration...")
+midi3.check()
'''
def fff(name):
@@ -395,7 +445,6 @@ def fff(name):
print("")
log.info("Creating startup point lists...")
-
if r.set("/clientkey","/pl/"+str(gstt.SceneNumber)+"/")==True:
print("sent clientkey : /pl/"+str(gstt.SceneNumber)+"/")
@@ -436,8 +485,6 @@ if __name__ == '__main__':
lasernumber = gstt.LaserNumber -1
print("LaserNumber = ", gstt.LaserNumber)
-
-
log.info("Starting "+str(gstt.LaserNumber) + " DACs process...")
# Launch one process (a tracer3 instance) by etherdream
@@ -471,14 +518,19 @@ if __name__ == '__main__':
try:
- # Websocket startup
- wserver = WebsocketServer(wsPORT,host=serverIP)
- plugins.Init(wserver)
-
log.info("Starting servers...")
+ hostIP= get_Host_name_IP()
+ if hostIP != gstt.wwwIP:
+ log.err("Host IP is : "+str(hostIP))
+ log.err("wwwIP in LJ.conf : "+str(gstt.wwwIP))
+ log.err("Update LJ.conf : python3 configure.py")
+ #gstt.wwwIP = hostIP
+ commands.LJautokill()
+ sys.exit()
+
# Launch OSC thread listening to oscserver
- print("Launching OSC server...")
- print("at", oscserverIPin, "port",str(oscserverPORTin))
+ print("Launching OSC server to receive messages (UI,...)")
+ print("binding at", oscserverIPin, "port",str(oscserverPORTin))
oscserver.addMsgHandler( "/noteon", commands.NoteOn)
oscserver.addMsgHandler( "/scim", commands.Scim)
oscserver.addMsgHandler( "/line1", commands.Line1)
@@ -486,19 +538,32 @@ if __name__ == '__main__':
# Default OSC handler for all OSC incoming message
oscserver.addMsgHandler("default", handler)
_thread.start_new_thread(osc_thread, ())
-
- print("Launching webUI Websocket server...")
- print("at", serverIP, "port",wsPORT)
+
+ #print()
+ # Websocket listening port
+ print("Listening for WebUI WS...")
+
+ hostIP= get_Host_name_IP()
+ if hostIP != gstt.wwwIP:
+ log.err("wwwIP in config is not set to "+str(hostIP))
+ gstt.wwwIP = hostIP
+ #commands.LJautokill()
+
+ print("binding at", gstt.wwwIP, "port",str(gstt.wsPORT))
+ wserver = WebsocketServer(gstt.wsPORT,host= gstt.wwwIP)
+ plugins.Init(wserver)
wserver.set_fn_new_client(new_client)
wserver.set_fn_client_left(client_left)
wserver.set_fn_message_received(message_received)
+
print("")
log.info("Resetting all Homographies...")
for laserid in range(0,gstt.LaserNumber):
homographyp.newEDH(laserid)
+ #midi3.check()
# plugins autostart
- print("")
+ #print("")
log.info("Plugins startup...")
if gstt.autostart != "":
diff --git a/plugins/aurora/anim.py b/plugins/aurora/anim.py
index 1bf4943..aabd87b 100644
--- a/plugins/aurora/anim.py
+++ b/plugins/aurora/anim.py
@@ -9,7 +9,7 @@ Aurora Animations points generators
LICENCE : CC
Sam Neurohack
-"ScanH", "ScanV", "Wave", "Circle", "Dot00", "Zero", "Maxwell", "Starfield", "Trckr", "Word"
+"ScanH", "ScanV", "Wave", "Circle", "Dot00", "Zero", "Maxwell", "Starfield", "Trckr", "Word", "Poses"
'''
@@ -29,7 +29,7 @@ sys.path.append(ljpath +'/../libs3/')
sys.path.append(ljpath +'/libs3/')
sys.path.append('../libs3')
-import lj23layers as lj
+import lj
import gstt
# link
@@ -175,6 +175,9 @@ def ssquare(samples, freq, phase, scale = 1):
samparray[ww] = signal.square(2 * np.pi * freq * t[ww]) * scale
return samparray
+
+
+
def ssine(samples, freq, phase, scale = 1):
samparray = [0] * samples
@@ -182,6 +185,7 @@ def ssine(samples, freq, phase, scale = 1):
for ww in range(samples):
samparray[ww] = np.sin(2 * np.pi * freq * t[ww]) * scale
return samparray
+#xsteps = ssine(LAY['scandots'], Cux['freq'], Cux['phaseoffset'] + Cux['inv'], Cux['amp'])
def scos(samples, freq, phase, scale = 1):
@@ -625,6 +629,124 @@ def Trckr(LAY, TrckrPts):
lj.rPolyLineOneColor(mouthfull(TrckrPts), c = LAY['color'], layer = LAY['number'], closed = False, xpos = -200 +LAY['Xcoord'], ypos = LAY['Ycoord'], resize = LAY['scale']*0.8, rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+#
+# Poses
+#
+
+# 0.25 : each frame will be repeated 4 times.
+animspeed = 0.1
+anims =[[]]*19
+
+def preparePoses(currentPose):
+
+ lj.WebStatus("Checking anims...")
+ print("Init Poses...")
+ print("Reading available Poses anims...")
+ # anim format (name, xpos, ypos, resize, currentframe, totalframe, count, speed)
+ # 0 1 2 3 4 5 6 7
+ # total frames is fetched from directory by lengthPOSE()
+
+ anims[0] = ['boredhh' , -100, 30, 550, 0, 0, 0, animspeed]
+ anims[1] = ['belka4' , -70, 380, 680, 0, 0, 0, animspeed]
+ anims[2] = ['belka3' , -100, 360, 700, 0, 0, 0, animspeed]
+ anims[3] = ['hhhead' , -100, 300, 600, 0, 0, 0, animspeed]
+ anims[4] = ['hhhead2', -100, 300, 600, 0, 0, 0, animspeed]
+ anims[5] = ['hhhead4', -100, 280, 600, 0, 0, 0, animspeed]
+ anims[6] = ['hhred' , -250, 220, 550, 0, 0, 0, animspeed]
+ anims[7] = ['hhred2' , -200, 200, 550, 0, 0, 0, animspeed]
+ anims[8] = ['lady1' , -100, 300, 600, 0, 0, 0, animspeed]
+ anims[9] = ['lady1' , -100, 280, 600, 0, 0, 0, animspeed]
+ anims[10] = ['lady2' , -100, 280, 600, 0, 0, 0, animspeed]
+ anims[11] = ['lady3' , -100, 300, 600, 0, 0, 0, animspeed]
+ anims[12] = ['lady4' , -100, 300, 600, 0, 0, 0, animspeed]
+ anims[13] = ['mila6' , -100, 280, 600, 0, 0, 0, animspeed]
+ anims[14] = ['mila5' , -100, 280, 600, 0, 0, 0, animspeed]
+ anims[15] = ['idiotia1', -100, 300, 600, 0, 0, 0, animspeed]
+ anims[16] = ['idiotia1', -100, 300, 600, 0, 0, 0, animspeed]
+ anims[17] = ['belka4', -100, 280, 600, 0, 0, 0, animspeed]
+ anims[18] = ['belka3', -100, 280, 600, 0, 0, 0, animspeed]
+
+ #for laseranims in anims:
+
+ for anim in anims:
+ #print(anim)
+ anim[5] = lengthPOSE(anim[0])
+ lj.WebStatus("Checking "+ anim[0] +"...")
+ if debug > 0:
+ print('plugins/aurora/poses/' + anim[0], "length :", anim[5], "frames")
+
+ print("Current Poses anim is",anims[currentPose][0],"("+str(currentPose)+")")
+
+#lj.RelativeObject('anim', True, 255, [], white, red, green, blue, 0 ,False, centerX, centerY, 1, Xrot, Yrot, Zrot)
+
+def Poses(LAY):
+
+ anim = anims[currentPose]
+ #anim = anims[LAY['poses']]
+ #print(anim)
+ #dots = []
+
+ # increase current frame [4] of speed [7] frames
+ # print(anim[4],anim[7],anim[4]+anim[7])
+ # print("frame", anim[4])
+ anim[4] = anim[4]+anim[7]
+ # print("animspeed",anim[7], "newframe", anim[4], "maximum frame", anim[5] )
+ # compare to total frame [5]
+ if anim[4] >= anim[5]:
+ anim[4] = 0
+
+ posename = 'plugins/aurora/poses/' + anim[0] + '/' + anim[0] +'-'+str("%05d"%int(anim[4]))+'.json'
+ # print(posename)
+ posefile = open(posename , 'r')
+ posedatas = posefile.read()
+ pose_json = json.loads(posedatas)
+ #WebStatus("Frame : "+str("%05d"%int(anim[4])))
+
+ # Draw Face
+
+ for people in range(len(pose_json['people'])):
+ '''
+ #lj.rPolyLineOneColor(face(pose_json, people), c = white, PL = laser closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ lj.rPolyLineOneColor(browL(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ lj.rPolyLineOneColor(browR(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ lj.rPolyLineOneColor(eyeR(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ #lj.rPolyLineOneColor(pupR(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ lj.rPolyLineOneColor(eyeL(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ #lj.rPolyLineOneColor(pupL(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ lj.rPolyLineOneColor(nose(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ lj.rPolyLineOneColor(mouth(pose_json, people), c = white, PL = laser, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3])
+ '''
+
+ lj.rPolyLineOneColor(browL(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = anim[3], rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ lj.rPolyLineOneColor(eyeL(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = anim[3], rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ lj.rPolyLineOneColor(browR(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = anim[3], rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ lj.rPolyLineOneColor(eyeR(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = anim[3], rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ #lj.rPolyLineOneColor(pupL(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = LAY['scale']*0.8, rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ #lj.rPolyLineOneColor(pupR(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = LAY['scale']*0.8, rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ lj.rPolyLineOneColor(nose1(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = anim[3], rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ lj.rPolyLineOneColor(nose2(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = anim[3], rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+ lj.rPolyLineOneColor(mouthfull(pose_json, people), c = LAY['color'], layer = LAY['number'], closed = False, xpos = anim[1] +LAY['Xcoord'], ypos = LAY['Ycoord'] + anim[2], resize = anim[3], rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
+
+
+import json
+#CurrentPose = 1
+
+# Get frame number for pose path describe in PoseDir
+def lengthPOSE(pose_dir):
+
+ if debug > 0:
+ print("Checking directory",'plugins/aurora/poses/' + pose_dir)
+ if os.path.exists('plugins/aurora/poses/' + pose_dir):
+
+ numfiles = sum(1 for f in os.listdir('plugins/aurora/poses/' + pose_dir) if os.path.isfile(os.path.join('plugins/VJing/poses/' + pose_dir + '/', f)) and f[0] != '.')
+ if debug > 0:
+ print(numfiles, 'frames')
+ return numfiles
+ else:
+ if debug > 0:
+ print("but it doesn't even exist!")
+ return 0
+
#
diff --git a/plugins/aurora/aurora.py b/plugins/aurora/aurora.py
index 5bdbe60..537d13f 100644
--- a/plugins/aurora/aurora.py
+++ b/plugins/aurora/aurora.py
@@ -172,7 +172,7 @@ if is_py2:
else:
from OSC3 import OSCServer, OSCClient, OSCMessage
-import lj23layers as lj
+import lj
import argparse
print()
@@ -275,11 +275,12 @@ else:
lj.Config(redisIP, ljscene, "aurora")
import anim, user
+#anim.
ccs =[[0] * 140] *4
# Layer FXs
-FXs = ["ScanH", "ScanV", "Wave", "Circle", "Dot00", "Zero", "Maxwell", "Starfield", "Trckr", "Word"]
+FXs = ["ScanH", "ScanV", "Wave", "Circle", "Dot00", "Zero", "Maxwell", "Starfield", "Trckr", "Word", "Poses"]
AllFXDisplay = [True, True, True, True]
@@ -374,6 +375,14 @@ def OSChandler(path, tags, args, source):
if len(args) > 0:
pass
+
+ # OSC ui connection
+ if path.find("/connect") :
+ print("OSCUI asked by", source)
+ gstt.TouchOSCUI = True
+ gstt.TouchOSCIP= source[0]
+ beatstepUI()
+ return
#Convert from TouchOSC full text OSC style (no args)
if path.find(" ") != -1:
@@ -507,6 +516,19 @@ def OSChandler(path, tags, args, source):
print("OSC default got /scim",int(args[0]))
#lj.SendLJ("/scim", [int(args[0])+24])
+ # /aurora/poses layer number
+ if path.find('/aurora/poses') == 0:
+
+ layer = int(args[0])
+ number = int(args[1])
+
+ #print(anim, state)
+
+ if state == 1:
+ print("/aurora/poses switch to",number)
+ Layer[layer]['poses'] = number
+
+
'''
# /aurora/color/layernumber color
def OSCcolor(path, tags, args, source):
@@ -970,7 +992,7 @@ def OSCaudioL(path, tags, args, source):
# OSC Beatstep
#
-beatstepfxs = ["anim.ScanH", "anim.ScanV", "anim.Wave", "anim.Circle", "anim.Starfield", "anim.Word", "anim.Trckr", "anim.ScanH"]
+beatstepfxs = ["anim.ScanH", "anim.ScanV", "anim.Wave", "anim.Circle", "anim.Starfield", "anim.Word", "anim.Trckr", "anim.Poses"]
beatstepcols = ["red", "yellow", "green", "blue", "cyan", "white", "white", "white"]
def beatstepUI():
@@ -1099,6 +1121,9 @@ def AllFX():
elif LAY['FX'] == "anim.Word":
anim.Word(LAY)
+ elif LAY['FX'] == "anim.Poses":
+ anim.Poses(LAY)
+
elif LAY['FX'] == "anim.User1":
user.User1(LAY)
@@ -1187,6 +1212,9 @@ def UpdateKnobs(layernumber):
prepareStarfield()
prepareTrckr()
+currentPose = 0
+lj.WebStatus("Init Poses...")
+anim.preparePoses(currentPose)
log.info("Starting OSC server at " + str(gstt.myIP)+ " port "+ str(OSCinPort)+ " ...")
#print("TouchOSC", gstt.TouchOSCIP)
@@ -1230,7 +1258,6 @@ lj.addOSCdefaults(oscserver)
oscserver.addMsgHandler( "default", OSChandler )
#anim.prepareSTARFIELD()
-beatstepUI()
#beatstep.UpdatePatch(beatstep.patchnumber)
diff --git a/plugins/aurora/maxwell.py b/plugins/aurora/maxwell.py
index a7a1290..099489f 100644
--- a/plugins/aurora/maxwell.py
+++ b/plugins/aurora/maxwell.py
@@ -145,7 +145,7 @@ if is_py2:
else:
from OSC3 import OSCServer, OSCClient, OSCMessage
-import lj23layers as lj
+import lj
import argparse
print ("")
diff --git a/plugins/aurora/midix.py b/plugins/aurora/midix.py
index 1167a02..037c0b0 100644
--- a/plugins/aurora/midix.py
+++ b/plugins/aurora/midix.py
@@ -140,22 +140,24 @@ def SendAU(oscaddress,oscargs=''):
def SendUI(oscaddress,oscargs=''):
- oscmsg = OSCMessage()
- oscmsg.setAddress(oscaddress)
- oscmsg.append(oscargs)
+ if gstt.TouchOSCUI == True:
+ oscmsg = OSCMessage()
+ oscmsg.setAddress(oscaddress)
+ oscmsg.append(oscargs)
- osclientlj = OSCClient()
- osclientlj.connect((gstt.TouchOSCIP, gstt.TouchOSCPort))
-
- #print("MIDI Aurora sending UI :", oscmsg, "to",gstt.TouchOSCIP,":",gstt.TouchOSCPort)
- try:
- osclientlj.sendto(oscmsg, (gstt.TouchOSCIP, gstt.TouchOSCPort))
- oscmsg.clearData()
- except:
- log.err('Connection to Aurora UI refused : died ?')
- pass
- #time.sleep(0.001
+ osclientlj = OSCClient()
+ osclientlj.connect((gstt.TouchOSCIP, gstt.TouchOSCPort))
+ #print("MIDI Aurora sending UI :", oscmsg, "to",gstt.TouchOSCIP,":",gstt.TouchOSCPort)
+ try:
+ osclientlj.sendto(oscmsg, (gstt.TouchOSCIP, gstt.TouchOSCPort))
+ oscmsg.clearData()
+ except:
+ log.err('Connection to Aurora UI refused : died ?')
+ pass
+ #time.sleep(0.001)
+ else:
+ print(oscaddress,": No remote OSC connected yet")
def GetTime():
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
@@ -730,15 +732,15 @@ def NoteOn(note, velocity, mididest):
def listdevice(number):
-
- return midiname[number]
+
+ return midiname[number]
-
+
def check():
OutConfig()
InConfig()
-
+
diff --git a/plugins/aurora/user.py b/plugins/aurora/user.py
index 23dcf5b..8200a2a 100644
--- a/plugins/aurora/user.py
+++ b/plugins/aurora/user.py
@@ -111,7 +111,7 @@ ljpath = r'%s' % os.getcwd().replace('\\','/')
sys.path.append('../libs3')
#sys.path.append(ljpath +'/../../libs')
-import lj23layers as lj
+import lj
width = 800
height = 600
diff --git a/plugins/custom1.py b/plugins/custom1.py
index 3ee5e6f..b70bbe5 100644
--- a/plugins/custom1.py
+++ b/plugins/custom1.py
@@ -31,7 +31,7 @@ sys.path.append(ljpath +'/../libs3/')
sys.path.append(ljpath +'/libs3/')
print(ljpath+'/../libs3/')
-import lj23layers as lj
+import lj
sys.path.append('../libs3')
from OSC3 import OSCServer, OSCClient, OSCMessage
diff --git a/plugins/square.py b/plugins/square.py
index 9b48d3f..9aa4f3c 100644
--- a/plugins/square.py
+++ b/plugins/square.py
@@ -31,7 +31,7 @@ sys.path.append(ljpath +'/../libs3/')
sys.path.append(ljpath +'/libs3/')
print(ljpath+'/../libs3/')
-import lj23layers as lj
+import lj
sys.path.append('../libs3')
from OSC3 import OSCServer, OSCClient, OSCMessage
diff --git a/plugins/trckr.py b/plugins/trckr.py
index fa449cc..7e269d4 100644
--- a/plugins/trckr.py
+++ b/plugins/trckr.py
@@ -48,7 +48,7 @@ sys.path.append('../libs3')
sys.path.append(ljpath +'/../../libs3')
from OSC3 import OSCServer, OSCClient, OSCMessage
-import lj23layers as lj
+import lj
import redis
import math
import time
diff --git a/server/install.sh b/server/install.sh
index 3f2e34b..b2b375b 100755
--- a/server/install.sh
+++ b/server/install.sh
@@ -1,4 +1,5 @@
#!/bin/bash
+sudo apt update
sudo apt upgrade
sudo apt install python3-pip
sudo apt install redis-server
@@ -15,6 +16,8 @@ sudo apt install redis-server
#sudo cp syncthing.conf to /etc/supervisor/conf.d/
pip3 install scipy
pip3 install numpy
+sudo apt-get install python-scipy
+sudo apt install libatlas-base-dev
#pip install pygame==1.9.2
#pip3 install pygame==1.9.2
pip3 install redis
diff --git a/server/install.sh.darwin b/server/install.sh.darwin
deleted file mode 100644
index 63edb84..0000000
--- a/server/install.sh.darwin
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/bash
-brew upgrade
-brew install python3-pip
-brew install git
-brew install redis
-#brew install htop
-#brew install syncthing
-#brew install screen
-#brew install tmux
-#brew install nginx
-#brew install supervisor
-
-pip3 install scipy
-pip3 install numpy
-#pip3 install pygame==1.9.2
-# brew install vulkan-headers
-pip3 install redis
-pip3 install pysimpledmx
-pip3 install DMXEnttecPro
-brew install libasound2-dev
-brew install libjack-dev
-pip3 install python-rtmidi
-pip3 install mido
-#pip3 install tk
-cd ../
-python3 configure.py
-#sudo cp syncthing.conf to /etc/supervisor/conf.d/
-git clone https://github.com/ptone/pyosc --depth 1 /tmp/pyosc && cd /tmp/pyosc && sudo ./setup.py install
-cd /tmp
-brew install portaudio19-dev
-brew install cmake
-
-
-#
-# Ableton link
-#
-
-git clone https://github.com/Ableton/link.git
-cd link
-git submodule update --init --recursive
-mkdir build
-cd build
-cmake ..
-cmake --build .
-
-cd /tmp/
-git clone --recursive https://github.com/gonzaloflirt/link-python.git
-cd link-python
-mkdir build
-cd build
-cmake ..
-
-# After cmake.. to build for non-apple python but brew style python :
-#
-# change in /tmp/link-python/build/CMakeCache.txt
-
-#//Path to a program.
-#PYTHON_EXECUTABLE:FILEPATH=/usr/local/bin/python3
-
-#//Path to a library.
-#PYTHON_LIBRARY:FILEPATH=/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/libpython3.8.dylib
-
-
-cmake --build .
diff --git a/templates/LJpad.touchosc b/templates/LJpad.touchosc
new file mode 100644
index 0000000..2e5d396
Binary files /dev/null and b/templates/LJpad.touchosc differ
diff --git a/www/auralls.html b/www/auralls.html
index daf2a20..10c14a4 100644
--- a/www/auralls.html
+++ b/www/auralls.html
@@ -59,7 +59,7 @@