update fork to current state of original repository
* also include the Timer1 library directly for less hassle
This commit is contained in:
parent
7b20c89240
commit
e29a4203ed
|
@ -1,4 +1,4 @@
|
|||
#include <TimerOne.h>
|
||||
#include "TimerOne.h"
|
||||
|
||||
boolean firstRun = true; // Used for one-run-only stuffs;
|
||||
|
||||
|
@ -8,32 +8,32 @@ const byte PIN_MAX = 17;
|
|||
#define RESOLUTION 40 //Microsecond resolution for notes
|
||||
|
||||
|
||||
/*NOTE: Many of the arrays below contain unused indexes. This is
|
||||
to prevent the Arduino from having to convert a pin input to an alternate
|
||||
array index and save as many cycles as possible. In other words information
|
||||
for pin 2 will be stored in index 2, and information for pin 4 will be
|
||||
stored in index 4.*/
|
||||
/*NOTE: Many of the arrays below contain unused indexes. This is
|
||||
to prevent the Arduino from having to convert a pin input to an alternate
|
||||
array index and save as many cycles as possible. In other words information
|
||||
for pin 2 will be stored in index 2, and information for pin 4 will be
|
||||
stored in index 4.*/
|
||||
|
||||
|
||||
/*An array of maximum track positions for each step-control pin. Even pins
|
||||
are used for control, so only even numbers need a value here. 3.5" Floppies have
|
||||
80 tracks, 5.25" have 50. These should be doubled, because each tick is now
|
||||
half a position (use 158 and 98).
|
||||
*/
|
||||
are used for control, so only even numbers need a value here. 3.5" Floppies have
|
||||
80 tracks, 5.25" have 50. These should be doubled, because each tick is now
|
||||
half a position (use 158 and 98).
|
||||
*/
|
||||
byte MAX_POSITION[] = {
|
||||
0,0,158,0,158,0,158,0,158,0,158,0,158,0,158,0,158,0};
|
||||
|
||||
|
||||
//Array to track the current position of each floppy head. (Only even indexes (i.e. 2,4,6...) are used)
|
||||
byte currentPosition[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
/*Array to keep track of state of each pin. Even indexes track the control-pins for toggle purposes. Odd indexes
|
||||
track direction-pins. LOW = forward, HIGH=reverse
|
||||
*/
|
||||
track direction-pins. LOW = forward, HIGH=reverse
|
||||
*/
|
||||
int currentState[] = {
|
||||
0,0,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW
|
||||
};
|
||||
|
||||
|
||||
//Current period assigned to each pin. 0 = off. Each period is of the length specified by the RESOLUTION
|
||||
//variable above. i.e. A period of 10 is (RESOLUTION x 10) microseconds long.
|
||||
unsigned int currentPeriod[] = {
|
||||
|
@ -42,7 +42,7 @@ unsigned int currentPeriod[] = {
|
|||
|
||||
//Current tick
|
||||
unsigned int currentTick[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
|
||||
|
@ -75,7 +75,7 @@ void setup(){
|
|||
|
||||
|
||||
void loop(){
|
||||
|
||||
|
||||
//The first loop, reset all the drives, and wait 2 seconds...
|
||||
if (firstRun)
|
||||
{
|
||||
|
@ -84,7 +84,7 @@ void loop(){
|
|||
delay(2000);
|
||||
}
|
||||
|
||||
//Only read if we have
|
||||
//Only read if we have
|
||||
if (Serial.available() > 2){
|
||||
//Watch for special 100-message to reset the drives
|
||||
if (Serial.peek() == 100) {
|
||||
|
@ -93,7 +93,7 @@ void loop(){
|
|||
while(Serial.available() > 0){
|
||||
Serial.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
currentPeriod[Serial.read()] = (Serial.read() << 8) | Serial.read();
|
||||
}
|
||||
|
@ -103,13 +103,13 @@ void loop(){
|
|||
|
||||
/*
|
||||
Called by the timer inturrupt at the specified resolution.
|
||||
*/
|
||||
*/
|
||||
void tick()
|
||||
{
|
||||
/*
|
||||
If there is a period set for control pin 2, count the number of
|
||||
ticks that pass, and toggle the pin if the current period is reached.
|
||||
*/
|
||||
/*
|
||||
If there is a period set for control pin 2, count the number of
|
||||
ticks that pass, and toggle the pin if the current period is reached.
|
||||
*/
|
||||
if (currentPeriod[2]>0){
|
||||
currentTick[2]++;
|
||||
if (currentTick[2] >= currentPeriod[2]){
|
||||
|
@ -166,29 +166,29 @@ void tick()
|
|||
currentTick[16]=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void togglePin(byte pin, byte direction_pin) {
|
||||
|
||||
|
||||
//Switch directions if end has been reached
|
||||
if (currentPosition[pin] >= MAX_POSITION[pin]) {
|
||||
currentState[direction_pin] = HIGH;
|
||||
digitalWrite(direction_pin,HIGH);
|
||||
}
|
||||
}
|
||||
else if (currentPosition[pin] <= 0) {
|
||||
currentState[direction_pin] = LOW;
|
||||
digitalWrite(direction_pin,LOW);
|
||||
}
|
||||
|
||||
//Update currentPosition
|
||||
|
||||
//Update currentPosition
|
||||
if (currentState[direction_pin] == HIGH){
|
||||
currentPosition[pin]--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentPosition[pin]++;
|
||||
}
|
||||
|
||||
|
||||
//Pulse the control pin
|
||||
digitalWrite(pin,currentState[pin]);
|
||||
currentState[pin] = ~currentState[pin];
|
||||
|
@ -203,7 +203,7 @@ void togglePin(byte pin, byte direction_pin) {
|
|||
void blinkLED(){
|
||||
digitalWrite(13, HIGH); // set the LED on
|
||||
delay(250); // wait for a second
|
||||
digitalWrite(13, LOW);
|
||||
digitalWrite(13, LOW);
|
||||
}
|
||||
|
||||
//For a given controller pin, runs the read-head all the way back to 0
|
||||
|
@ -222,12 +222,17 @@ void reset(byte pin)
|
|||
|
||||
//Resets all the pins
|
||||
void resetAll(){
|
||||
|
||||
|
||||
// Old one-at-a-time reset
|
||||
//for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
|
||||
// reset(p);
|
||||
//}
|
||||
|
||||
|
||||
//Stop all notes (don't want to be playing during/after reset)
|
||||
for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
|
||||
currentPeriod[p] = 0; // Stop playing notes
|
||||
}
|
||||
|
||||
// New all-at-once reset
|
||||
for (byte s=0;s<80;s++){ // For max drive's position
|
||||
for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
|
||||
|
@ -237,14 +242,11 @@ void resetAll(){
|
|||
}
|
||||
delay(5);
|
||||
}
|
||||
|
||||
|
||||
for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
|
||||
currentPosition[p] = 0; // We're reset.
|
||||
digitalWrite(p+1,LOW);
|
||||
currentState[p+1] = 0; // Ready to go forward.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
209
Arduino/Moppy/TimerOne.cpp
Normal file
209
Arduino/Moppy/TimerOne.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
|
||||
* Original code by Jesse Tane for http://labs.ideo.com August 2008
|
||||
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
|
||||
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
|
||||
* Modified June 2011 by Lex Talionis to add a function to read the timer
|
||||
* Modified Oct 2011 by Andrew Richards to avoid certain problems:
|
||||
* - Add (long) assignments and casts to TimerOne::read() to ensure calculations involving tmp, ICR1 and TCNT1 aren't truncated
|
||||
* - Ensure 16 bit registers accesses are atomic - run with interrupts disabled when accessing
|
||||
* - Remove global enable of interrupts (sei())- could be running within an interrupt routine)
|
||||
* - Disable interrupts whilst TCTN1 == 0. Datasheet vague on this, but experiment shows that overflow interrupt
|
||||
* flag gets set whilst TCNT1 == 0, resulting in a phantom interrupt. Could just set to 1, but gets inaccurate
|
||||
* at very short durations
|
||||
* - startBottom() added to start counter at 0 and handle all interrupt enabling.
|
||||
* - start() amended to enable interrupts
|
||||
* - restart() amended to point at startBottom()
|
||||
* Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis
|
||||
* - renamed start() to resume() to reflect it's actual role
|
||||
* - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest
|
||||
*/
|
||||
#ifndef TIMERONE_cpp
|
||||
#define TIMERONE_cpp
|
||||
|
||||
#include "TimerOne.h"
|
||||
|
||||
TimerOne Timer1; // preinstatiate
|
||||
|
||||
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
|
||||
{
|
||||
Timer1.isrCallback();
|
||||
}
|
||||
|
||||
|
||||
void TimerOne::initialize(long microseconds)
|
||||
{
|
||||
TCCR1A = 0; // clear control register A
|
||||
TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer
|
||||
setPeriod(microseconds);
|
||||
}
|
||||
|
||||
|
||||
void TimerOne::setPeriod(long microseconds) // AR modified for atomic access
|
||||
{
|
||||
|
||||
long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
|
||||
if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal
|
||||
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8
|
||||
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
|
||||
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256
|
||||
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
|
||||
else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum
|
||||
|
||||
oldSREG = SREG;
|
||||
cli(); // Disable interrupts for 16 bit register access
|
||||
ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode
|
||||
SREG = oldSREG;
|
||||
|
||||
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
|
||||
TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock
|
||||
}
|
||||
|
||||
void TimerOne::setPwmDuty(char pin, int duty)
|
||||
{
|
||||
unsigned long dutyCycle = pwmPeriod;
|
||||
|
||||
dutyCycle *= duty;
|
||||
dutyCycle >>= 10;
|
||||
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
if(pin == 1 || pin == 9) OCR1A = dutyCycle;
|
||||
else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
|
||||
SREG = oldSREG;
|
||||
}
|
||||
|
||||
void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
|
||||
{
|
||||
if(microseconds > 0) setPeriod(microseconds);
|
||||
if(pin == 1 || pin == 9) {
|
||||
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
|
||||
TCCR1A |= _BV(COM1A1); // activates the output pin
|
||||
}
|
||||
else if(pin == 2 || pin == 10) {
|
||||
DDRB |= _BV(PORTB2);
|
||||
TCCR1A |= _BV(COM1B1);
|
||||
}
|
||||
setPwmDuty(pin, duty);
|
||||
resume(); // Lex - make sure the clock is running. We don't want to restart the count, in case we are starting the second WGM
|
||||
// and the first one is in the middle of a cycle
|
||||
}
|
||||
|
||||
void TimerOne::disablePwm(char pin)
|
||||
{
|
||||
if(pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1
|
||||
else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2
|
||||
}
|
||||
|
||||
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
|
||||
{
|
||||
if(microseconds > 0) setPeriod(microseconds);
|
||||
isrCallback = isr; // register the user's callback with the real ISR
|
||||
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
|
||||
// might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
|
||||
// sei();
|
||||
resume();
|
||||
}
|
||||
|
||||
void TimerOne::detachInterrupt()
|
||||
{
|
||||
TIMSK1 &= ~_BV(TOIE1); // clears the timer overflow interrupt enable bit
|
||||
// timer continues to count without calling the isr
|
||||
}
|
||||
|
||||
void TimerOne::resume() // AR suggested
|
||||
{
|
||||
TCCR1B |= clockSelectBits;
|
||||
}
|
||||
|
||||
void TimerOne::restart() // Depricated - Public interface to start at zero - Lex 10/9/2011
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void TimerOne::start() // AR addition, renamed by Lex to reflect it's actual role
|
||||
{
|
||||
unsigned int tcnt1;
|
||||
|
||||
TIMSK1 &= ~_BV(TOIE1); // AR added
|
||||
GTCCR |= _BV(PSRSYNC); // AR added - reset prescaler (NB: shared with all 16 bit timers);
|
||||
|
||||
oldSREG = SREG; // AR - save status register
|
||||
cli(); // AR - Disable interrupts
|
||||
TCNT1 = 0;
|
||||
SREG = oldSREG; // AR - Restore status register
|
||||
resume();
|
||||
do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
tcnt1 = TCNT1;
|
||||
SREG = oldSREG;
|
||||
} while (tcnt1==0);
|
||||
|
||||
// TIFR1 = 0xff; // AR - Clear interrupt flags
|
||||
// TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
|
||||
}
|
||||
|
||||
void TimerOne::stop()
|
||||
{
|
||||
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits
|
||||
}
|
||||
|
||||
unsigned long TimerOne::read() //returns the value of the timer in microseconds
|
||||
{ //rember! phase and freq correct mode counts up to then down again
|
||||
unsigned long tmp; // AR amended to hold more than 65536 (could be nearly double this)
|
||||
unsigned int tcnt1; // AR added
|
||||
|
||||
oldSREG= SREG;
|
||||
cli();
|
||||
tmp=TCNT1;
|
||||
SREG = oldSREG;
|
||||
|
||||
char scale=0;
|
||||
switch (clockSelectBits)
|
||||
{
|
||||
case 1:// no prescalse
|
||||
scale=0;
|
||||
break;
|
||||
case 2:// x8 prescale
|
||||
scale=3;
|
||||
break;
|
||||
case 3:// x64
|
||||
scale=6;
|
||||
break;
|
||||
case 4:// x256
|
||||
scale=8;
|
||||
break;
|
||||
case 5:// x1024
|
||||
scale=10;
|
||||
break;
|
||||
}
|
||||
|
||||
do { // Nothing -- max delay here is ~1023 cycles. AR modified
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
tcnt1 = TCNT1;
|
||||
SREG = oldSREG;
|
||||
} while (tcnt1==tmp); //if the timer has not ticked yet
|
||||
|
||||
//if we are counting down add the top value to how far we have counted down
|
||||
tmp = ( (tcnt1>tmp) ? (tmp) : (long)(ICR1-tcnt1)+(long)ICR1 ); // AR amended to add casts and reuse previous TCNT1
|
||||
return ((tmp*1000L)/(F_CPU /1000L))<<scale;
|
||||
}
|
||||
|
||||
#endif
|
70
Arduino/Moppy/TimerOne.h
Normal file
70
Arduino/Moppy/TimerOne.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
|
||||
* Original code by Jesse Tane for http://labs.ideo.com August 2008
|
||||
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
|
||||
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
|
||||
* Modified June 2011 by Lex Talionis to add a function to read the timer
|
||||
* Modified Oct 2011 by Andrew Richards to avoid certain problems:
|
||||
* - Add (long) assignments and casts to TimerOne::read() to ensure calculations involving tmp, ICR1 and TCNT1 aren't truncated
|
||||
* - Ensure 16 bit registers accesses are atomic - run with interrupts disabled when accessing
|
||||
* - Remove global enable of interrupts (sei())- could be running within an interrupt routine)
|
||||
* - Disable interrupts whilst TCTN1 == 0. Datasheet vague on this, but experiment shows that overflow interrupt
|
||||
* flag gets set whilst TCNT1 == 0, resulting in a phantom interrupt. Could just set to 1, but gets inaccurate
|
||||
* at very short durations
|
||||
* - startBottom() added to start counter at 0 and handle all interrupt enabling.
|
||||
* - start() amended to enable interrupts
|
||||
* - restart() amended to point at startBottom()
|
||||
* Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis
|
||||
* - renamed start() to resume() to reflect it's actual role
|
||||
* - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest
|
||||
*/
|
||||
#ifndef TIMERONE_h
|
||||
#define TIMERONE_h
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#define RESOLUTION 65536 // Timer1 is 16 bit
|
||||
|
||||
class TimerOne
|
||||
{
|
||||
public:
|
||||
|
||||
// properties
|
||||
unsigned int pwmPeriod;
|
||||
unsigned char clockSelectBits;
|
||||
char oldSREG; // To hold Status Register while ints disabled
|
||||
|
||||
// methods
|
||||
void initialize(long microseconds=1000000);
|
||||
void start();
|
||||
void stop();
|
||||
void restart();
|
||||
void resume();
|
||||
unsigned long read();
|
||||
void pwm(char pin, int duty, long microseconds=-1);
|
||||
void disablePwm(char pin);
|
||||
void attachInterrupt(void (*isr)(), long microseconds=-1);
|
||||
void detachInterrupt();
|
||||
void setPeriod(long microseconds);
|
||||
void setPwmDuty(char pin, int duty);
|
||||
void (*isrCallback)();
|
||||
};
|
||||
|
||||
extern TimerOne Timer1;
|
||||
#endif
|
|
@ -51,8 +51,7 @@
|
|||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar-with-manifest: JAR building (if you are using a manifest)
|
||||
-do-jar-without-manifest: JAR building (if you are not using a manifest)
|
||||
-do-jar: JAR building
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -12,18 +12,18 @@ is divided into following sections:
|
|||
- execution
|
||||
- debugging
|
||||
- javadoc
|
||||
- junit compilation
|
||||
- junit execution
|
||||
- junit debugging
|
||||
- test compilation
|
||||
- test execution
|
||||
- test debugging
|
||||
- applet
|
||||
- cleanup
|
||||
|
||||
-->
|
||||
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="MoppyDesk-impl">
|
||||
<fail message="Please build using Ant 1.7.1 or higher.">
|
||||
<fail message="Please build using Ant 1.8.0 or higher.">
|
||||
<condition>
|
||||
<not>
|
||||
<antversion atleast="1.7.1"/>
|
||||
<antversion atleast="1.8.0"/>
|
||||
</not>
|
||||
</condition>
|
||||
</fail>
|
||||
|
@ -54,6 +54,7 @@ is divided into following sections:
|
|||
<property file="nbproject/project.properties"/>
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
|
||||
<property name="platform.java" value="${java.home}/bin/java"/>
|
||||
<available file="${manifest.file}" property="manifest.available"/>
|
||||
<condition property="splashscreen.available">
|
||||
<and>
|
||||
|
@ -71,16 +72,20 @@ is divided into following sections:
|
|||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="manifest.available+main.class">
|
||||
<condition property="profile.available">
|
||||
<and>
|
||||
<isset property="manifest.available"/>
|
||||
<isset property="main.class.available"/>
|
||||
<isset property="javac.profile"/>
|
||||
<length length="0" string="${javac.profile}" when="greater"/>
|
||||
<matches pattern="1\.[89](\..*)?" string="${javac.source}"/>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="do.archive">
|
||||
<not>
|
||||
<istrue value="${jar.archive.disabled}"/>
|
||||
</not>
|
||||
<or>
|
||||
<not>
|
||||
<istrue value="${jar.archive.disabled}"/>
|
||||
</not>
|
||||
<istrue value="${not.archive.disabled}"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition property="do.mkdist">
|
||||
<and>
|
||||
|
@ -91,12 +96,6 @@ is divided into following sections:
|
|||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="manifest.available+main.class+mkdist.available">
|
||||
<and>
|
||||
<istrue value="${manifest.available+main.class}"/>
|
||||
<isset property="do.mkdist"/>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="do.archive+manifest.available">
|
||||
<and>
|
||||
<isset property="manifest.available"/>
|
||||
|
@ -115,24 +114,12 @@ is divided into following sections:
|
|||
<istrue value="${do.archive}"/>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="do.archive+manifest.available+main.class">
|
||||
<condition property="do.archive+profile.available">
|
||||
<and>
|
||||
<istrue value="${manifest.available+main.class}"/>
|
||||
<isset property="profile.available"/>
|
||||
<istrue value="${do.archive}"/>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="manifest.available-mkdist.available">
|
||||
<or>
|
||||
<istrue value="${manifest.available}"/>
|
||||
<isset property="do.mkdist"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition property="manifest.available+main.class-mkdist.available">
|
||||
<or>
|
||||
<istrue value="${manifest.available+main.class}"/>
|
||||
<isset property="do.mkdist"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition property="have.tests">
|
||||
<or>
|
||||
<available file="${test.src.dir}"/>
|
||||
|
@ -156,6 +143,7 @@ is divided into following sections:
|
|||
</and>
|
||||
</condition>
|
||||
<property name="run.jvmargs" value=""/>
|
||||
<property name="run.jvmargs.ide" value=""/>
|
||||
<property name="javac.compilerargs" value=""/>
|
||||
<property name="work.dir" value="${basedir}"/>
|
||||
<condition property="no.deps">
|
||||
|
@ -185,7 +173,15 @@ is divided into following sections:
|
|||
</condition>
|
||||
<path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
|
||||
<condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
|
||||
<length length="0" string="${endorsed.classpath}" when="greater"/>
|
||||
<and>
|
||||
<isset property="endorsed.classpath"/>
|
||||
<not>
|
||||
<equals arg1="${endorsed.classpath}" arg2="" trim="true"/>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<condition else="" property="javac.profile.cmd.line.arg" value="-profile ${javac.profile}">
|
||||
<isset property="profile.available"/>
|
||||
</condition>
|
||||
<condition else="false" property="jdkBug6558476">
|
||||
<and>
|
||||
|
@ -198,7 +194,29 @@ is divided into following sections:
|
|||
<property name="javac.fork" value="${jdkBug6558476}"/>
|
||||
<property name="jar.index" value="false"/>
|
||||
<property name="jar.index.metainf" value="${jar.index}"/>
|
||||
<property name="copylibs.rebase" value="true"/>
|
||||
<available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
|
||||
<condition property="junit.available">
|
||||
<or>
|
||||
<available classname="org.junit.Test" classpath="${run.test.classpath}"/>
|
||||
<available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition property="testng.available">
|
||||
<available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
|
||||
</condition>
|
||||
<condition property="junit+testng.available">
|
||||
<and>
|
||||
<istrue value="${junit.available}"/>
|
||||
<istrue value="${testng.available}"/>
|
||||
</and>
|
||||
</condition>
|
||||
<condition else="testng" property="testng.mode" value="mixed">
|
||||
<istrue value="${junit+testng.available}"/>
|
||||
</condition>
|
||||
<condition else="" property="testng.debug.mode" value="-mixed">
|
||||
<istrue value="${junit+testng.available}"/>
|
||||
</condition>
|
||||
</target>
|
||||
<target name="-post-init">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
|
@ -252,6 +270,7 @@ is divided into following sections:
|
|||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
<compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
|
||||
<compilerarg line="${javac.profile.cmd.line.arg}"/>
|
||||
<compilerarg line="${javac.compilerargs}"/>
|
||||
<compilerarg value="-processorpath"/>
|
||||
<compilerarg path="@{processorpath}:${empty.dir}"/>
|
||||
|
@ -291,6 +310,7 @@ is divided into following sections:
|
|||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
<compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
|
||||
<compilerarg line="${javac.profile.cmd.line.arg}"/>
|
||||
<compilerarg line="${javac.compilerargs}"/>
|
||||
<customize/>
|
||||
</javac>
|
||||
|
@ -331,11 +351,57 @@ is divided into following sections:
|
|||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target name="-init-macrodef-junit">
|
||||
<target if="${junit.available}" name="-init-macrodef-junit-init">
|
||||
<condition else="false" property="nb.junit.batch" value="true">
|
||||
<and>
|
||||
<istrue value="${junit.available}"/>
|
||||
<not>
|
||||
<isset property="test.method"/>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<condition else="false" property="nb.junit.single" value="true">
|
||||
<and>
|
||||
<istrue value="${junit.available}"/>
|
||||
<isset property="test.method"/>
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
<target name="-init-test-properties">
|
||||
<property name="test.binaryincludes" value="<nothing>"/>
|
||||
<property name="test.binarytestincludes" value=""/>
|
||||
<property name="test.binaryexcludes" value=""/>
|
||||
</target>
|
||||
<target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
|
||||
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<property name="junit.forkmode" value="perTest"/>
|
||||
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
|
||||
<test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<formatter type="brief" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<customize/>
|
||||
</junit>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
|
||||
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<property name="junit.forkmode" value="perTest"/>
|
||||
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
|
||||
|
@ -343,33 +409,277 @@ is divided into following sections:
|
|||
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
|
||||
<filename name="@{testincludes}"/>
|
||||
</fileset>
|
||||
<fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
|
||||
<filename name="${test.binarytestincludes}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
<classpath>
|
||||
<path path="${run.test.classpath}"/>
|
||||
</classpath>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<formatter type="brief" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
<customize/>
|
||||
</junit>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" name="profile-init"/>
|
||||
<target name="-profile-pre-init">
|
||||
<target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
|
||||
<target if="${testng.available}" name="-init-macrodef-testng">
|
||||
<macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
|
||||
<isset property="test.method"/>
|
||||
</condition>
|
||||
<union id="test.set">
|
||||
<fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
|
||||
<filename name="@{testincludes}"/>
|
||||
</fileset>
|
||||
</union>
|
||||
<taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
|
||||
<testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="MoppyDesk" testname="TestNG tests" workingDir="${work.dir}">
|
||||
<xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
|
||||
<propertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</propertyset>
|
||||
<customize/>
|
||||
</testng>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target name="-init-macrodef-test-impl">
|
||||
<macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element implicit="true" name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<echo>No tests executed.</echo>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
|
||||
<macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element implicit="true" name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
|
||||
<customize/>
|
||||
</j2seproject3:junit>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
|
||||
<macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element implicit="true" name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
|
||||
<customize/>
|
||||
</j2seproject3:testng>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
|
||||
<macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<sequential>
|
||||
<j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
|
||||
<customize>
|
||||
<classpath>
|
||||
<path path="${run.test.classpath}"/>
|
||||
</classpath>
|
||||
<jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
<jvmarg line="${run.jvmargs.ide}"/>
|
||||
</customize>
|
||||
</j2seproject3:test-impl>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
|
||||
<macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<property name="junit.forkmode" value="perTest"/>
|
||||
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
|
||||
<test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<formatter type="brief" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg line="${debug-args-line}"/>
|
||||
<jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
|
||||
<customize/>
|
||||
</junit>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
|
||||
<macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<property name="junit.forkmode" value="perTest"/>
|
||||
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
|
||||
<batchtest todir="${build.test.results.dir}">
|
||||
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
|
||||
<filename name="@{testincludes}"/>
|
||||
</fileset>
|
||||
<fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
|
||||
<filename name="${test.binarytestincludes}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<formatter type="brief" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg line="${debug-args-line}"/>
|
||||
<jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
|
||||
<customize/>
|
||||
</junit>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
|
||||
<macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<element implicit="true" name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
|
||||
<customize/>
|
||||
</j2seproject3:junit-debug>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target if="${testng.available}" name="-init-macrodef-testng-debug">
|
||||
<macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${main.class}" name="testClass"/>
|
||||
<attribute default="" name="testMethod"/>
|
||||
<element name="customize2" optional="true"/>
|
||||
<sequential>
|
||||
<condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
|
||||
<isset property="test.method"/>
|
||||
</condition>
|
||||
<condition else="-suitename MoppyDesk -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
|
||||
<matches pattern=".*\.xml" string="@{testClass}"/>
|
||||
</condition>
|
||||
<delete dir="${build.test.results.dir}" quiet="true"/>
|
||||
<mkdir dir="${build.test.results.dir}"/>
|
||||
<j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
|
||||
<customize>
|
||||
<customize2/>
|
||||
<jvmarg value="-ea"/>
|
||||
<arg line="${testng.debug.mode}"/>
|
||||
<arg line="-d ${build.test.results.dir}"/>
|
||||
<arg line="-listener org.testng.reporters.VerboseReporter"/>
|
||||
<arg line="${testng.cmd.args}"/>
|
||||
</customize>
|
||||
</j2seproject3:debug>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
|
||||
<macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${main.class}" name="testClass"/>
|
||||
<attribute default="" name="testMethod"/>
|
||||
<element implicit="true" name="customize2" optional="true"/>
|
||||
<sequential>
|
||||
<j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
|
||||
<customize2/>
|
||||
</j2seproject3:testng-debug>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
|
||||
<macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<attribute default="${main.class}" name="testClass"/>
|
||||
<attribute default="" name="testMethod"/>
|
||||
<sequential>
|
||||
<j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
|
||||
<customize>
|
||||
<classpath>
|
||||
<path path="${run.test.classpath}"/>
|
||||
</classpath>
|
||||
<jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
<jvmarg line="${run.jvmargs.ide}"/>
|
||||
</customize>
|
||||
</j2seproject3:test-debug-impl>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
|
||||
<macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<attribute default="" name="testmethods"/>
|
||||
<attribute default="${main.class}" name="testClass"/>
|
||||
<attribute default="" name="testMethod"/>
|
||||
<sequential>
|
||||
<j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
|
||||
<customize2>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
</customize2>
|
||||
</j2seproject3:testng-debug-impl>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
|
||||
<!--
|
||||
pre NB7.2 profiling section; consider it deprecated
|
||||
-->
|
||||
<target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
|
||||
<target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target name="-profile-post-init">
|
||||
<target if="profiler.info.jvmargs.agent" name="-profile-post-init">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target name="-profile-init-macrodef-profile">
|
||||
<target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
|
||||
<macrodef name="resolve">
|
||||
<attribute name="name"/>
|
||||
<attribute name="value"/>
|
||||
|
@ -384,6 +694,7 @@ is divided into following sections:
|
|||
<property environment="env"/>
|
||||
<resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
|
||||
<java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
|
||||
<jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
|
||||
<jvmarg value="${profiler.info.jvmargs.agent}"/>
|
||||
<jvmarg line="${profiler.info.jvmargs}"/>
|
||||
<env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
|
||||
|
@ -400,10 +711,13 @@ is divided into following sections:
|
|||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" name="-profile-init-check">
|
||||
<target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
|
||||
<fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
|
||||
<fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
|
||||
</target>
|
||||
<!--
|
||||
end of pre NB7.2 profiling section
|
||||
-->
|
||||
<target depends="-init-debug-args" name="-init-macrodef-nbjpda">
|
||||
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<attribute default="${main.class}" name="name"/>
|
||||
|
@ -461,6 +775,7 @@ is divided into following sections:
|
|||
<jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
|
||||
<redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
<jvmarg line="${run.jvmargs.ide}"/>
|
||||
<classpath>
|
||||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
|
@ -477,6 +792,7 @@ is divided into following sections:
|
|||
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<attribute default="${main.class}" name="classname"/>
|
||||
<attribute default="${run.classpath}" name="classpath"/>
|
||||
<attribute default="jvm" name="jvm"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<java classname="@{classname}" dir="${work.dir}" fork="true">
|
||||
|
@ -484,6 +800,7 @@ is divided into following sections:
|
|||
<jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
|
||||
<redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
<jvmarg line="${run.jvmargs.ide}"/>
|
||||
<classpath>
|
||||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
|
@ -510,12 +827,15 @@ is divided into following sections:
|
|||
<path path="${run.classpath.without.build.classes.dir}"/>
|
||||
<chainedmapper>
|
||||
<flattenmapper/>
|
||||
<filtermapper>
|
||||
<replacestring from=" " to="%20"/>
|
||||
</filtermapper>
|
||||
<globmapper from="*" to="lib/*"/>
|
||||
</chainedmapper>
|
||||
</pathconvert>
|
||||
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
|
||||
<copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
<copylibs compress="${jar.compress}" excludeFromCopy="${copylibs.excludes}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
|
||||
<fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
|
||||
<manifest>
|
||||
<attribute name="Class-Path" value="${jar.classpath}"/>
|
||||
<customize/>
|
||||
|
@ -527,7 +847,7 @@ is divided into following sections:
|
|||
<target name="-init-presetdef-jar">
|
||||
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
|
||||
<j2seproject1:fileset dir="${build.classes.dir}"/>
|
||||
<j2seproject1:fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
|
||||
</jar>
|
||||
</presetdef>
|
||||
</target>
|
||||
|
@ -555,7 +875,7 @@ is divided into following sections:
|
|||
<target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
|
||||
<property name="ap.cmd.line.internal" value=""/>
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
|
||||
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
|
||||
<!--
|
||||
===================
|
||||
COMPILATION SECTION
|
||||
|
@ -608,7 +928,7 @@ is divided into following sections:
|
|||
<target if="has.persistence.xml" name="-copy-persistence-xml">
|
||||
<mkdir dir="${build.classes.dir}/META-INF"/>
|
||||
<copy todir="${build.classes.dir}/META-INF">
|
||||
<fileset dir="${meta.inf.dir}" includes="persistence.xml"/>
|
||||
<fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
|
||||
</copy>
|
||||
</target>
|
||||
<target name="-post-compile">
|
||||
|
@ -643,41 +963,25 @@ is divided into following sections:
|
|||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available-mkdist.available">
|
||||
<j2seproject1:jar/>
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class-mkdist.available">
|
||||
<j2seproject1:jar manifest="${manifest.file}"/>
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
|
||||
<j2seproject1:jar manifest="${manifest.file}">
|
||||
<j2seproject1:manifest>
|
||||
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
|
||||
</j2seproject1:manifest>
|
||||
</j2seproject1:jar>
|
||||
<echo level="info">To run this application from the command line without Ant, try:</echo>
|
||||
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
|
||||
<property location="${dist.jar}" name="dist.jar.resolved"/>
|
||||
<pathconvert property="run.classpath.with.dist.jar">
|
||||
<path path="${run.classpath}"/>
|
||||
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
|
||||
</pathconvert>
|
||||
<echo level="info">java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
|
||||
</target>
|
||||
<target depends="init" if="do.archive" name="-do-jar-with-libraries-create-manifest" unless="manifest.available">
|
||||
<target depends="init" if="do.archive" name="-do-jar-create-manifest" unless="manifest.available">
|
||||
<tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
|
||||
<touch file="${tmp.manifest.file}" verbose="false"/>
|
||||
</target>
|
||||
<target depends="init" if="do.archive+manifest.available" name="-do-jar-with-libraries-copy-manifest">
|
||||
<target depends="init" if="do.archive+manifest.available" name="-do-jar-copy-manifest">
|
||||
<tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
|
||||
<copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
|
||||
</target>
|
||||
<target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+main.class.available" name="-do-jar-with-libraries-set-main">
|
||||
<target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+main.class.available" name="-do-jar-set-mainclass">
|
||||
<manifest file="${tmp.manifest.file}" mode="update">
|
||||
<attribute name="Main-Class" value="${main.class}"/>
|
||||
</manifest>
|
||||
</target>
|
||||
<target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-with-libraries-set-splashscreen">
|
||||
<target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+profile.available" name="-do-jar-set-profile">
|
||||
<manifest file="${tmp.manifest.file}" mode="update">
|
||||
<attribute name="Profile" value="${javac.profile}"/>
|
||||
</manifest>
|
||||
</target>
|
||||
<target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-set-splashscreen">
|
||||
<basename file="${application.splash}" property="splashscreen.basename"/>
|
||||
<mkdir dir="${build.classes.dir}/META-INF"/>
|
||||
<copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
|
||||
|
@ -685,23 +989,41 @@ is divided into following sections:
|
|||
<attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
|
||||
</manifest>
|
||||
</target>
|
||||
<target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen" if="do.mkdist" name="-do-jar-with-libraries-pack">
|
||||
<target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.mkdist" name="-do-jar-copylibs">
|
||||
<j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
|
||||
<echo level="info">To run this application from the command line without Ant, try:</echo>
|
||||
<property location="${dist.jar}" name="dist.jar.resolved"/>
|
||||
<echo level="info">java -jar "${dist.jar.resolved}"</echo>
|
||||
</target>
|
||||
<target depends="-do-jar-with-libraries-pack" if="do.archive" name="-do-jar-with-libraries-delete-manifest">
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.archive" name="-do-jar-jar" unless="do.mkdist">
|
||||
<j2seproject1:jar manifest="${tmp.manifest.file}"/>
|
||||
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
|
||||
<property location="${dist.jar}" name="dist.jar.resolved"/>
|
||||
<pathconvert property="run.classpath.with.dist.jar">
|
||||
<path path="${run.classpath}"/>
|
||||
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
|
||||
</pathconvert>
|
||||
<condition else="" property="jar.usage.message" value="To run this application from the command line without Ant, try:${line.separator}${platform.java} -cp ${run.classpath.with.dist.jar} ${main.class}">
|
||||
<isset property="main.class.available"/>
|
||||
</condition>
|
||||
<condition else="debug" property="jar.usage.level" value="info">
|
||||
<isset property="main.class.available"/>
|
||||
</condition>
|
||||
<echo level="${jar.usage.level}" message="${jar.usage.message}"/>
|
||||
</target>
|
||||
<target depends="-do-jar-copylibs" if="do.archive" name="-do-jar-delete-manifest">
|
||||
<delete>
|
||||
<fileset file="${tmp.manifest.file}"/>
|
||||
</delete>
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen,-do-jar-with-libraries-pack,-do-jar-with-libraries-delete-manifest" name="-do-jar-with-libraries"/>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-jar,-do-jar-delete-manifest" name="-do-jar-without-libraries"/>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-copylibs,-do-jar-delete-manifest" name="-do-jar-with-libraries"/>
|
||||
<target name="-post-jar">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
|
||||
<target depends="init,compile,-pre-jar,-do-jar-without-libraries,-do-jar-with-libraries,-post-jar" name="-do-jar"/>
|
||||
<target depends="init,compile,-pre-jar,-do-jar,-post-jar" description="Build JAR." name="jar"/>
|
||||
<!--
|
||||
=================
|
||||
EXECUTION SECTION
|
||||
|
@ -771,7 +1093,11 @@ is divided into following sections:
|
|||
PROFILING SECTION
|
||||
=================
|
||||
-->
|
||||
<target depends="profile-init,compile" description="Profile a project in the IDE." if="netbeans.home" name="profile">
|
||||
<!--
|
||||
pre NB7.2 profiler integration
|
||||
-->
|
||||
<target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
|
||||
<fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
|
||||
<nbprofiledirect>
|
||||
<classpath>
|
||||
<path path="${run.classpath}"/>
|
||||
|
@ -779,8 +1105,9 @@ is divided into following sections:
|
|||
</nbprofiledirect>
|
||||
<profile/>
|
||||
</target>
|
||||
<target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="netbeans.home" name="profile-single">
|
||||
<target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
|
||||
<fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
|
||||
<fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
|
||||
<nbprofiledirect>
|
||||
<classpath>
|
||||
<path path="${run.classpath}"/>
|
||||
|
@ -788,12 +1115,8 @@ is divided into following sections:
|
|||
</nbprofiledirect>
|
||||
<profile classname="${profile.class}"/>
|
||||
</target>
|
||||
<!--
|
||||
=========================
|
||||
APPLET PROFILING SECTION
|
||||
=========================
|
||||
-->
|
||||
<target depends="profile-init,compile-single" if="netbeans.home" name="profile-applet">
|
||||
<target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
|
||||
<fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
|
||||
<nbprofiledirect>
|
||||
<classpath>
|
||||
<path path="${run.classpath}"/>
|
||||
|
@ -805,12 +1128,8 @@ is divided into following sections:
|
|||
</customize>
|
||||
</profile>
|
||||
</target>
|
||||
<!--
|
||||
=========================
|
||||
TESTS PROFILING SECTION
|
||||
=========================
|
||||
-->
|
||||
<target depends="profile-init,compile-test-single" if="netbeans.home" name="profile-test-single">
|
||||
<target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
|
||||
<fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
|
||||
<nbprofiledirect>
|
||||
<classpath>
|
||||
<path path="${run.test.classpath}"/>
|
||||
|
@ -832,6 +1151,42 @@ is divided into following sections:
|
|||
<formatter type="xml"/>
|
||||
</junit>
|
||||
</target>
|
||||
<!--
|
||||
end of pre NB72 profiling section
|
||||
-->
|
||||
<target if="netbeans.home" name="-profile-check">
|
||||
<condition property="profiler.configured">
|
||||
<or>
|
||||
<contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
|
||||
<contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
|
||||
</or>
|
||||
</condition>
|
||||
</target>
|
||||
<target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
|
||||
<startprofiler/>
|
||||
<antcall target="run"/>
|
||||
</target>
|
||||
<target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
|
||||
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
|
||||
<startprofiler/>
|
||||
<antcall target="run-single"/>
|
||||
</target>
|
||||
<target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
|
||||
<target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
|
||||
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
|
||||
<startprofiler/>
|
||||
<antcall target="test-single"/>
|
||||
</target>
|
||||
<target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
|
||||
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
|
||||
<startprofiler/>
|
||||
<antcal target="run-test-with-main"/>
|
||||
</target>
|
||||
<target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
|
||||
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
|
||||
<startprofiler/>
|
||||
<antcall target="run-applet"/>
|
||||
</target>
|
||||
<!--
|
||||
===============
|
||||
JAVADOC SECTION
|
||||
|
@ -839,17 +1194,29 @@ is divided into following sections:
|
|||
-->
|
||||
<target depends="init" if="have.sources" name="-javadoc-build">
|
||||
<mkdir dir="${dist.javadoc.dir}"/>
|
||||
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
|
||||
<condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
|
||||
<and>
|
||||
<isset property="endorsed.classpath.cmd.line.arg"/>
|
||||
<not>
|
||||
<equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<condition else="" property="bug5101868workaround" value="*.java">
|
||||
<matches pattern="1\.[56](\..*)?" string="${java.version}"/>
|
||||
</condition>
|
||||
<javadoc additionalparam="-J-Dfile.encoding=${file.encoding} ${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
|
||||
<classpath>
|
||||
<path path="${javac.classpath}"/>
|
||||
</classpath>
|
||||
<fileset dir="${src.dir}" excludes="*.java,${excludes}" includes="${includes}">
|
||||
<fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
|
||||
<filename name="**/*.java"/>
|
||||
</fileset>
|
||||
<fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
|
||||
<include name="**/*.java"/>
|
||||
<exclude name="*.java"/>
|
||||
</fileset>
|
||||
<arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
|
||||
</javadoc>
|
||||
<copy todir="${dist.javadoc.dir}">
|
||||
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
|
||||
|
@ -866,7 +1233,7 @@ is divided into following sections:
|
|||
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
|
||||
<!--
|
||||
=========================
|
||||
JUNIT COMPILATION SECTION
|
||||
TEST COMPILATION SECTION
|
||||
=========================
|
||||
-->
|
||||
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
|
||||
|
@ -909,14 +1276,14 @@ is divided into following sections:
|
|||
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
|
||||
<!--
|
||||
=======================
|
||||
JUNIT EXECUTION SECTION
|
||||
TEST EXECUTION SECTION
|
||||
=======================
|
||||
-->
|
||||
<target depends="init" if="have.tests" name="-pre-test-run">
|
||||
<mkdir dir="${build.test.results.dir}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
|
||||
<j2seproject3:junit testincludes="**/*Test.java"/>
|
||||
<j2seproject3:test includes="${includes}" testincludes="**/*Test.java"/>
|
||||
</target>
|
||||
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
|
||||
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
|
||||
|
@ -929,39 +1296,40 @@ is divided into following sections:
|
|||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
|
||||
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
|
||||
<j2seproject3:junit excludes="" includes="${test.includes}"/>
|
||||
<j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
|
||||
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
|
||||
<fail unless="test.class">Must select some files in the IDE or set test.class</fail>
|
||||
<fail unless="test.method">Must select some method in the IDE or set test.method</fail>
|
||||
<j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
|
||||
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
|
||||
<!--
|
||||
=======================
|
||||
JUNIT DEBUGGING SECTION
|
||||
TEST DEBUGGING SECTION
|
||||
=======================
|
||||
-->
|
||||
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
|
||||
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
|
||||
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
|
||||
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
|
||||
<delete file="${test.report.file}"/>
|
||||
<mkdir dir="${build.test.results.dir}"/>
|
||||
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
|
||||
<customize>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<arg value="${test.class}"/>
|
||||
<arg value="showoutput=true"/>
|
||||
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
|
||||
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
|
||||
</customize>
|
||||
</j2seproject3:debug>
|
||||
<j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
|
||||
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
|
||||
<fail unless="test.method">Must select some method in the IDE or set test.method</fail>
|
||||
<j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
|
||||
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
|
||||
<target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
|
||||
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
|
||||
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
|
||||
</target>
|
||||
|
@ -1026,9 +1394,12 @@ is divided into following sections:
|
|||
<target name="-check-call-dep">
|
||||
<property file="${call.built.properties}" prefix="already.built."/>
|
||||
<condition property="should.call.dep">
|
||||
<not>
|
||||
<isset property="already.built.${call.subproject}"/>
|
||||
</not>
|
||||
<and>
|
||||
<not>
|
||||
<isset property="already.built.${call.subproject}"/>
|
||||
</not>
|
||||
<available file="${call.script}"/>
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
<target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
build.xml.data.CRC32=23b52058
|
||||
build.xml.script.CRC32=b64bcd8b
|
||||
build.xml.stylesheet.CRC32=28e38971@1.38.2.45
|
||||
build.xml.data.CRC32=bfb77442
|
||||
build.xml.script.CRC32=b3725edf
|
||||
build.xml.stylesheet.CRC32=8064a381@1.75.2.48
|
||||
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
||||
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
||||
nbproject/build-impl.xml.data.CRC32=23b52058
|
||||
nbproject/build-impl.xml.script.CRC32=9ea63390
|
||||
nbproject/build-impl.xml.stylesheet.CRC32=0ae3a408@1.44.1.45
|
||||
nbproject/build-impl.xml.data.CRC32=bfb77442
|
||||
nbproject/build-impl.xml.script.CRC32=7aa67ee7
|
||||
nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
annotation.processing.enabled=true
|
||||
annotation.processing.enabled.in.editor=false
|
||||
annotation.processing.processors.list=
|
||||
annotation.processing.run.all.processors=true
|
||||
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
|
||||
application.homepage=https://github.com/SammyIAm/Moppy
|
||||
application.title=MoppyDesk
|
||||
application.vendor=Sam
|
||||
application.vendor=Sammy1Am
|
||||
auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.classes.excludes=**/*.java,**/*.form
|
||||
# This directory is removed when the project is cleaned:
|
||||
|
@ -26,19 +29,20 @@ dist.jar=${dist.dir}/MoppyDesk.jar
|
|||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
file.reference.RXTXcomm.jar=lib\\RXTXcomm.jar
|
||||
file.reference.nrjavaserial-3.9.3.jar=..\\SerialDrivers\\nrjavaserial-3.9.3.jar
|
||||
includes=**
|
||||
jar.archive.disabled=${jnlp.enabled}
|
||||
jar.compress=false
|
||||
jar.index=${jnlp.enabled}
|
||||
javac.classpath=\
|
||||
${file.reference.RXTXcomm.jar}:\
|
||||
${libs.swing-app-framework.classpath}
|
||||
${file.reference.nrjavaserial-3.9.3.jar}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
javac.processorpath=\
|
||||
${javac.classpath}
|
||||
javac.source=1.5
|
||||
javac.target=1.5
|
||||
javac.source=1.7
|
||||
javac.target=1.7
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
|
@ -55,7 +59,20 @@ javadoc.splitindex=true
|
|||
javadoc.use=true
|
||||
javadoc.version=false
|
||||
javadoc.windowtitle=
|
||||
jnlp.codebase.type=no.codebase
|
||||
jnlp.descriptor=application
|
||||
jnlp.enabled=false
|
||||
jnlp.mixed.code=default
|
||||
jnlp.offline-allowed=false
|
||||
jnlp.signed=false
|
||||
jnlp.signing=
|
||||
jnlp.signing.alias=
|
||||
jnlp.signing.keystore=
|
||||
main.class=moppydesk.MoppyUI
|
||||
# Optional override of default Codebase manifest attribute, use to prevent RIAs from being repurposed
|
||||
manifest.custom.codebase=
|
||||
# Optional override of default Permissions manifest attribute (supported values: sandbox, all-permissions)
|
||||
manifest.custom.permissions=
|
||||
manifest.file=manifest.mf
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
mkdist.disabled=false
|
||||
|
@ -63,10 +80,6 @@ platform.active=default_platform
|
|||
run.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
# Space-separated list of JVM arguments used when running the project
|
||||
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
|
||||
# or test-sys-prop.name=value to set system properties for unit tests):
|
||||
run.jvmargs=-Djava.library.path="../SerialDrivers/rxtx-2.1-7-bins-r2/Windows/ch-rxtx-2.2-20081207-win-x64;${env_var:PATH}"
|
||||
run.test.classpath=\
|
||||
${javac.test.classpath}:\
|
||||
${build.test.classes.dir}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.java.j2seproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>MoppyDesk</name>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.java.j2seproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>MoppyDesk</name>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
<spellchecker-wordlist xmlns="http://www.netbeans.org/ns/spellchecker-wordlist/1">
|
||||
<word>Arduino</word>
|
||||
</spellchecker-wordlist>
|
||||
</configuration>
|
||||
</project>
|
||||
|
|
33
Java/MoppyDesk/src/moppydesk/Constants.java
Normal file
33
Java/MoppyDesk/src/moppydesk/Constants.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package moppydesk;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class Constants {
|
||||
//Sequencer preferences
|
||||
public static final String PREF_LOADED_SEQ = "loadedSequencePath";
|
||||
public static final String PREF_DELAY_RESET = "delayResetValue";
|
||||
public static final String PREF_RESET_DRIVES = "resetDrivesValue";
|
||||
public static final String PREF_REPEAT_SEQ = "repeatSequenceValue";
|
||||
public static final String PREF_OUTPUT_SETTINGS = "outputSettingsArray";
|
||||
|
||||
//Playlist preferences
|
||||
public static final String PREF_LOADED_LIST = "loadedPlaylistPath";
|
||||
public static final String PREF_LOADED_MPL = "lastLoadedPlaylistFile";
|
||||
public static final String PREF_LOAD_MPL_ON_START = "loadMPLValue";
|
||||
|
||||
//Pooling preferences
|
||||
public static final String PREF_POOL_ENABLE = "poolingEnabled";
|
||||
public static final String PREF_POOL_FROM_START = "poolingFromStart";
|
||||
public static final String PREF_POOL_FROM_END = "poolingFromEnd";
|
||||
public static final String PREF_POOL_TO_START = "poolingToStart";
|
||||
public static final String PREF_POOL_TO_END = "poolingToEnd";
|
||||
public static final String PREF_POOL_STRATEGY = "poolingStrategy";
|
||||
|
||||
//Filter preferences
|
||||
public static final String PREF_FILTER_CONSTRAIN = "filterAutoConstrain";
|
||||
public static final String PREF_FILTER_IGNORETEN = "ignore10";
|
||||
|
||||
public static final int NUM_MIDI_CHANNELS = 16;
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
package moppydesk;
|
||||
|
||||
import gnu.io.CommPortIdentifier;
|
||||
import gnu.io.NoSuchPortException;
|
||||
import gnu.io.PortInUseException;
|
||||
import gnu.io.SerialPort;
|
||||
import gnu.io.UnsupportedCommOperationException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class MoppyBridge {
|
||||
|
||||
static int FIRST_PIN = 2;
|
||||
static int MAX_PIN = 17;
|
||||
|
||||
int SERIAL_RATE = 9600;
|
||||
OutputStream os;
|
||||
SerialPort com;
|
||||
|
||||
public MoppyBridge(String portName) throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException, IOException {
|
||||
CommPortIdentifier cpi = CommPortIdentifier.getPortIdentifier(portName);
|
||||
com = (SerialPort) cpi.open("MoppyDesk", 2000);
|
||||
com.setSerialPortParams(SERIAL_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
|
||||
os = com.getOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that splits the periodData int
|
||||
* into two bytes for sending over serial.
|
||||
* @param pin Controller pin to handle ntoe
|
||||
* @param periodData length of period in microSeconds
|
||||
*/
|
||||
public void sendEvent(byte pin, int periodData){
|
||||
sendEvent(pin, (byte)((periodData >> 8) & 0xFF), (byte)(periodData & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an event to the Arduino.
|
||||
* @param pin Controller pin
|
||||
* @param b1
|
||||
* @param b2
|
||||
*/
|
||||
public void sendEvent(byte pin, byte b1, byte b2){
|
||||
sendArray(new byte[] {pin, b1, b2});
|
||||
}
|
||||
|
||||
private void sendArray(byte[] message){
|
||||
try {
|
||||
os.write(message);
|
||||
os.flush();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyBridge.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a '0' period to all drives to silence them.
|
||||
*/
|
||||
private void silenceDrives(){
|
||||
// Stop notes
|
||||
for (int d=FIRST_PIN;d<=MAX_PIN;d+=2){
|
||||
sendArray(new byte[] {(byte)d,(byte)0,(byte)0});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a special code (first byte=100) to reset the drives
|
||||
*/
|
||||
public void resetDrives(){
|
||||
silenceDrives();
|
||||
//Send reset code
|
||||
sendArray(new byte[] {(byte)100,(byte)0,(byte)0});
|
||||
try {
|
||||
Thread.sleep(1500); // Give the drives time to reset
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(MoppyBridge.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void close(){
|
||||
if (os != null){
|
||||
silenceDrives();
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyBridge.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (com != null){
|
||||
com.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,470 +0,0 @@
|
|||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MoppyMainWindow.java
|
||||
*
|
||||
* Created on Oct 8, 2011, 8:34:57 PM
|
||||
*/
|
||||
package moppydesk;
|
||||
|
||||
import gnu.io.CommPortIdentifier;
|
||||
import java.awt.Component;
|
||||
import java.io.File;
|
||||
import java.util.Enumeration;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.prefs.Preferences;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSlider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam
|
||||
*/
|
||||
public class MoppyMainWindow extends javax.swing.JFrame implements MoppyStatusConsumer {
|
||||
|
||||
static String PREF_COM_PORT = "comPort";
|
||||
static String PREF_LOADED_SEQ = "loadedSequencePath";
|
||||
MoppyUI app;
|
||||
Preferences prefs = Preferences.userNodeForPackage(MoppyUI.class);
|
||||
final JFileChooser sequenceChooser = new JFileChooser();
|
||||
boolean comboBoxReady = false;
|
||||
|
||||
/** Creates new form MoppyMainWindow */
|
||||
public MoppyMainWindow(MoppyUI app) {
|
||||
this.app = app;
|
||||
initComponents();
|
||||
|
||||
updateComSelectionMenu();
|
||||
|
||||
statusLabel.setText("Ready");
|
||||
|
||||
// initializeSequencer((String) comSelectionMenu.getSelectedItem());
|
||||
//
|
||||
//
|
||||
}
|
||||
|
||||
private void updateComSelectionMenu() {
|
||||
comboBoxReady = false;
|
||||
comSelectionMenu.removeAllItems();
|
||||
Enumeration<CommPortIdentifier> e = CommPortIdentifier.getPortIdentifiers();
|
||||
while (e.hasMoreElements()) {
|
||||
comSelectionMenu.addItem(e.nextElement().getName());
|
||||
}
|
||||
comSelectionMenu.setSelectedItem(prefs.get(PREF_COM_PORT, ""));
|
||||
comboBoxReady = true;
|
||||
}
|
||||
|
||||
private void initializeSequencer(String comPort) {
|
||||
statusLabel.setText("Initializing sequencer...");
|
||||
if (app.ms != null) {
|
||||
app.ms.closeSequencer();
|
||||
}
|
||||
try {
|
||||
app.ms = new MoppySequencer(comPort);
|
||||
app.ms.addListener(this);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MoppyMainWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
statusLabel.setText("Sequencer initialization error!");
|
||||
JOptionPane.showMessageDialog(rootPane, ex);
|
||||
}
|
||||
statusLabel.setText("Sequencer connected to " + comPort);
|
||||
|
||||
String previouslyLoadedFile = prefs.get(PREF_LOADED_SEQ, null);
|
||||
if (previouslyLoadedFile != null) {
|
||||
loadSequenceFile(new File(previouslyLoadedFile));
|
||||
}
|
||||
|
||||
setSequenceControlsEnabled(true);
|
||||
connectSeqButton.setText("Disconnect");
|
||||
}
|
||||
|
||||
private void shutdownSequencer() {
|
||||
statusLabel.setText("Closing sequencer...");
|
||||
if (app.ms != null) {
|
||||
app.ms.closeSequencer();
|
||||
app.ms = null;
|
||||
}
|
||||
setSequenceControlsEnabled(false);
|
||||
connectSeqButton.setText("Connect");
|
||||
statusLabel.setText("Sequencer closed");
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
comSelectionMenu = new javax.swing.JComboBox();
|
||||
statusLabel = new javax.swing.JLabel();
|
||||
jSeparator1 = new javax.swing.JSeparator();
|
||||
jTabbedPane1 = new javax.swing.JTabbedPane();
|
||||
jPanel1 = new javax.swing.JPanel();
|
||||
sequencerControlsPanel = new javax.swing.JPanel();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
sequenceNameLabel = new javax.swing.JLabel();
|
||||
startButton = new javax.swing.JButton();
|
||||
stopButton = new javax.swing.JButton();
|
||||
loadButton = new javax.swing.JButton();
|
||||
jSlider1 = new javax.swing.JSlider();
|
||||
bpmLabel = new javax.swing.JLabel();
|
||||
jSeparator2 = new javax.swing.JSeparator();
|
||||
connectSeqButton = new javax.swing.JButton();
|
||||
jPanel2 = new javax.swing.JPanel();
|
||||
jLabel2 = new javax.swing.JLabel();
|
||||
jLabel3 = new javax.swing.JLabel();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
||||
setTitle("MoppyDesk");
|
||||
setMinimumSize(new java.awt.Dimension(480, 410));
|
||||
addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
public void windowClosing(java.awt.event.WindowEvent evt) {
|
||||
MoppyMainWindow.this.windowClosing(evt);
|
||||
}
|
||||
});
|
||||
|
||||
comSelectionMenu.setName("comSelectionMenu"); // NOI18N
|
||||
comSelectionMenu.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
comPortSelected(evt);
|
||||
}
|
||||
});
|
||||
|
||||
statusLabel.setText("Loading application...");
|
||||
statusLabel.setName("statusLabel"); // NOI18N
|
||||
|
||||
jSeparator1.setName("jSeparator1"); // NOI18N
|
||||
|
||||
jTabbedPane1.setName("bridgePanel"); // NOI18N
|
||||
|
||||
jPanel1.setName("sequencerPanel"); // NOI18N
|
||||
jPanel1.addComponentListener(new java.awt.event.ComponentAdapter() {
|
||||
public void componentHidden(java.awt.event.ComponentEvent evt) {
|
||||
seqTabHidden(evt);
|
||||
}
|
||||
});
|
||||
|
||||
sequencerControlsPanel.setName("sequencerControlsPanel"); // NOI18N
|
||||
sequencerControlsPanel.setPreferredSize(new java.awt.Dimension(200, 200));
|
||||
|
||||
jLabel1.setText("Current Sequence:");
|
||||
jLabel1.setEnabled(false);
|
||||
jLabel1.setName("jLabel1"); // NOI18N
|
||||
|
||||
sequenceNameLabel.setText("<None loaded>");
|
||||
sequenceNameLabel.setEnabled(false);
|
||||
sequenceNameLabel.setName("sequenceNameLabel"); // NOI18N
|
||||
|
||||
startButton.setText("Start");
|
||||
startButton.setEnabled(false);
|
||||
startButton.setName("startButton"); // NOI18N
|
||||
startButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
startButtonClicked(evt);
|
||||
}
|
||||
});
|
||||
|
||||
stopButton.setText("Stop/Reset");
|
||||
stopButton.setEnabled(false);
|
||||
stopButton.setName("stopButton"); // NOI18N
|
||||
stopButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
stopResetClicked(evt);
|
||||
}
|
||||
});
|
||||
|
||||
loadButton.setText("Load Sequence");
|
||||
loadButton.setEnabled(false);
|
||||
loadButton.setName("loadButton"); // NOI18N
|
||||
loadButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
loadSequence(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jSlider1.setMajorTickSpacing(10);
|
||||
jSlider1.setMaximum(210);
|
||||
jSlider1.setMinimum(20);
|
||||
jSlider1.setPaintTicks(true);
|
||||
jSlider1.setValue(120);
|
||||
jSlider1.setEnabled(false);
|
||||
jSlider1.setName("jSlider1"); // NOI18N
|
||||
jSlider1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
|
||||
public void mouseDragged(java.awt.event.MouseEvent evt) {
|
||||
tempoSliderChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
bpmLabel.setText(jSlider1.getValue() + " bpm");
|
||||
bpmLabel.setEnabled(false);
|
||||
bpmLabel.setName("bpmLabel"); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout sequencerControlsPanelLayout = new javax.swing.GroupLayout(sequencerControlsPanel);
|
||||
sequencerControlsPanel.setLayout(sequencerControlsPanelLayout);
|
||||
sequencerControlsPanelLayout.setHorizontalGroup(
|
||||
sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addGroup(sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addGroup(sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(sequenceNameLabel)
|
||||
.addComponent(jLabel1))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 220, Short.MAX_VALUE)
|
||||
.addComponent(loadButton))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 66, Short.MAX_VALUE)
|
||||
.addComponent(startButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(stopButton))))
|
||||
.addGroup(sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addGap(136, 136, 136)
|
||||
.addComponent(bpmLabel)))
|
||||
.addContainerGap())
|
||||
);
|
||||
sequencerControlsPanelLayout.setVerticalGroup(
|
||||
sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addGroup(sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(sequenceNameLabel))
|
||||
.addComponent(loadButton))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 100, Short.MAX_VALUE)
|
||||
.addGroup(sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(sequencerControlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(stopButton)
|
||||
.addComponent(startButton))
|
||||
.addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap())
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, sequencerControlsPanelLayout.createSequentialGroup()
|
||||
.addComponent(bpmLabel)
|
||||
.addGap(54, 54, 54))))
|
||||
);
|
||||
|
||||
bpmLabel.getAccessibleContext().setAccessibleName(jSlider1.getValue() + " bpm");
|
||||
|
||||
jSeparator2.setName("jSeparator2"); // NOI18N
|
||||
|
||||
connectSeqButton.setText("Connect");
|
||||
connectSeqButton.setToolTipText("Attempts to open selected COM port.");
|
||||
connectSeqButton.setName("connectSequencerButton"); // NOI18N
|
||||
connectSeqButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
connectSequencerPressed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||
jPanel1.setLayout(jPanel1Layout);
|
||||
jPanel1Layout.setHorizontalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(sequencerControlsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 436, Short.MAX_VALUE)
|
||||
.addContainerGap())
|
||||
.addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 456, Short.MAX_VALUE)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(connectSeqButton)
|
||||
.addContainerGap(373, Short.MAX_VALUE))
|
||||
);
|
||||
jPanel1Layout.setVerticalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(connectSeqButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(sequencerControlsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 187, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
jTabbedPane1.addTab("Sequencer", jPanel1);
|
||||
|
||||
jPanel2.setName("jPanel2"); // NOI18N
|
||||
|
||||
jLabel2.setText("Coming soon... (sorry!)");
|
||||
jLabel2.setName("jLabel2"); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
|
||||
jPanel2.setLayout(jPanel2Layout);
|
||||
jPanel2Layout.setHorizontalGroup(
|
||||
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel2Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jLabel2)
|
||||
.addContainerGap(333, Short.MAX_VALUE))
|
||||
);
|
||||
jPanel2Layout.setVerticalGroup(
|
||||
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel2Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jLabel2)
|
||||
.addContainerGap(229, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
jTabbedPane1.addTab("Bridge", jPanel2);
|
||||
|
||||
jLabel3.setText("Arduino Port:");
|
||||
jLabel3.setName("jLabel3"); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jTabbedPane1)
|
||||
.addComponent(statusLabel)
|
||||
.addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 461, Short.MAX_VALUE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jLabel3)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(comSelectionMenu, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(comSelectionMenu, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabel3))
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(jTabbedPane1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 8, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(statusLabel)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
jTabbedPane1.getAccessibleContext().setAccessibleName("Bridge"); // NOI18N
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void stopResetClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopResetClicked
|
||||
statusLabel.setText("Stopping...");
|
||||
app.ms.stopSequencer();
|
||||
startButton.setEnabled(true);
|
||||
statusLabel.setText("Stopped");
|
||||
}//GEN-LAST:event_stopResetClicked
|
||||
|
||||
private void startButtonClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonClicked
|
||||
startButton.setEnabled(false);
|
||||
app.ms.startSequencer();
|
||||
}//GEN-LAST:event_startButtonClicked
|
||||
|
||||
private void loadSequence(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadSequence
|
||||
String previouslyLoaded = prefs.get(PREF_LOADED_SEQ, null);
|
||||
if (previouslyLoaded != null) {
|
||||
sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
|
||||
}
|
||||
int returnVal = sequenceChooser.showOpenDialog(this);
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
loadSequenceFile(sequenceChooser.getSelectedFile());
|
||||
} else {
|
||||
//Cancelled
|
||||
}
|
||||
}//GEN-LAST:event_loadSequence
|
||||
|
||||
private void loadSequenceFile(File sequenceFile) {
|
||||
try {
|
||||
statusLabel.setText("Loading file...");
|
||||
app.ms.loadFile(sequenceFile.getPath());
|
||||
sequenceNameLabel.setText(sequenceFile.getName());
|
||||
prefs.put(PREF_LOADED_SEQ, sequenceFile.getPath());
|
||||
statusLabel.setText("Loaded " + sequenceFile.getName());
|
||||
startButton.setEnabled(true);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MoppyMainWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
statusLabel.setText("File loading error!");
|
||||
JOptionPane.showMessageDialog(rootPane, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void tempoSliderChanged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tempoSliderChanged
|
||||
JSlider s = (JSlider) evt.getSource();
|
||||
app.ms.setTempo(s.getValue());
|
||||
bpmLabel.setText(s.getValue() + " bpm");
|
||||
}//GEN-LAST:event_tempoSliderChanged
|
||||
|
||||
private void comPortSelected(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comPortSelected
|
||||
JComboBox cb = (JComboBox) evt.getSource();
|
||||
if (comboBoxReady) {
|
||||
String comPort = (String) cb.getSelectedItem();
|
||||
shutdownSequencer();
|
||||
prefs.put(PREF_COM_PORT, comPort);
|
||||
}
|
||||
}//GEN-LAST:event_comPortSelected
|
||||
|
||||
private void windowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_windowClosing
|
||||
if (app.ms != null){
|
||||
app.ms.closeSequencer();
|
||||
}
|
||||
}//GEN-LAST:event_windowClosing
|
||||
|
||||
private void connectSequencerPressed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectSequencerPressed
|
||||
if (connectSeqButton.getText().equals("Connect")) {
|
||||
initializeSequencer((String) comSelectionMenu.getSelectedItem());
|
||||
} else {
|
||||
shutdownSequencer();
|
||||
}
|
||||
}//GEN-LAST:event_connectSequencerPressed
|
||||
|
||||
private void seqTabHidden(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_seqTabHidden
|
||||
shutdownSequencer();
|
||||
}//GEN-LAST:event_seqTabHidden
|
||||
|
||||
private void setSequenceControlsEnabled(boolean enabled) {
|
||||
for (Component c : sequencerControlsPanel.getComponents()) {
|
||||
c.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
public void tempoChanged(int newTempo) {
|
||||
jSlider1.setValue(newTempo);
|
||||
bpmLabel.setText(newTempo + " bpm");
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel bpmLabel;
|
||||
private javax.swing.JComboBox comSelectionMenu;
|
||||
private javax.swing.JButton connectSeqButton;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
private javax.swing.JLabel jLabel3;
|
||||
private javax.swing.JPanel jPanel1;
|
||||
private javax.swing.JPanel jPanel2;
|
||||
private javax.swing.JSeparator jSeparator1;
|
||||
private javax.swing.JSeparator jSeparator2;
|
||||
private javax.swing.JSlider jSlider1;
|
||||
private javax.swing.JTabbedPane jTabbedPane1;
|
||||
private javax.swing.JButton loadButton;
|
||||
private javax.swing.JLabel sequenceNameLabel;
|
||||
private javax.swing.JPanel sequencerControlsPanel;
|
||||
private javax.swing.JButton startButton;
|
||||
private javax.swing.JLabel statusLabel;
|
||||
private javax.swing.JButton stopButton;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
|
@ -10,4 +10,5 @@ package moppydesk;
|
|||
*/
|
||||
public interface MoppyStatusConsumer {
|
||||
public void tempoChanged(int newTempo);
|
||||
public void sequenceEnded();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,22 @@
|
|||
*/
|
||||
package moppydesk;
|
||||
|
||||
import moppydesk.inputs.MoppySequencer;
|
||||
import gnu.io.NoSuchPortException;
|
||||
import gnu.io.PortInUseException;
|
||||
import gnu.io.UnsupportedCommOperationException;
|
||||
import java.awt.EventQueue;
|
||||
import java.io.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.prefs.BackingStoreException;
|
||||
import java.util.prefs.Preferences;
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.sound.midi.Receiver;
|
||||
import javax.swing.JOptionPane;
|
||||
import moppydesk.inputs.MoppyMIDIInput;
|
||||
import moppydesk.outputs.ReceiverMarshaller;
|
||||
import moppydesk.ui.MoppyControlWindow;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -11,19 +27,109 @@ package moppydesk;
|
|||
*/
|
||||
public class MoppyUI {
|
||||
|
||||
MoppySequencer ms = null;
|
||||
|
||||
public MoppyUI() {
|
||||
MoppyMainWindow mainWindow = new MoppyMainWindow(this);
|
||||
mainWindow.setVisible(true);
|
||||
//Input objects
|
||||
public MoppySequencer ms;
|
||||
public MoppyMIDIInput midiIn;
|
||||
/**
|
||||
* The {@link ReceiverMarshaller} will be added as a receiver to whatver
|
||||
* input object is selected.
|
||||
*/
|
||||
public ReceiverMarshaller rm = new ReceiverMarshaller();
|
||||
public Preferences prefs = Preferences.userNodeForPackage(MoppyUI.class);
|
||||
|
||||
protected void startup() {
|
||||
//Initialize parts
|
||||
try {
|
||||
ms = new MoppySequencer();
|
||||
midiIn = new MoppyMIDIInput();
|
||||
|
||||
} catch (Exception ex) {
|
||||
JOptionPane.showMessageDialog(null, ex.toString());
|
||||
}
|
||||
MoppyControlWindow mainWindow = new MoppyControlWindow(this);
|
||||
mainWindow.setStatus("Initializing...");
|
||||
mainWindow.setVisible(true);
|
||||
mainWindow.setStatus("Initialized.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Main method launching the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new MoppyUI();
|
||||
|
||||
/* Set the Nimbus look and feel */
|
||||
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
|
||||
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
|
||||
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
|
||||
*/
|
||||
try {
|
||||
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
|
||||
if ("Windows".equals(info.getName())) {
|
||||
javax.swing.UIManager.setLookAndFeel(info.getClassName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
java.util.logging.Logger.getLogger(MoppyUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (InstantiationException ex) {
|
||||
java.util.logging.Logger.getLogger(MoppyUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
java.util.logging.Logger.getLogger(MoppyUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
|
||||
java.util.logging.Logger.getLogger(MoppyUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MoppyUI ui = new MoppyUI();
|
||||
ui.startup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void savePreferences() {
|
||||
try {
|
||||
prefs.flush();
|
||||
} catch (BackingStoreException ex) {
|
||||
Logger.getLogger(MoppyUI.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void putPreferenceObject(String key, Object object) {
|
||||
try {
|
||||
prefs.putByteArray(key, serializePref(object));
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyUI.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getPreferenceObject(String key) {
|
||||
try {
|
||||
return deserializePref(prefs.getByteArray(key, null));
|
||||
} catch (NullPointerException ex) {
|
||||
Logger.getLogger(MoppyUI.class.getName()).log(Level.WARNING, "No preference set for " + key, ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyUI.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
Logger.getLogger(MoppyUI.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//Preference to object
|
||||
private static Object deserializePref(byte[] b) throws NullPointerException, IOException, ClassNotFoundException {
|
||||
return new ObjectInputStream(new ByteArrayInputStream(b)).readObject();
|
||||
}
|
||||
|
||||
//Object to preference
|
||||
private static byte[] serializePref(Object p) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(p);
|
||||
oos.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
25
Java/MoppyDesk/src/moppydesk/OutputSetting.java
Normal file
25
Java/MoppyDesk/src/moppydesk/OutputSetting.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moppydesk;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam
|
||||
*/
|
||||
public class OutputSetting implements Serializable{
|
||||
public enum OutputType {MOPPY, MIDI};
|
||||
|
||||
public final int MIDIChannel;
|
||||
public boolean enabled = false;
|
||||
public OutputType type = OutputType.MOPPY;
|
||||
public String comPort;
|
||||
public String midiDeviceName;
|
||||
|
||||
public OutputSetting(int MIDIChannel){
|
||||
this.MIDIChannel = MIDIChannel;
|
||||
}
|
||||
}
|
74
Java/MoppyDesk/src/moppydesk/inputs/MoppyMIDIInput.java
Normal file
74
Java/MoppyDesk/src/moppydesk/inputs/MoppyMIDIInput.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
package moppydesk.inputs;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.*;
|
||||
import javax.sound.midi.MidiDevice.Info;
|
||||
|
||||
|
||||
public class MoppyMIDIInput implements Transmitter, Receiver{
|
||||
MidiDevice currentDevice = null;
|
||||
Receiver downstreamReceiver = null;
|
||||
|
||||
public void setDevice(Info deviceInfo) throws MidiUnavailableException{
|
||||
if (currentDevice != null){
|
||||
currentDevice.close();
|
||||
}
|
||||
currentDevice = MidiSystem.getMidiDevice(deviceInfo);
|
||||
currentDevice.open();
|
||||
currentDevice.getTransmitter().setReceiver(this);
|
||||
}
|
||||
|
||||
public void setReceiver(Receiver receiver) {
|
||||
downstreamReceiver = receiver;
|
||||
}
|
||||
|
||||
public Receiver getReceiver() {
|
||||
return downstreamReceiver;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (currentDevice != null){
|
||||
currentDevice.close();
|
||||
currentDevice = null;
|
||||
}
|
||||
if (downstreamReceiver != null){
|
||||
downstreamReceiver.close();
|
||||
downstreamReceiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
/// Receiver logic for forwarding messages
|
||||
//
|
||||
|
||||
public void send(MidiMessage message, long timeStamp) {
|
||||
//TODO Edit message based on settings.
|
||||
if (downstreamReceiver != null){
|
||||
downstreamReceiver.send(message, timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//// UTILITY METHODS
|
||||
//
|
||||
|
||||
public static HashMap<String,MidiDevice.Info> getMIDIInInfos(){
|
||||
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
|
||||
HashMap<String,MidiDevice.Info> outInfos = new HashMap<String,MidiDevice.Info>();
|
||||
|
||||
for (MidiDevice.Info i : infos){
|
||||
try {
|
||||
MidiDevice dev = MidiSystem.getMidiDevice(i);
|
||||
if (dev.getMaxTransmitters() != 0){
|
||||
outInfos.put(i.getName(), i);
|
||||
}
|
||||
} catch (MidiUnavailableException ex) {
|
||||
Logger.getLogger(MoppyMIDIInput.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
return outInfos;
|
||||
}
|
||||
}
|
|
@ -1,70 +1,86 @@
|
|||
package moppydesk;
|
||||
package moppydesk.inputs;
|
||||
|
||||
import gnu.io.NoSuchPortException;
|
||||
import gnu.io.PortInUseException;
|
||||
import gnu.io.UnsupportedCommOperationException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.InvalidMidiDataException;
|
||||
import javax.sound.midi.MetaEventListener;
|
||||
import javax.sound.midi.MetaMessage;
|
||||
import javax.sound.midi.MidiMessage;
|
||||
import javax.sound.midi.MidiSystem;
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.sound.midi.Receiver;
|
||||
import javax.sound.midi.Sequence;
|
||||
import javax.sound.midi.Sequencer;
|
||||
import javax.sound.midi.Transmitter;
|
||||
import moppydesk.MoppyStatusConsumer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class MoppySequencer implements MetaEventListener{
|
||||
public class MoppySequencer implements MetaEventListener, Transmitter{
|
||||
|
||||
MoppyBridge mb;
|
||||
MoppyPlayer mp;
|
||||
Sequencer sequencer;
|
||||
Sequence currentSequence = null;
|
||||
Transmitter sequenceTransmitter; // Because we'll be piping all the messages to a common receiver, we'll only need one of these
|
||||
ArrayList<MoppyStatusConsumer> listeners = new ArrayList<MoppyStatusConsumer>(1);
|
||||
|
||||
public MoppySequencer(String comPort) throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException, IOException, MidiUnavailableException {
|
||||
mb = new MoppyBridge(comPort); //Create MoppyBridge on the COM port with the Arduino
|
||||
mp = new MoppyPlayer(mb);
|
||||
|
||||
mb.resetDrives();
|
||||
public MoppySequencer() throws MidiUnavailableException {
|
||||
|
||||
sequencer = MidiSystem.getSequencer(false);
|
||||
sequencer.open();
|
||||
sequencer.getTransmitter().setReceiver(mp); // Set MoppyPlayer as a receiver.
|
||||
sequencer.addMetaEventListener(this);
|
||||
sequenceTransmitter = sequencer.getTransmitter(); // This method creates a new transmitter each time it's called!
|
||||
}
|
||||
|
||||
public void loadFile(String filePath) throws InvalidMidiDataException, IOException, MidiUnavailableException {
|
||||
|
||||
sequencer.stop();
|
||||
Sequence sequence = MidiSystem.getSequence(new File(filePath));
|
||||
|
||||
sequencer.setSequence(sequence);
|
||||
System.out.println("Loaded sequence with "+(sequence.getTracks().length-1)+" MIDI channels.");
|
||||
System.out.println("Loaded sequence with "+(sequence.getTracks().length-1)+" MIDI tracks.");
|
||||
currentSequence = sequence;
|
||||
}
|
||||
|
||||
public void startSequencer(){
|
||||
sequencer.start();
|
||||
}
|
||||
|
||||
public boolean isRunning(){
|
||||
return sequencer.isRunning();
|
||||
}
|
||||
|
||||
public void stopSequencer(){
|
||||
if (sequencer.isOpen()){
|
||||
sequencer.stop();
|
||||
}
|
||||
mb.resetDrives();
|
||||
}
|
||||
|
||||
public void resetSequencer(){
|
||||
if (sequencer.isOpen()){
|
||||
sequencer.stop();
|
||||
sequencer.setTickPosition(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTempo(float newTempo){
|
||||
sequencer.setTempoInBPM(newTempo);
|
||||
}
|
||||
|
||||
public long getSecondsLength(){
|
||||
return sequencer.getMicrosecondLength()/1000000;
|
||||
}
|
||||
|
||||
public long getSecondsPosition(){
|
||||
return sequencer.getMicrosecondPosition()/1000000;
|
||||
}
|
||||
|
||||
public void setSecondsPosition(long seconds){
|
||||
sequencer.setMicrosecondPosition(seconds*1000000);
|
||||
}
|
||||
|
||||
public void addListener(MoppyStatusConsumer newListener){
|
||||
listeners.add(newListener);
|
||||
}
|
||||
|
@ -76,7 +92,6 @@ public class MoppySequencer implements MetaEventListener{
|
|||
public void closeSequencer(){
|
||||
stopSequencer();
|
||||
sequencer.close();
|
||||
mp.close();
|
||||
}
|
||||
|
||||
public void meta(MetaMessage meta) {
|
||||
|
@ -97,5 +112,24 @@ public class MoppySequencer implements MetaEventListener{
|
|||
|
||||
System.out.println("Tempo changed to: " + newTempo);
|
||||
}
|
||||
else if (meta.getType() == 47) {
|
||||
//MrSolidSnake745: Exposing end of sequence event
|
||||
for (MoppyStatusConsumer c : listeners) {
|
||||
c.sequenceEnded();
|
||||
}
|
||||
System.out.println("End of current sequence");
|
||||
}
|
||||
}
|
||||
|
||||
public void setReceiver(Receiver receiver) {
|
||||
sequenceTransmitter.setReceiver(receiver);
|
||||
}
|
||||
|
||||
public Receiver getReceiver() {
|
||||
return sequenceTransmitter.getReceiver();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
closeSequencer();
|
||||
}
|
||||
}
|
171
Java/MoppyDesk/src/moppydesk/midputs/DrivePooler.java
Normal file
171
Java/MoppyDesk/src/moppydesk/midputs/DrivePooler.java
Normal file
|
@ -0,0 +1,171 @@
|
|||
package moppydesk.midputs;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.*;
|
||||
import moppydesk.Constants;
|
||||
|
||||
/**
|
||||
* This class will re-map notes from specified incoming channels to a pool of
|
||||
* output channels based on one of several strategies.
|
||||
*/
|
||||
public class DrivePooler implements Receiver, Transmitter {
|
||||
|
||||
public enum PoolingStrategy {
|
||||
|
||||
STRAIGHT_THROUGH, ROUND_ROBIN, STACK
|
||||
};
|
||||
Receiver receiver = null;
|
||||
private int startInput = 0;
|
||||
private int endInput = 0;
|
||||
private int startOutput = 0;
|
||||
private int endOutput = 7;
|
||||
private PoolingStrategy currentStrategy = PoolingStrategy.STRAIGHT_THROUGH;
|
||||
private int[] currentNotes = new int[Constants.NUM_MIDI_CHANNELS];
|
||||
private int rrNextNote = 0;
|
||||
|
||||
public void setInputRange(int start, int end) {
|
||||
startInput = start - 1;
|
||||
endInput = end - 1;
|
||||
}
|
||||
|
||||
public void setOutputRange(int start, int end) {
|
||||
startOutput = start - 1;
|
||||
endOutput = end - 1;
|
||||
}
|
||||
|
||||
public void setStrategy(PoolingStrategy newStrat) {
|
||||
allOff();
|
||||
currentStrategy = newStrat;
|
||||
}
|
||||
|
||||
public void send(MidiMessage message, long timeStamp) {
|
||||
if (receiver != null) {
|
||||
if (message instanceof ShortMessage
|
||||
&& (message.getMessage()[0] & 0xFF) > 127 && (message.getMessage()[1] & 0xFF) < 160) {
|
||||
switch (currentStrategy) {
|
||||
case STRAIGHT_THROUGH:
|
||||
receiver.send(message, timeStamp); //No modifications
|
||||
break;
|
||||
case ROUND_ROBIN:
|
||||
receiver.send(roundRobinMap(message), timeStamp);
|
||||
break;
|
||||
case STACK:
|
||||
receiver.send(stackMap(message), timeStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MidiMessage roundRobinMap(MidiMessage message) {
|
||||
|
||||
if (rrNextNote < startOutput || rrNextNote > endOutput) {
|
||||
rrNextNote = startOutput;
|
||||
}
|
||||
|
||||
ShortMessage mappedMessage = (ShortMessage) message;
|
||||
try {
|
||||
if (mappedMessage.getChannel() >= startInput && mappedMessage.getChannel() <= endInput) {
|
||||
if (mappedMessage.getCommand() == ShortMessage.NOTE_OFF || (mappedMessage.getCommand() == ShortMessage.NOTE_ON && mappedMessage.getData2() == 0)) {
|
||||
int noteNumber = mappedMessage.getData1();
|
||||
for (int n = startOutput; n <= endOutput; n++) {
|
||||
if (currentNotes[n] == noteNumber) {
|
||||
currentNotes[n] = -1;
|
||||
mappedMessage.setMessage(mappedMessage.getCommand(), n, mappedMessage.getData1(), mappedMessage.getData2());
|
||||
break; // Only turn off one of the notes
|
||||
}
|
||||
}
|
||||
} else if (mappedMessage.getCommand() == ShortMessage.NOTE_ON) {
|
||||
int targetNote = rrNextNote;
|
||||
|
||||
while (targetNote <= endOutput) {
|
||||
if (currentNotes[targetNote] < 0) {
|
||||
break; // If that one's free, we're good.
|
||||
} else if (targetNote == endOutput) {
|
||||
targetNote = startOutput;
|
||||
} else {
|
||||
targetNote++;
|
||||
}
|
||||
|
||||
if (targetNote == rrNextNote) {
|
||||
break; //We've gone around once, stop!
|
||||
}
|
||||
}
|
||||
|
||||
currentNotes[targetNote] = mappedMessage.getData1();
|
||||
mappedMessage.setMessage(mappedMessage.getCommand(), targetNote, mappedMessage.getData1(), mappedMessage.getData2());
|
||||
|
||||
rrNextNote++;
|
||||
}
|
||||
} else {
|
||||
return message; //It's not in the mapping range, let it pass through...
|
||||
}
|
||||
} catch (InvalidMidiDataException ex) {
|
||||
Logger.getLogger(DrivePooler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return mappedMessage;
|
||||
|
||||
}
|
||||
|
||||
private MidiMessage stackMap(MidiMessage message) {
|
||||
ShortMessage mappedMessage = (ShortMessage) message;
|
||||
try {
|
||||
//If it's in the chosen range:
|
||||
if (mappedMessage.getChannel() >= startInput && mappedMessage.getChannel() <= endInput) {
|
||||
if (mappedMessage.getCommand() == ShortMessage.NOTE_OFF || (mappedMessage.getCommand() == ShortMessage.NOTE_ON && mappedMessage.getData2() == 0)) {
|
||||
int noteNumber = mappedMessage.getData1();
|
||||
for (int n = startOutput; n <= endOutput; n++) {
|
||||
if (currentNotes[n] == noteNumber) {
|
||||
currentNotes[n] = -1;
|
||||
mappedMessage.setMessage(mappedMessage.getCommand(), n, mappedMessage.getData1(), mappedMessage.getData2());
|
||||
}
|
||||
}
|
||||
} else if (mappedMessage.getCommand() == ShortMessage.NOTE_ON) {
|
||||
|
||||
int targetChannel = 0;
|
||||
|
||||
for (int n = startOutput; n <= endOutput; n++) {
|
||||
if (currentNotes[n] < 0) {
|
||||
targetChannel = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currentNotes[targetChannel] = mappedMessage.getData1();
|
||||
mappedMessage.setMessage(mappedMessage.getCommand(), targetChannel, mappedMessage.getData1(), mappedMessage.getData2());
|
||||
}
|
||||
} else {
|
||||
return message; //It's not in the mapping range, let it pass through...
|
||||
}
|
||||
} catch (InvalidMidiDataException ex) {
|
||||
Logger.getLogger(DrivePooler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return mappedMessage;
|
||||
}
|
||||
|
||||
private void allOff() {
|
||||
Arrays.fill(currentNotes, -1);
|
||||
}
|
||||
|
||||
//
|
||||
//// Transmitter-methods
|
||||
//
|
||||
public void close() {
|
||||
if (receiver != null) {
|
||||
receiver.close();
|
||||
receiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setReceiver(Receiver newReceiver) {
|
||||
if (this.receiver != null) {
|
||||
this.receiver.close();
|
||||
}
|
||||
this.receiver = newReceiver;
|
||||
}
|
||||
|
||||
public Receiver getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
}
|
92
Java/MoppyDesk/src/moppydesk/midputs/NoteFilter.java
Normal file
92
Java/MoppyDesk/src/moppydesk/midputs/NoteFilter.java
Normal file
|
@ -0,0 +1,92 @@
|
|||
package moppydesk.midputs;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.*;
|
||||
|
||||
/**
|
||||
* This class will perform various operations on notes as they pass through. Mostly this
|
||||
* is for keeping notes within the specified range.
|
||||
*/
|
||||
public class NoteFilter implements Receiver, Transmitter {
|
||||
|
||||
Receiver receiver = null;
|
||||
private boolean autoContstrain = false;
|
||||
private boolean ignoreTen = false;
|
||||
|
||||
private static final int LOWEST_NOTE = 24; //C1
|
||||
private static final int HIGHEST_NOTE = 71; //B4
|
||||
|
||||
public void setAutoConstrain(boolean newValue) {
|
||||
autoContstrain = newValue;
|
||||
}
|
||||
|
||||
public void setIgnoreTen(boolean newValue) {
|
||||
ignoreTen = newValue;
|
||||
}
|
||||
|
||||
public void send(MidiMessage message, long timeStamp) {
|
||||
if (receiver != null) {
|
||||
if (message instanceof ShortMessage
|
||||
&& (message.getMessage()[0] & 0xFF) >= 128 && (message.getMessage()[1] & 0xFF) <= 159) {
|
||||
ShortMessage filteredMessage = (ShortMessage) message;
|
||||
|
||||
if (autoContstrain){
|
||||
constrainNote(filteredMessage);
|
||||
}
|
||||
if (ignoreTen && filteredMessage.getChannel() == 9){
|
||||
return; // If we're ignoring 10 and that's the channel, just return immediately
|
||||
}
|
||||
|
||||
receiver.send(filteredMessage, timeStamp);
|
||||
} else {
|
||||
receiver.send(message, timeStamp); // If it's not a note event, pass it on through.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the note data within this message to fit between {@link #LOWEST_NOTE} and {@link #HIGHEST_NOTE}, inclusive.
|
||||
* This will affect both on and off messages so that any altered notes turned on will also be turned off.
|
||||
* @param message
|
||||
*/
|
||||
private void constrainNote(ShortMessage message){
|
||||
int newNote = message.getData1();
|
||||
|
||||
while (newNote<LOWEST_NOTE){
|
||||
newNote += 12; // Up an octave
|
||||
}
|
||||
while (newNote>HIGHEST_NOTE){
|
||||
newNote -= 12; // Down an octave
|
||||
}
|
||||
|
||||
try {
|
||||
message.setMessage(message.getStatus(), newNote, message.getData2());
|
||||
} catch (InvalidMidiDataException ex) {
|
||||
Logger.getLogger(NoteFilter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//// Transmitter-methods
|
||||
//
|
||||
public void close() {
|
||||
if (receiver != null) {
|
||||
receiver.close();
|
||||
receiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setReceiver(Receiver newReceiver) {
|
||||
if (this.receiver != null) {
|
||||
this.receiver.close();
|
||||
}
|
||||
this.receiver = newReceiver;
|
||||
}
|
||||
|
||||
public Receiver getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
|
||||
}
|
110
Java/MoppyDesk/src/moppydesk/outputs/MoppyCOMBridge.java
Normal file
110
Java/MoppyDesk/src/moppydesk/outputs/MoppyCOMBridge.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
package moppydesk.outputs;
|
||||
|
||||
import gnu.io.NRSerialPort;
|
||||
import gnu.io.NoSuchPortException;
|
||||
import gnu.io.PortInUseException;
|
||||
import gnu.io.UnsupportedCommOperationException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class MoppyCOMBridge {
|
||||
|
||||
static int FIRST_PIN = 2;
|
||||
static int MAX_PIN = 17;
|
||||
int SERIAL_RATE = 9600;
|
||||
OutputStream os;
|
||||
NRSerialPort com;
|
||||
private boolean isOutputOpen = false;
|
||||
|
||||
public MoppyCOMBridge(String portName) throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException, IOException {
|
||||
com = new NRSerialPort(portName, SERIAL_RATE);
|
||||
com.connect();
|
||||
|
||||
os = com.getOutputStream();
|
||||
isOutputOpen = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that splits the periodData int into two bytes for
|
||||
* sending over serial.
|
||||
*
|
||||
* @param pin Controller pin to handle ntoe
|
||||
* @param periodData length of period in microSeconds
|
||||
*/
|
||||
public void sendEvent(byte pin, int periodData) {
|
||||
sendEvent(pin, (byte) ((periodData >> 8) & 0xFF), (byte) (periodData & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an event to the Arduino.
|
||||
*
|
||||
* @param pin Controller pin
|
||||
* @param b1
|
||||
* @param b2
|
||||
*/
|
||||
public void sendEvent(byte pin, byte b1, byte b2) {
|
||||
sendArray(new byte[]{pin, b1, b2});
|
||||
}
|
||||
|
||||
private void sendArray(byte[] message) {
|
||||
try {
|
||||
os.write(message);
|
||||
os.flush();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyCOMBridge.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a '0' period to all drives to silence them.
|
||||
*/
|
||||
public void silenceDrives() {
|
||||
// Stop notes
|
||||
for (int d = FIRST_PIN; d <= MAX_PIN; d += 2) {
|
||||
sendArray(new byte[]{(byte) d, (byte) 0, (byte) 0});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a special code (first byte=100) to reset the drives
|
||||
*/
|
||||
public void resetDrives() {
|
||||
if (isOutputOpen) {
|
||||
//Send reset code
|
||||
sendArray(new byte[]{(byte) 100, (byte) 0, (byte) 0});
|
||||
try {
|
||||
Thread.sleep(500); // Give the drives time to reset
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(MoppyCOMBridge.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (os != null) {
|
||||
if (isOutputOpen) { //Only attempt to silence if the output is still open.
|
||||
silenceDrives();
|
||||
}
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyCOMBridge.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (com != null && com.isConnected()) {
|
||||
com.disconnect();
|
||||
}
|
||||
isOutputOpen = false;
|
||||
}
|
||||
|
||||
public static String[] getAvailableCOMPorts() {
|
||||
return NRSerialPort.getAvailableSerialPorts().toArray(new String[0]);
|
||||
}
|
||||
}
|
97
Java/MoppyDesk/src/moppydesk/outputs/MoppyMIDIOutput.java
Normal file
97
Java/MoppyDesk/src/moppydesk/outputs/MoppyMIDIOutput.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moppydesk.outputs;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.*;
|
||||
import javax.sound.midi.MidiDevice.Info;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam
|
||||
*/
|
||||
public class MoppyMIDIOutput implements MoppyReceiver{
|
||||
|
||||
MidiDevice device;
|
||||
Receiver deviceReceiver;
|
||||
|
||||
public MoppyMIDIOutput(String midiDeviceName) throws MidiUnavailableException{
|
||||
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
|
||||
for (Info i : infos){
|
||||
try {
|
||||
if (i.getName().equalsIgnoreCase(midiDeviceName)){
|
||||
this.device = MidiSystem.getMidiDevice(i);
|
||||
}
|
||||
} catch (MidiUnavailableException ex) {
|
||||
Logger.getLogger(MoppyMIDIOutput.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
device.open();
|
||||
deviceReceiver = device.getReceiver();
|
||||
}
|
||||
|
||||
public static HashMap<String,Info> getMIDIOutInfos(){
|
||||
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
|
||||
HashMap<String,Info> outInfos = new HashMap<String,Info>();
|
||||
|
||||
for (Info i : infos){
|
||||
try {
|
||||
MidiDevice dev = MidiSystem.getMidiDevice(i);
|
||||
if (dev.getMaxReceivers() != 0){
|
||||
outInfos.put(i.getName(), i);
|
||||
}
|
||||
} catch (MidiUnavailableException ex) {
|
||||
Logger.getLogger(MoppyMIDIOutput.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
return outInfos;
|
||||
}
|
||||
|
||||
public void send(MidiMessage message, long timeStamp) {
|
||||
deviceReceiver.send(message, timeStamp);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
deviceReceiver.close();
|
||||
device.close();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
//Nothing really to do here, I don't think.
|
||||
if (deviceReceiver != null){
|
||||
try {
|
||||
ShortMessage resetMessage = new ShortMessage();
|
||||
resetMessage.setMessage(ShortMessage.SYSTEM_RESET);
|
||||
deviceReceiver.send(resetMessage,(long)-1);
|
||||
} catch (InvalidMidiDataException ex) {
|
||||
Logger.getLogger(MoppyMIDIOutput.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Since the goal here is to silence any playing devices, we'll pass the "All Note Off" command to
|
||||
* each channel. Hopefully the receiving devices understand this message.
|
||||
*/
|
||||
public void silence() {
|
||||
if (deviceReceiver != null) {
|
||||
try {
|
||||
ShortMessage silenceMessage = new ShortMessage();
|
||||
|
||||
for (int channelCode=176;channelCode<=191;channelCode++){
|
||||
silenceMessage.setMessage(channelCode, 123, 0);
|
||||
deviceReceiver.send(silenceMessage, (long) -1);
|
||||
}
|
||||
|
||||
} catch (InvalidMidiDataException ex) {
|
||||
Logger.getLogger(MoppyMIDIOutput.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
package moppydesk;
|
||||
package moppydesk.outputs;
|
||||
|
||||
import gnu.io.SerialPort;
|
||||
import javax.sound.midi.MidiMessage;
|
||||
import javax.sound.midi.Receiver;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class MoppyPlayer implements Receiver {
|
||||
public class MoppyPlayerOutput implements MoppyReceiver {
|
||||
|
||||
/**
|
||||
* The periods for each MIDI note in an array. The floppy drives
|
||||
|
@ -16,6 +15,8 @@ public class MoppyPlayer implements Receiver {
|
|||
* Periods are in microseconds because that's what the Arduino uses for its
|
||||
* clock-cycles in the micro() function, and because milliseconds aren't
|
||||
* precise enough for musical notes.
|
||||
*
|
||||
* Notes are named (e.g. C1-B4) based on scientific pitch notation (A4=440Hz)
|
||||
*/
|
||||
public static int[] microPeriods = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -29,6 +30,11 @@ public class MoppyPlayer implements Receiver {
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Maximum number of cents to bend +/-.
|
||||
*/
|
||||
private static int BEND_CENTS = 200;
|
||||
|
||||
/**
|
||||
* Resolution of the Arduino code in microSeconds.
|
||||
*/
|
||||
|
@ -40,15 +46,16 @@ public class MoppyPlayer implements Receiver {
|
|||
*/
|
||||
private int[] currentPeriod = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
MoppyBridge mb;
|
||||
MoppyCOMBridge mb;
|
||||
SerialPort com;
|
||||
|
||||
public MoppyPlayer(MoppyBridge newMb) {
|
||||
public MoppyPlayerOutput(MoppyCOMBridge newMb) {
|
||||
mb = newMb;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mb.close();
|
||||
mb.resetDrives();
|
||||
mb.close();
|
||||
}
|
||||
|
||||
//Is called by Java MIDI libraries for each MIDI message encountered.
|
||||
|
@ -94,13 +101,22 @@ public class MoppyPlayer implements Receiver {
|
|||
//Arduino by multipying by 2.
|
||||
byte pin = (byte) (2 * (message.getStatus() - 223));
|
||||
|
||||
double pitchBend = ((message.getMessage()[2] & 0xff) << 8) + (message.getMessage()[1] & 0xff);
|
||||
|
||||
int period = (int) (currentPeriod[message.getStatus() - 224] / Math.pow(2.0, (pitchBend - 8192) / 8192));
|
||||
//System.out.println(currentPeriod[message.getStatus() - 224] + "-" + period);
|
||||
double pitchBend = ((message.getMessage()[2] & 0xff) << 7) + (message.getMessage()[1] & 0xff);
|
||||
//System.out.println("Pitch bend " + pitchBend);
|
||||
// Calculate the new period based on the desired maximum bend and the current pitchBend value
|
||||
int period = (int) (currentPeriod[message.getStatus() - 224] / Math.pow(2.0, (BEND_CENTS/1200.0)*((pitchBend - 8192.0) / 8192.0)));
|
||||
//System.out.println("Bent by " + Math.pow(2.0, (bendCents/1200.0)*((pitchBend - 8192.0) / 8192.0)));
|
||||
mb.sendEvent(pin, period);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mb.resetDrives();
|
||||
}
|
||||
|
||||
public void silence() {
|
||||
mb.silenceDrives();
|
||||
}
|
||||
}
|
17
Java/MoppyDesk/src/moppydesk/outputs/MoppyReceiver.java
Normal file
17
Java/MoppyDesk/src/moppydesk/outputs/MoppyReceiver.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package moppydesk.outputs;
|
||||
|
||||
import javax.sound.midi.Receiver;
|
||||
|
||||
/**
|
||||
* Adds a reset function to the MIDI Receiver class.
|
||||
* @author Sam
|
||||
*/
|
||||
public interface MoppyReceiver extends Receiver{
|
||||
|
||||
/**
|
||||
* Returns the drives/xylophone/calliope/organ/drums to a reset-state.
|
||||
* This should not disconnect or dispose of any connection though.
|
||||
*/
|
||||
public void reset();
|
||||
public void silence();
|
||||
}
|
107
Java/MoppyDesk/src/moppydesk/outputs/ReceiverMarshaller.java
Normal file
107
Java/MoppyDesk/src/moppydesk/outputs/ReceiverMarshaller.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
package moppydesk.outputs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import javax.sound.midi.MidiDevice;
|
||||
import javax.sound.midi.MidiMessage;
|
||||
import javax.sound.midi.Receiver;
|
||||
import javax.sound.midi.ShortMessage;
|
||||
|
||||
/**
|
||||
* Marshals data from the chosen input device to the (up to) 16 output receivers.
|
||||
* Receivers are defined in a size-16 array, one slot for each MIDI channel. Each received
|
||||
* message is routed to the appropriate receiver based on its channel. If a receiver
|
||||
* is not defined for the given channel's index in the array, the message is dropped.
|
||||
*/
|
||||
public class ReceiverMarshaller implements MoppyReceiver{
|
||||
|
||||
/**
|
||||
* Array of {@link MoppyReceiver} references, one for each channel. The same receiver
|
||||
* object can be assigned to multiple indexes if it is going to be handling multiple
|
||||
* channels of data.
|
||||
*/
|
||||
private final MoppyReceiver[] outputReceivers = new MoppyReceiver[16];
|
||||
|
||||
/**
|
||||
* Creates a new ReceiverMarshaller with an empty array of {@link Receiver}s.
|
||||
* @param receivers
|
||||
*/
|
||||
public ReceiverMarshaller(){
|
||||
//Nothing for now.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a channel's Receiver object. If a receiver is already assigned to this
|
||||
* channel, {@link Receiver#close()} will be called before it is removed and replaced
|
||||
* with the new {@link Receiver}.
|
||||
* @param MIDIChannel
|
||||
* @param channelReceiver
|
||||
*/
|
||||
public void setReceiver(int MIDIChannel, MoppyReceiver channelReceiver){
|
||||
if (MIDIChannel < 1 || MIDIChannel > 16){
|
||||
throw new IllegalArgumentException("Only channels 1-16 are supported by the ReceiverMarshaller!");
|
||||
}
|
||||
if (outputReceivers[MIDIChannel-1] != null){
|
||||
outputReceivers[MIDIChannel-1].close();
|
||||
}
|
||||
outputReceivers[MIDIChannel-1] = channelReceiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all receivers, and removes them from the array (fills array with nulls).
|
||||
*/
|
||||
public void clearReceivers()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
public void send(MidiMessage message, long timeStamp) {
|
||||
int ch = ((ShortMessage)message).getChannel();
|
||||
if (outputReceivers[ch]!= null){
|
||||
outputReceivers[ch].send(message, timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicity closes all output receivers, and nulls the array.
|
||||
* This differs slightly from the use described in {@link MidiDevice} in that
|
||||
* the ReceiverMarshaller itself is not necessarily closed when this is called.
|
||||
* After being closed, new receivers can continue to be added to the ReceiverMarshaller.
|
||||
*/
|
||||
public void close() {
|
||||
for (Receiver r: outputReceivers){
|
||||
if (r!= null){
|
||||
r.close();
|
||||
}
|
||||
}
|
||||
Arrays.fill(outputReceivers, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the unique set of receivers and calls the {@link MoppyReceiver#reset() } method.
|
||||
* We go through the trouble of finding unique receivers incase the reset is time-consuming.
|
||||
*/
|
||||
public void reset() {
|
||||
ArrayList<MoppyReceiver> uniqueReceivers = new ArrayList<MoppyReceiver>();
|
||||
for (MoppyReceiver r: outputReceivers){
|
||||
if (r!= null && !uniqueReceivers.contains(r)){
|
||||
uniqueReceivers.add(r);
|
||||
}
|
||||
}
|
||||
for (MoppyReceiver r : uniqueReceivers){
|
||||
r.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public void silence() {
|
||||
ArrayList<MoppyReceiver> uniqueReceivers = new ArrayList<MoppyReceiver>();
|
||||
for (MoppyReceiver r: outputReceivers){
|
||||
if (r!= null && !uniqueReceivers.contains(r)){
|
||||
uniqueReceivers.add(r);
|
||||
}
|
||||
}
|
||||
for (MoppyReceiver r : uniqueReceivers){
|
||||
r.silence();
|
||||
}
|
||||
}
|
||||
}
|
173
Java/MoppyDesk/src/moppydesk/playlist/MoppyPlaylist.java
Normal file
173
Java/MoppyDesk/src/moppydesk/playlist/MoppyPlaylist.java
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moppydesk.playlist;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author AJ (MrSolidSnake745)
|
||||
* Class that represents a playlist
|
||||
*/
|
||||
public class MoppyPlaylist extends AbstractTableModel {
|
||||
private List<MoppySong> playlist = new ArrayList<>();
|
||||
private int currentIndex = -1;
|
||||
private static final int COL_COUNT = 3;
|
||||
private static final int INDICATOR_INDEX = 0;
|
||||
private static final int TITLE_INDEX = 2;
|
||||
private static final int PLAYED_INDEX = 1;
|
||||
|
||||
public MoppyPlaylist() {
|
||||
|
||||
}
|
||||
public void addSong(File file) {playlist.add(new MoppySong(file)); fireTableDataChanged();}
|
||||
public void currentSongFinished() {if(currentIndex != -1) {playlist.get(currentIndex).setPlayed(true);} fireTableDataChanged();}
|
||||
public void currentSongReset() {if(currentIndex != -1) {playlist.get(currentIndex).setPlayed(false);} fireTableDataChanged();}
|
||||
|
||||
public Boolean isFinished() {
|
||||
if(isEmpty()) return true;
|
||||
for (MoppySong s: playlist) {if(!(s.getPlayed())) return false;}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean isEmpty() {return playlist.isEmpty();}
|
||||
public Boolean isFirstSong() {return currentIndex == 0;}
|
||||
public Boolean isLastSong() {return currentIndex == playlist.size() - 1;}
|
||||
public int getIndex() {return currentIndex;}
|
||||
|
||||
public String getCurrentSongName() {return playlist.get(currentIndex).getName();}
|
||||
public Boolean getCurrentSongPlayed() {return playlist.get(currentIndex).getPlayed();}
|
||||
public void randomize() {Collections.shuffle(playlist); reset();}
|
||||
|
||||
public File getNextSong() {
|
||||
if(!isLastSong()) {
|
||||
currentSongFinished();
|
||||
return playlist.get(++currentIndex).getFile();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public File getPreviousSong() {
|
||||
if(!isFirstSong()) {
|
||||
--currentIndex; currentSongReset();
|
||||
return playlist.get(currentIndex).getFile();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
currentIndex = -1;
|
||||
for (MoppySong i: playlist) {i.setPlayed(false);}
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
currentIndex = -1;
|
||||
playlist.clear();
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
public boolean savePlaylistFile(File input) {
|
||||
try {
|
||||
FileWriter fr = new FileWriter(input);
|
||||
BufferedWriter br = new BufferedWriter(fr);
|
||||
for (MoppySong i: playlist) {
|
||||
br.write(i.getName() + ";" + i.getFile().getPath());
|
||||
br.newLine();
|
||||
}
|
||||
br.close();
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyPlaylist.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean loadPlaylistFile(File input) {
|
||||
try {
|
||||
FileReader fr = new FileReader(input);
|
||||
BufferedReader br = new BufferedReader(fr);
|
||||
List<MoppySong> newpl = new ArrayList<>();
|
||||
String s = br.readLine();
|
||||
while (s != null) {
|
||||
String[] line = s.split(";");
|
||||
if(line.length == 2) { newpl.add(new MoppySong(line[0], line[1])); }
|
||||
s = br.readLine();
|
||||
}
|
||||
br.close();
|
||||
playlist = newpl;
|
||||
fireTableDataChanged();
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MoppyPlaylist.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="TableModel Implementation">
|
||||
@Override
|
||||
public int getRowCount() { return playlist.size(); }
|
||||
@Override
|
||||
public int getColumnCount() { return COL_COUNT; }
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) { return false; } //Setting all cells to read only
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
MoppySong song = playlist.get(rowIndex);
|
||||
switch (columnIndex) {
|
||||
case INDICATOR_INDEX:
|
||||
if(rowIndex == currentIndex) return " ► ";
|
||||
return "";
|
||||
case TITLE_INDEX:
|
||||
return song.getName();
|
||||
case PLAYED_INDEX:
|
||||
return song.getPlayed();
|
||||
default:
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getColumnClass(int column) {
|
||||
switch (column) {
|
||||
case INDICATOR_INDEX:
|
||||
return String.class;
|
||||
case TITLE_INDEX:
|
||||
return String.class;
|
||||
case PLAYED_INDEX:
|
||||
return Boolean.class;
|
||||
default:
|
||||
return Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
switch (column) {
|
||||
case INDICATOR_INDEX:
|
||||
return "";
|
||||
case TITLE_INDEX:
|
||||
return "Name";
|
||||
case PLAYED_INDEX:
|
||||
return "Played";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
// </editor-fold>
|
||||
}
|
34
Java/MoppyDesk/src/moppydesk/playlist/MoppySong.java
Normal file
34
Java/MoppyDesk/src/moppydesk/playlist/MoppySong.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package moppydesk.playlist;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author AJ (MrSolidSnake745)
|
||||
* Stupid simple class to represent a song...
|
||||
*/
|
||||
public class MoppySong {
|
||||
private String title;
|
||||
private Boolean played = false;
|
||||
private String filePath = null;
|
||||
|
||||
public MoppySong(String titleIn, String pathIn) { title = titleIn; filePath = pathIn; }
|
||||
|
||||
public MoppySong(File fileIn) {
|
||||
title = fileIn.getName().substring(0, fileIn.getName().lastIndexOf("."));
|
||||
filePath = fileIn.getAbsolutePath();
|
||||
}
|
||||
|
||||
public String getName() {return title;}
|
||||
public Boolean getPlayed() {return played;}
|
||||
public String getFilePath() {return filePath;}
|
||||
|
||||
public void setName(String titleIn) {title = titleIn;}
|
||||
public void setPlayed(Boolean playedIn) {played = playedIn;}
|
||||
public void setFilePath(String filePathIn) {filePath = filePathIn;}
|
||||
|
||||
public File getFile() {
|
||||
if(filePath != null) return new File(filePath);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
Application.name = MoppyUI
|
||||
Application.id = MoppyUI
|
||||
Application.title = Moppy UI
|
||||
Application.version = 1.1.0
|
||||
Application.vendor = Sammy1Am
|
||||
Application.vendorId = sam
|
||||
Application.homepage = https://github.com/SammyIAm/Moppy
|
||||
Application.description = Control software for Musical fOPPY drives.
|
||||
Application.lookAndFeel = system
|
122
Java/MoppyDesk/src/moppydesk/ui/ChannelOutControl.form
Normal file
122
Java/MoppyDesk/src/moppydesk/ui/ChannelOutControl.form
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<NonVisualComponents>
|
||||
<Component class="javax.swing.ButtonGroup" name="outputTypeRB">
|
||||
</Component>
|
||||
</NonVisualComponents>
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[525, 23]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="enabledCB" min="-2" pref="46" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="moppyTypeRB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="comComboBox" pref="161" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="MIDITypeRB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="midiOutComboBox" min="-2" pref="130" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="moppyTypeRB" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="MIDITypeRB" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="comComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="midiOutComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="enabledCB" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JRadioButton" name="moppyTypeRB">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="outputTypeRB"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Moppy Serial:"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Sends Moppy-protocol serial data to selected COM port"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="outputTypeChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="MIDITypeRB">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="outputTypeRB"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="MIDI Out:"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Sends MIDI messages through to selected MIDI port"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="outputTypeChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="comComboBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new DefaultComboBoxModel<String>(moppydesk.outputs.MoppyCOMBridge.getAvailableCOMPorts())" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="popupMenuWillBecomeVisible" listener="javax.swing.event.PopupMenuListener" parameters="javax.swing.event.PopupMenuEvent" handler="comComboBoxPopupMenuWillBecomeVisible"/>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="comComboBoxActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="midiOutComboBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new DefaultComboBoxModel<String>(controlWindow.availableMIDIOuts.keySet().toArray(new String[0]))" type="code"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="midiOutComboBoxActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="enabledCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="String.valueOf(settings.MIDIChannel)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="enabledCBActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
243
Java/MoppyDesk/src/moppydesk/ui/ChannelOutControl.java
Normal file
243
Java/MoppyDesk/src/moppydesk/ui/ChannelOutControl.java
Normal file
|
@ -0,0 +1,243 @@
|
|||
package moppydesk.ui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import moppydesk.OutputSetting;
|
||||
import moppydesk.OutputSetting.OutputType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class ChannelOutControl extends javax.swing.JPanel {
|
||||
|
||||
private final OutputSetting settings;
|
||||
private final MoppyControlWindow controlWindow;
|
||||
|
||||
/**
|
||||
* Creates new form ChannelOutControl
|
||||
*/
|
||||
public ChannelOutControl(MoppyControlWindow mcw, OutputSetting os) {
|
||||
this.settings = os;
|
||||
this.controlWindow = mcw;
|
||||
initComponents();
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
private void loadSettings() {
|
||||
|
||||
if (settings.type.equals(OutputType.MOPPY)) {
|
||||
moppyTypeRB.setSelected(true);
|
||||
outputTypeChanged(OutputType.MOPPY);
|
||||
} else {
|
||||
MIDITypeRB.setSelected(true);
|
||||
outputTypeChanged(OutputType.MIDI);
|
||||
}
|
||||
|
||||
if (settings.enabled) {
|
||||
enabledCB.setSelected(true);
|
||||
enableControls();
|
||||
} else {
|
||||
enabledCB.setSelected(false);
|
||||
disableControls();
|
||||
}
|
||||
|
||||
//MrSolidSnake745: Ensure the saved settings are still valid and load their values
|
||||
//Else default to the first item in the collection
|
||||
if(doesCOMExist(settings.comPort)) {comComboBox.setSelectedItem(settings.comPort);}
|
||||
else {settings.comPort = (String) comComboBox.getModel().getElementAt(0);}
|
||||
|
||||
if(doesMIDIExist(settings.midiDeviceName)) {midiOutComboBox.setSelectedItem(settings.midiDeviceName);}
|
||||
else {settings.midiDeviceName = (String) midiOutComboBox.getModel().getElementAt(0);}
|
||||
}
|
||||
|
||||
public void lockControl(){
|
||||
enabledCB.setEnabled(false);
|
||||
disableControls();
|
||||
}
|
||||
|
||||
public void unlockControl(){
|
||||
enabledCB.setEnabled(true);
|
||||
if (enabledCB.isSelected()) enableControls();
|
||||
}
|
||||
|
||||
private void disableControls() {
|
||||
moppyTypeRB.setEnabled(false);
|
||||
MIDITypeRB.setEnabled(false);
|
||||
comComboBox.setEnabled(false);
|
||||
midiOutComboBox.setEnabled(false);
|
||||
}
|
||||
|
||||
private void enableControls() {
|
||||
moppyTypeRB.setEnabled(true);
|
||||
MIDITypeRB.setEnabled(true);
|
||||
if (moppyTypeRB.isSelected()){
|
||||
outputTypeChanged(new ActionEvent(moppyTypeRB, ActionEvent.ACTION_PERFORMED, moppyTypeRB.getActionCommand()));
|
||||
} else if (MIDITypeRB.isSelected()){
|
||||
outputTypeChanged(new ActionEvent(MIDITypeRB, ActionEvent.ACTION_PERFORMED, MIDITypeRB.getActionCommand()));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doesCOMExist(Object obj) {
|
||||
return (((DefaultComboBoxModel)(comComboBox.getModel())).getIndexOf(obj) > -1);
|
||||
}
|
||||
|
||||
private boolean doesMIDIExist(Object obj) {
|
||||
return (((DefaultComboBoxModel)(midiOutComboBox.getModel())).getIndexOf(obj) > -1);
|
||||
}
|
||||
|
||||
//MrSolidSnake745: Method to refresh the list of available COM ports
|
||||
private void refreshAvailablePorts() {
|
||||
comComboBox.setModel(new DefaultComboBoxModel<String>(moppydesk.outputs.MoppyCOMBridge.getAvailableCOMPorts()));
|
||||
if(doesCOMExist(settings.comPort)) {comComboBox.setSelectedItem(settings.comPort);} //To avoid losing last user selected value
|
||||
else {settings.comPort = (String) comComboBox.getModel().getElementAt(0);} //ActionPerformed event isn't triggered so we need to manually set
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
outputTypeRB = new javax.swing.ButtonGroup();
|
||||
moppyTypeRB = new javax.swing.JRadioButton();
|
||||
MIDITypeRB = new javax.swing.JRadioButton();
|
||||
comComboBox = new javax.swing.JComboBox<String>();
|
||||
midiOutComboBox = new javax.swing.JComboBox<String>();
|
||||
enabledCB = new javax.swing.JCheckBox();
|
||||
|
||||
setPreferredSize(new java.awt.Dimension(525, 23));
|
||||
|
||||
outputTypeRB.add(moppyTypeRB);
|
||||
moppyTypeRB.setText("Moppy Serial:");
|
||||
moppyTypeRB.setToolTipText("Sends Moppy-protocol serial data to selected COM port");
|
||||
moppyTypeRB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
outputTypeChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
outputTypeRB.add(MIDITypeRB);
|
||||
MIDITypeRB.setText("MIDI Out:");
|
||||
MIDITypeRB.setToolTipText("Sends MIDI messages through to selected MIDI port");
|
||||
MIDITypeRB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
outputTypeChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
comComboBox.setModel(new DefaultComboBoxModel<String>(moppydesk.outputs.MoppyCOMBridge.getAvailableCOMPorts()));
|
||||
comComboBox.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
|
||||
public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
|
||||
}
|
||||
public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
|
||||
}
|
||||
public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
|
||||
comComboBoxPopupMenuWillBecomeVisible(evt);
|
||||
}
|
||||
});
|
||||
comComboBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
comComboBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
midiOutComboBox.setModel(new DefaultComboBoxModel<String>(controlWindow.availableMIDIOuts.keySet().toArray(new String[0])));
|
||||
midiOutComboBox.setEnabled(false);
|
||||
midiOutComboBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
midiOutComboBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
enabledCB.setText(String.valueOf(settings.MIDIChannel));
|
||||
enabledCB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
enabledCBActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(enabledCB, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(moppyTypeRB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(comComboBox, 0, 161, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(MIDITypeRB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(midiOutComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(moppyTypeRB)
|
||||
.addComponent(MIDITypeRB)
|
||||
.addComponent(comComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(midiOutComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(enabledCB)))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void comComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comComboBoxActionPerformed
|
||||
//MrSolidSnake745: FYI, this fires on initial click to generate dropdown and once more on clicking a value
|
||||
settings.comPort = (String) ((JComboBox) evt.getSource()).getSelectedItem();
|
||||
}//GEN-LAST:event_comComboBoxActionPerformed
|
||||
|
||||
private void midiOutComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_midiOutComboBoxActionPerformed
|
||||
settings.midiDeviceName = (String) ((JComboBox) evt.getSource()).getSelectedItem();
|
||||
}//GEN-LAST:event_midiOutComboBoxActionPerformed
|
||||
|
||||
private void enabledCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_enabledCBActionPerformed
|
||||
settings.enabled = ((JCheckBox) evt.getSource()).isSelected();
|
||||
if (settings.enabled) {
|
||||
enableControls();
|
||||
} else {
|
||||
disableControls();
|
||||
}
|
||||
}//GEN-LAST:event_enabledCBActionPerformed
|
||||
|
||||
private void outputTypeChanged(OutputType newType){
|
||||
settings.type = newType;
|
||||
if (newType.equals(OutputType.MOPPY)){
|
||||
midiOutComboBox.setEnabled(false);
|
||||
comComboBox.setEnabled(true);
|
||||
} else {
|
||||
comComboBox.setEnabled(false);
|
||||
midiOutComboBox.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void outputTypeChanged(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_outputTypeChanged
|
||||
if (evt.getSource().equals(moppyTypeRB)) {
|
||||
outputTypeChanged(OutputType.MOPPY);
|
||||
} else {
|
||||
outputTypeChanged(OutputType.MIDI);
|
||||
}
|
||||
}//GEN-LAST:event_outputTypeChanged
|
||||
|
||||
private void comComboBoxPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_comComboBoxPopupMenuWillBecomeVisible
|
||||
refreshAvailablePorts();
|
||||
}//GEN-LAST:event_comComboBoxPopupMenuWillBecomeVisible
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JRadioButton MIDITypeRB;
|
||||
private javax.swing.JComboBox<String> comComboBox;
|
||||
private javax.swing.JCheckBox enabledCB;
|
||||
private javax.swing.JComboBox<String> midiOutComboBox;
|
||||
private javax.swing.JRadioButton moppyTypeRB;
|
||||
private javax.swing.ButtonGroup outputTypeRB;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
71
Java/MoppyDesk/src/moppydesk/ui/FilterControls.form
Normal file
71
Java/MoppyDesk/src/moppydesk/ui/FilterControls.form
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[149, 149]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="constrainCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="ignoreTenCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="49" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="constrainCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="ignoreTenCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="91" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JCheckBox" name="constrainCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Constrain Notes"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Automatically transposes notes outside of the floppy drive range into playable range."/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="constrainCBActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="ignoreTenCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Ignore Channel 10"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="MIDI channel 10 is generally reserved for percussion instruments and is unlikely to render correctly on floppy drives."/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ignoreTenCBActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
139
Java/MoppyDesk/src/moppydesk/ui/FilterControls.java
Normal file
139
Java/MoppyDesk/src/moppydesk/ui/FilterControls.java
Normal file
|
@ -0,0 +1,139 @@
|
|||
package moppydesk.ui;
|
||||
|
||||
import moppydesk.Constants;
|
||||
import moppydesk.MoppyUI;
|
||||
import moppydesk.midputs.NoteFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class FilterControls extends javax.swing.JPanel {
|
||||
|
||||
private NoteFilter filter;
|
||||
private MoppyUI app;
|
||||
|
||||
/**
|
||||
* This constructor is only for use in the NetBeans editor window. The constructor
|
||||
* below that takes a {@link MoppyUI} as an argument should always be used.
|
||||
*/
|
||||
public FilterControls() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
public FilterControls(MoppyUI app) {
|
||||
this.app = app;
|
||||
|
||||
initComponents();
|
||||
filter = new NoteFilter();
|
||||
|
||||
loadSettings();
|
||||
updateFilter();
|
||||
}
|
||||
|
||||
public NoteFilter getNoteFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public void connected() {
|
||||
saveSettings();
|
||||
setControlsEnabled(false);
|
||||
}
|
||||
|
||||
public void disconnected() {
|
||||
filter.close();
|
||||
setControlsEnabled(true);
|
||||
}
|
||||
|
||||
private void loadSettings() {
|
||||
constrainCB.setSelected(app.prefs.getBoolean(Constants.PREF_FILTER_CONSTRAIN, false));
|
||||
ignoreTenCB.setSelected(app.prefs.getBoolean(Constants.PREF_FILTER_IGNORETEN, false));
|
||||
|
||||
updateFilter();
|
||||
}
|
||||
|
||||
private void saveSettings() {
|
||||
app.prefs.putBoolean(Constants.PREF_FILTER_CONSTRAIN, constrainCB.isSelected());
|
||||
app.prefs.putBoolean(Constants.PREF_FILTER_IGNORETEN, ignoreTenCB.isSelected());
|
||||
|
||||
app.savePreferences();
|
||||
}
|
||||
|
||||
private void updateFilter() {
|
||||
filter.setAutoConstrain(constrainCB.isSelected());
|
||||
filter.setIgnoreTen(ignoreTenCB.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
constrainCB = new javax.swing.JCheckBox();
|
||||
ignoreTenCB = new javax.swing.JCheckBox();
|
||||
|
||||
setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
setPreferredSize(new java.awt.Dimension(149, 149));
|
||||
|
||||
constrainCB.setText("Constrain Notes");
|
||||
constrainCB.setToolTipText("Automatically transposes notes outside of the floppy drive range into playable range.");
|
||||
constrainCB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
constrainCBActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
ignoreTenCB.setText("Ignore Channel 10");
|
||||
ignoreTenCB.setToolTipText("MIDI channel 10 is generally reserved for percussion instruments and is unlikely to render correctly on floppy drives.");
|
||||
ignoreTenCB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
ignoreTenCBActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(constrainCB)
|
||||
.addComponent(ignoreTenCB))
|
||||
.addContainerGap(49, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(constrainCB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(ignoreTenCB)
|
||||
.addContainerGap(91, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void constrainCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_constrainCBActionPerformed
|
||||
updateFilter();
|
||||
}//GEN-LAST:event_constrainCBActionPerformed
|
||||
|
||||
private void ignoreTenCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ignoreTenCBActionPerformed
|
||||
updateFilter();
|
||||
}//GEN-LAST:event_ignoreTenCBActionPerformed
|
||||
|
||||
|
||||
private void setControlsEnabled(boolean enabled){
|
||||
constrainCB.setEnabled(enabled);
|
||||
ignoreTenCB.setEnabled(enabled);
|
||||
}
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JCheckBox constrainCB;
|
||||
private javax.swing.JCheckBox ignoreTenCB;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
21
Java/MoppyDesk/src/moppydesk/ui/InputPanel.java
Normal file
21
Java/MoppyDesk/src/moppydesk/ui/InputPanel.java
Normal file
|
@ -0,0 +1,21 @@
|
|||
package moppydesk.ui;
|
||||
|
||||
import javax.sound.midi.Transmitter;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam
|
||||
*/
|
||||
public abstract class InputPanel extends JPanel{
|
||||
/** Returns the {@link Trasmitter} being controlled by this panel*/
|
||||
abstract Transmitter getTransmitter();
|
||||
/** Called when the outputs are connected to the input device*/
|
||||
abstract void connected();
|
||||
/** Called when the outputs are disconnected from the input device*/
|
||||
abstract void disconnected();
|
||||
|
||||
//MrSolidSnake745: Below two optional methods define how preferences are saved/loaded for a given input panel
|
||||
public void savePreferences() {}; //Called when connecting or switching panels on main window dropdown (MoppyControlWindow: , connect())
|
||||
public void loadPreferences() {}; //Called when main window class is instantiated (MoppyControlWindow: constructor)
|
||||
}
|
58
Java/MoppyDesk/src/moppydesk/ui/MIDIInControls.form
Normal file
58
Java/MoppyDesk/src/moppydesk/ui/MIDIInControls.form
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="midiInComboBox" min="-2" pref="187" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="241" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="midiInComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="184" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JComboBox" name="midiInComboBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new DefaultComboBoxModel(availableMIDIIns.keySet().toArray(new String[0]))" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="midiInComboBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="MIDI IN:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
99
Java/MoppyDesk/src/moppydesk/ui/MIDIInControls.java
Normal file
99
Java/MoppyDesk/src/moppydesk/ui/MIDIInControls.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
|
||||
package moppydesk.ui;
|
||||
|
||||
import moppydesk.inputs.MoppyMIDIInput;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.MidiDevice.Info;
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.sound.midi.Transmitter;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
|
||||
/**
|
||||
* Controls for the {@link MoppyMIDIInput} object.
|
||||
* @author Sam
|
||||
*/
|
||||
public class MIDIInControls extends InputPanel {
|
||||
|
||||
MoppyMIDIInput midiInput;
|
||||
HashMap<String,Info> availableMIDIIns = MoppyMIDIInput.getMIDIInInfos();
|
||||
|
||||
/**
|
||||
* Creates new form midiInControls
|
||||
*/
|
||||
public MIDIInControls(MoppyMIDIInput midiInput) {
|
||||
this.midiInput = midiInput;
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
midiInComboBox = new javax.swing.JComboBox();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
|
||||
midiInComboBox.setModel(new DefaultComboBoxModel(availableMIDIIns.keySet().toArray(new String[0])));
|
||||
midiInComboBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
midiInComboBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel1.setText("MIDI IN:");
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jLabel1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(midiInComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 187, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(241, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel1)
|
||||
.addComponent(midiInComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(184, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void midiInComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_midiInComboBoxActionPerformed
|
||||
try {
|
||||
midiInput.setDevice(availableMIDIIns.get(((JComboBox)evt.getSource()).getSelectedItem()));
|
||||
} catch (MidiUnavailableException ex) {
|
||||
Logger.getLogger(MIDIInControls.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}//GEN-LAST:event_midiInComboBoxActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JComboBox midiInComboBox;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
public Transmitter getTransmitter() {
|
||||
return midiInput;
|
||||
}
|
||||
|
||||
public void connected() {
|
||||
//Nothing to do;
|
||||
}
|
||||
|
||||
public void disconnected() {
|
||||
midiInput.setReceiver(null); // Clear out receiver so that MIDI messages aren't sent anywhere.
|
||||
}
|
||||
}
|
186
Java/MoppyDesk/src/moppydesk/ui/MoppyControlWindow.form
Normal file
186
Java/MoppyDesk/src/moppydesk/ui/MoppyControlWindow.form
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="3"/>
|
||||
<Property name="title" type="java.lang.String" value="Moppy Control Application"/>
|
||||
<Property name="iconImage" type="java.awt.Image" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new javax.swing.ImageIcon(MoppyControlWindow.class.getResource("/moppydesk/ui/moppy_ico.png")).getImage()" type="code"/>
|
||||
</Property>
|
||||
<Property name="resizable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jSeparator1" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="inputSelectBox" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="493" max="-2" attributes="0"/>
|
||||
<Component id="connectButton" min="-2" pref="99" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="filterControls1" min="-2" pref="171" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="poolingControls1" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="mainInputPanel" min="-2" pref="529" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="mainOutputPanel" min="-2" pref="550" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="mainStatusLabel" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="inputSelectBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="mainOutputPanel" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="mainInputPanel" pref="0" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="poolingControls1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Component id="filterControls1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="connectButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jSeparator1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="mainStatusLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JSeparator" name="jSeparator1">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="mainStatusLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Loaded."/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Current status"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="mainInputPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[350, 400]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.JComboBox" name="inputSelectBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="3">
|
||||
<StringItem index="0" value="MIDI File"/>
|
||||
<StringItem index="1" value="MIDI IN Port"/>
|
||||
<StringItem index="2" value="Playlist"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="inputSelectBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Input Mode"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="mainOutputPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[350, 400]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||
<Property name="axis" type="int" value="1"/>
|
||||
</Layout>
|
||||
</Container>
|
||||
<Component class="javax.swing.JButton" name="connectButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Connect"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Saves current output settings and connects as specified."/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="connectButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="moppydesk.ui.PoolingControls" name="poolingControls1">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new PoolingControls(app);"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="moppydesk.ui.FilterControls" name="filterControls1">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new FilterControls(app);"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
343
Java/MoppyDesk/src/moppydesk/ui/MoppyControlWindow.java
Normal file
343
Java/MoppyDesk/src/moppydesk/ui/MoppyControlWindow.java
Normal file
|
@ -0,0 +1,343 @@
|
|||
package moppydesk.ui;
|
||||
|
||||
import moppydesk.outputs.MoppyMIDIOutput;
|
||||
import moppydesk.outputs.MoppyCOMBridge;
|
||||
import moppydesk.outputs.MoppyPlayerOutput;
|
||||
import gnu.io.NoSuchPortException;
|
||||
import gnu.io.PortInUseException;
|
||||
import gnu.io.UnsupportedCommOperationException;
|
||||
import java.awt.Component;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.MidiDevice.Info;
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.swing.JOptionPane;
|
||||
import moppydesk.*;
|
||||
import moppydesk.outputs.MoppyReceiver;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class MoppyControlWindow extends javax.swing.JFrame {
|
||||
|
||||
MoppyUI app;
|
||||
HashMap<String, Info> availableMIDIOuts;
|
||||
OutputSetting[] outputSettings = new OutputSetting[Constants.NUM_MIDI_CHANNELS];
|
||||
|
||||
HashMap<String,MoppyReceiver> outputPlayers = new HashMap<String, MoppyReceiver>();
|
||||
|
||||
MIDIInControls midiInControls;
|
||||
SequencerControls seqControls;
|
||||
PlaylistControls playControls;
|
||||
|
||||
InputPanel currentInputPanel;
|
||||
|
||||
/**
|
||||
* Creates new form MoppyControlWindow
|
||||
*/
|
||||
public MoppyControlWindow(MoppyUI app) {
|
||||
this.app = app;
|
||||
|
||||
midiInControls = new MIDIInControls(app.midiIn);
|
||||
seqControls = new SequencerControls(app, this, app.ms);
|
||||
playControls = new PlaylistControls(app, this, app.ms);
|
||||
|
||||
availableMIDIOuts = MoppyMIDIOutput.getMIDIOutInfos();
|
||||
loadOutputSettings();
|
||||
|
||||
initComponents();
|
||||
|
||||
updateInputPanel(); //Sammy1Am: Preferences will be loaded for the input panels in this call
|
||||
setupOutputControls();
|
||||
}
|
||||
|
||||
private void loadOutputSettings() {
|
||||
OutputSetting[] os = (OutputSetting[]) app.getPreferenceObject(Constants.PREF_OUTPUT_SETTINGS);
|
||||
if (os == null) {
|
||||
for (int i = 1; i <= 16; i++) {
|
||||
outputSettings[i - 1] = new OutputSetting(i);
|
||||
}
|
||||
app.putPreferenceObject(Constants.PREF_OUTPUT_SETTINGS, outputSettings);
|
||||
} else {
|
||||
outputSettings = os;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupOutputControls() {
|
||||
|
||||
|
||||
for (OutputSetting s : outputSettings) {
|
||||
ChannelOutControl newControl = new ChannelOutControl(this, s);
|
||||
//TODO Read in preferences here? Serialize all properties to preferences?
|
||||
mainOutputPanel.add(newControl);
|
||||
}
|
||||
mainOutputPanel.revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
jSeparator1 = new javax.swing.JSeparator();
|
||||
mainStatusLabel = new javax.swing.JLabel();
|
||||
mainInputPanel = new javax.swing.JPanel();
|
||||
inputSelectBox = new javax.swing.JComboBox();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
mainOutputPanel = new javax.swing.JPanel();
|
||||
connectButton = new javax.swing.JButton();
|
||||
poolingControls1 = new PoolingControls(app);
|
||||
filterControls1 = new FilterControls(app);
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
||||
setTitle("Moppy Control Application");
|
||||
setIconImage(new javax.swing.ImageIcon(MoppyControlWindow.class.getResource("/moppydesk/ui/moppy_ico.png")).getImage());
|
||||
setResizable(false);
|
||||
|
||||
mainStatusLabel.setText("Loaded.");
|
||||
mainStatusLabel.setToolTipText("Current status");
|
||||
|
||||
mainInputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
mainInputPanel.setPreferredSize(new java.awt.Dimension(350, 400));
|
||||
|
||||
inputSelectBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "MIDI File", "MIDI IN Port", "Playlist" }));
|
||||
inputSelectBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
inputSelectBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel1.setText("Input Mode");
|
||||
|
||||
mainOutputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
mainOutputPanel.setPreferredSize(new java.awt.Dimension(350, 400));
|
||||
mainOutputPanel.setLayout(new javax.swing.BoxLayout(mainOutputPanel, javax.swing.BoxLayout.Y_AXIS));
|
||||
|
||||
connectButton.setText("Connect");
|
||||
connectButton.setToolTipText("Saves current output settings and connects as specified.");
|
||||
connectButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
connectButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jSeparator1)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jLabel1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(inputSelectBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(493, 493, 493)
|
||||
.addComponent(connectButton, javax.swing.GroupLayout.PREFERRED_SIZE, 99, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(filterControls1, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(poolingControls1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
|
||||
.addComponent(mainInputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 529, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(mainOutputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 550, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(mainStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(8, 8, 8)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(inputSelectBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabel1))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(mainOutputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(mainInputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(poolingControls1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(6, 6, 6)
|
||||
.addComponent(filterControls1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(connectButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(mainStatusLabel)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void connect() {
|
||||
try {
|
||||
|
||||
//Let the control pannels know they're connected.
|
||||
currentInputPanel.connected();
|
||||
poolingControls1.connected();
|
||||
filterControls1.connected();
|
||||
|
||||
//Disable and save output settings...
|
||||
for (Component c : mainOutputPanel.getComponents()){
|
||||
if (c instanceof ChannelOutControl){
|
||||
((ChannelOutControl)c).lockControl();
|
||||
}
|
||||
}
|
||||
app.putPreferenceObject(Constants.PREF_OUTPUT_SETTINGS, outputSettings);
|
||||
app.savePreferences();
|
||||
|
||||
//MrSolidSnake745: Tell the current input panel to save it's preferences
|
||||
currentInputPanel.savePreferences();
|
||||
|
||||
setStatus("Initializing Receivers...");
|
||||
initializeReceivers();
|
||||
|
||||
//If pooling is enabled, send messages through pooler, otherwise bypass it
|
||||
inputSelectBox.setEnabled(false);
|
||||
|
||||
// Always connect to the note filter
|
||||
currentInputPanel.getTransmitter().setReceiver(filterControls1.getNoteFilter());
|
||||
|
||||
// Only connect to pooling if it's enabled.
|
||||
if (poolingControls1.isPoolingEnabled()){
|
||||
filterControls1.getNoteFilter().setReceiver(poolingControls1.getDrivePooler());
|
||||
poolingControls1.getDrivePooler().setReceiver(app.rm);
|
||||
} else {
|
||||
filterControls1.getNoteFilter().setReceiver(app.rm);
|
||||
}
|
||||
|
||||
|
||||
|
||||
connectButton.setText("Disconnect");
|
||||
setStatus("Connected.");
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MoppyControlWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
JOptionPane.showMessageDialog(rootPane, ex.toString(),ex.getMessage(),JOptionPane.ERROR_MESSAGE);
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void disconnect() {
|
||||
setStatus("Disconnecting...");
|
||||
app.rm.close();
|
||||
currentInputPanel.disconnected();
|
||||
poolingControls1.disconnected();
|
||||
filterControls1.disconnected();
|
||||
|
||||
//Reenable output settings
|
||||
for (Component c : mainOutputPanel.getComponents()){
|
||||
if (c instanceof ChannelOutControl){
|
||||
((ChannelOutControl)c).unlockControl();
|
||||
}
|
||||
}
|
||||
|
||||
inputSelectBox.setEnabled(true);
|
||||
connectButton.setText("Connect");
|
||||
setStatus("Disconnected.");
|
||||
}
|
||||
|
||||
private void initializeReceivers() throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException, IOException, MidiUnavailableException {
|
||||
app.rm.clearReceivers();
|
||||
|
||||
outputPlayers.clear();
|
||||
|
||||
for (int ch = 1; ch <= 16; ch++) {
|
||||
OutputSetting os = outputSettings[ch-1]; //OutputSettings are 0-indexed
|
||||
if (os.enabled) {
|
||||
// MoppyPlayer/Receivers are grouped by COM port
|
||||
if (os.type.equals(OutputSetting.OutputType.MOPPY)) {
|
||||
if (!outputPlayers.containsKey(os.comPort)){
|
||||
outputPlayers.put(os.comPort, new MoppyPlayerOutput(new MoppyCOMBridge(os.comPort)));
|
||||
}
|
||||
app.rm.setReceiver(ch, outputPlayers.get(os.comPort));
|
||||
}
|
||||
//MIDIPlayer/Receivers are grouped by MIDI output name
|
||||
else if (os.type.equals(OutputSetting.OutputType.MIDI)) {
|
||||
if (!outputPlayers.containsKey(os.midiDeviceName)){
|
||||
outputPlayers.put(os.midiDeviceName, new MoppyMIDIOutput(os.midiDeviceName));
|
||||
}
|
||||
app.rm.setReceiver(ch, outputPlayers.get(os.midiDeviceName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateInputPanel(){
|
||||
if (currentInputPanel != null) { //Panel is only null on initial load, also helps prevent unecessary preference saving
|
||||
currentInputPanel.savePreferences(); //Tell the current panel to save preferences before switching
|
||||
//MrSolidSnake745: Necessary after implementing sequenceEnded event and having multiple input panels
|
||||
//Without removing listener, sequenceEnded can fire on all panels implementing MoppyStatusConsumer even if they are not the current input panel
|
||||
//Applies to all events defined through MoppyStatusConsumer
|
||||
if (currentInputPanel instanceof MoppyStatusConsumer) app.ms.removeListener((MoppyStatusConsumer) currentInputPanel);
|
||||
}
|
||||
mainInputPanel.removeAll();
|
||||
switch(inputSelectBox.getSelectedIndex())
|
||||
{
|
||||
case 0: currentInputPanel = seqControls; break; //MIDI File
|
||||
case 1: currentInputPanel = midiInControls; break; //MIDI In
|
||||
case 2: currentInputPanel = playControls; break; //Playlist
|
||||
}
|
||||
//Adding listener back for the selected panel if it implements MoppyStatusConsumer
|
||||
if (currentInputPanel instanceof MoppyStatusConsumer) app.ms.addListener((MoppyStatusConsumer) currentInputPanel);
|
||||
|
||||
//Before adding the panel to the mainUI, load its preferences (in case something has been changed (e.g. by another input panel)
|
||||
currentInputPanel.loadPreferences();
|
||||
|
||||
mainInputPanel.add(currentInputPanel);
|
||||
mainInputPanel.revalidate();
|
||||
mainInputPanel.repaint();
|
||||
}
|
||||
|
||||
private void connectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectButtonActionPerformed
|
||||
connectButton.setEnabled(false);
|
||||
if (connectButton.getText().equals("Connect")) {
|
||||
connect();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
connectButton.setEnabled(true);
|
||||
}//GEN-LAST:event_connectButtonActionPerformed
|
||||
|
||||
private void inputSelectBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_inputSelectBoxActionPerformed
|
||||
updateInputPanel();
|
||||
}//GEN-LAST:event_inputSelectBoxActionPerformed
|
||||
|
||||
public void setStatus(String newStatus) {
|
||||
mainStatusLabel.setText(newStatus);
|
||||
mainStatusLabel.repaint();
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton connectButton;
|
||||
private moppydesk.ui.FilterControls filterControls1;
|
||||
private javax.swing.JComboBox inputSelectBox;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JSeparator jSeparator1;
|
||||
private javax.swing.JPanel mainInputPanel;
|
||||
private javax.swing.JPanel mainOutputPanel;
|
||||
private javax.swing.JLabel mainStatusLabel;
|
||||
private moppydesk.ui.PoolingControls poolingControls1;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
371
Java/MoppyDesk/src/moppydesk/ui/PlaylistControls.form
Normal file
371
Java/MoppyDesk/src/moppydesk/ui/PlaylistControls.form
Normal file
|
@ -0,0 +1,371 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[529, 240]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 0]"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||
<Property name="opaque" type="boolean" value="false"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[524, 240]"/>
|
||||
</Property>
|
||||
<Property name="requestFocusEnabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="currentPositionLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="sequenceProgressSlider" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="totalPositionLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="loadListButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="saveListButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="randomizeButton" min="-2" pref="60" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="loadLastListCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="sequenceNameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="bpmLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="playlistScrollPane" min="-2" pref="425" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="loadButton" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="resetDrivesCheckbox" alignment="1" pref="87" max="32767" attributes="0"/>
|
||||
<Component id="loadDirectoryButton" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="clearButton" max="32767" attributes="0"/>
|
||||
<Component id="resetListButton" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="loadButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="loadDirectoryButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="resetListButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="clearButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="resetDrivesCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="playlistScrollPane" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="loadListButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="saveListButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="randomizeButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="loadLastListCheckbox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="jPanel1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="20" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="sequenceNameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="sequenceProgressSlider" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="bpmLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="currentPositionLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="totalPositionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="sequenceNameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="<None loaded>"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="bpmLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code=""? bpm"" type="code"/>
|
||||
</Property>
|
||||
<Property name="alignmentX" type="float" value="1.0"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="PlaylistControls_bpmLabel"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="clearButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Clear List"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="clearButtonstopResetClicked"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="loadButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="label" type="java.lang.String" value="Load MIDI"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="loadButtonloadSequence"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSlider" name="sequenceProgressSlider">
|
||||
<Properties>
|
||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
||||
<Property name="value" type="int" value="0"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseDragged" listener="java.awt.event.MouseMotionListener" parameters="java.awt.event.MouseEvent" handler="sequenceProgressDragged"/>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="sequenceProgressDragged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="currentPositionLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="00:00"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="totalPositionLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="00:00"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="resetListButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Reset List"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="resetListButtonstopResetClicked"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="resetDrivesCheckbox">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Reset drives"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="If selected, will reset the drives to the intial position between songs"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="resetDrivesCheckboxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="loadListButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Load List"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="loadListButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="saveListButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Save List"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="saveListButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JScrollPane" name="playlistScrollPane">
|
||||
<AuxValues>
|
||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTable" name="playlistTable">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
|
||||
<Table columnCount="0" rowCount="0"/>
|
||||
</Property>
|
||||
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
|
||||
<TableColumnModel selectionModel="0"/>
|
||||
</Property>
|
||||
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
|
||||
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="jPanel1">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="previousButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="◄◄"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Previous"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="previousButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="startButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value=" ► "/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Start/Pause"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 3, 2, 3]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="startButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="stopButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="■"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Stop/Reset - Click while stopped to reset drives"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 7, 2, 7]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="stopButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="nextButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="►►"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Next"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="nextButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JButton" name="loadDirectoryButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Load Directory"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="loadDirectoryButtonloadSequence"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="randomizeButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Randomize"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 2, 2, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="randomizeButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="loadLastListCheckbox">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Load last MPL on startup"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="If selected, will load the last successfully loaded MPL file"/>
|
||||
<Property name="actionCommand" type="java.lang.String" value="Load last MPL on startup"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="loadLastListCheckboxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
702
Java/MoppyDesk/src/moppydesk/ui/PlaylistControls.java
Normal file
702
Java/MoppyDesk/src/moppydesk/ui/PlaylistControls.java
Normal file
|
@ -0,0 +1,702 @@
|
|||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moppydesk.ui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.Transmitter;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import moppydesk.Constants;
|
||||
import moppydesk.MoppyStatusConsumer;
|
||||
import moppydesk.MoppyUI;
|
||||
import moppydesk.inputs.MoppySequencer;
|
||||
import moppydesk.playlist.MoppyPlaylist;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam/AJ (MrSolidSnake745)
|
||||
*
|
||||
*/
|
||||
|
||||
public class PlaylistControls extends InputPanel implements MoppyStatusConsumer {
|
||||
|
||||
MoppySequencer seq;
|
||||
MoppyControlWindow controlWindow;
|
||||
MoppyUI app;
|
||||
final JFileChooser sequenceChooser = new JFileChooser();
|
||||
final FileNameExtensionFilter MIDIFilter = new FileNameExtensionFilter("MIDI Files (*.mid, *.midi)", "mid", "midi");
|
||||
final FileNameExtensionFilter MPLFilter = new FileNameExtensionFilter("Moppy Playlist Files", "mpl");
|
||||
Timer progressTimer;
|
||||
private boolean isConnected = false;
|
||||
private boolean fileLoaded = false;
|
||||
private boolean interruptNextSong = false;
|
||||
MoppyPlaylist playlist = new MoppyPlaylist();
|
||||
|
||||
/**
|
||||
* Creates new form PlaylistControls
|
||||
*/
|
||||
public PlaylistControls(MoppyUI app, MoppyControlWindow mcw, MoppySequencer newSequencer) {
|
||||
this.seq = newSequencer;
|
||||
this.app = app;
|
||||
this.controlWindow = mcw;
|
||||
|
||||
initComponents();
|
||||
|
||||
progressTimer = new Timer(1000, new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
updateProgressDisplay();
|
||||
}
|
||||
});
|
||||
|
||||
setupPlaylistTable();
|
||||
sequenceChooser.addChoosableFileFilter(MIDIFilter);
|
||||
sequenceChooser.addChoosableFileFilter(MPLFilter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void savePreferences() {
|
||||
//Nothing to do here! All prefs are saved upon UI actions currently
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPreferences() {
|
||||
loadLastListCheckbox.setSelected(app.prefs.getBoolean(Constants.PREF_LOAD_MPL_ON_START, false));
|
||||
String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_MPL, null);
|
||||
if (previouslyLoaded != null && !previouslyLoaded.isEmpty() && loadLastListCheckbox.isSelected()) {
|
||||
//Try to load the last MPL, if it fails, clear out the preference
|
||||
if (!loadPlaylist(new File(previouslyLoaded))) { app.prefs.put(Constants.PREF_LOADED_MPL, ""); }
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgressDisplay() {
|
||||
long currentSeconds = seq.getSecondsPosition();
|
||||
sequenceProgressSlider.setValue((int) (currentSeconds));
|
||||
String currentPosition = String.format("%d:%02d",
|
||||
TimeUnit.SECONDS.toMinutes(currentSeconds),
|
||||
currentSeconds % 60);
|
||||
String totalPosition = String.format("%d:%02d",
|
||||
TimeUnit.SECONDS.toMinutes(seq.getSecondsLength()),
|
||||
seq.getSecondsLength() % 60);
|
||||
currentPositionLabel.setText(currentPosition);
|
||||
totalPositionLabel.setText(totalPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
sequenceNameLabel = new javax.swing.JLabel();
|
||||
bpmLabel = new javax.swing.JLabel();
|
||||
clearButton = new javax.swing.JButton();
|
||||
loadButton = new javax.swing.JButton();
|
||||
sequenceProgressSlider = new javax.swing.JSlider();
|
||||
currentPositionLabel = new javax.swing.JLabel();
|
||||
totalPositionLabel = new javax.swing.JLabel();
|
||||
resetListButton = new javax.swing.JButton();
|
||||
resetDrivesCheckbox = new javax.swing.JCheckBox();
|
||||
loadListButton = new javax.swing.JButton();
|
||||
saveListButton = new javax.swing.JButton();
|
||||
playlistScrollPane = new javax.swing.JScrollPane();
|
||||
playlistTable = new javax.swing.JTable();
|
||||
jPanel1 = new javax.swing.JPanel();
|
||||
previousButton = new javax.swing.JButton();
|
||||
startButton = new javax.swing.JButton();
|
||||
stopButton = new javax.swing.JButton();
|
||||
nextButton = new javax.swing.JButton();
|
||||
loadDirectoryButton = new javax.swing.JButton();
|
||||
randomizeButton = new javax.swing.JButton();
|
||||
loadLastListCheckbox = new javax.swing.JCheckBox();
|
||||
|
||||
setMaximumSize(new java.awt.Dimension(529, 240));
|
||||
setMinimumSize(new java.awt.Dimension(0, 0));
|
||||
setName(""); // NOI18N
|
||||
setOpaque(false);
|
||||
setPreferredSize(new java.awt.Dimension(524, 240));
|
||||
setRequestFocusEnabled(false);
|
||||
|
||||
sequenceNameLabel.setText("<None loaded>");
|
||||
|
||||
bpmLabel.setText("? bpm");
|
||||
bpmLabel.setAlignmentX(1.0F);
|
||||
|
||||
clearButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
clearButton.setText("Clear List");
|
||||
clearButton.setToolTipText("");
|
||||
clearButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
clearButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
clearButtonstopResetClicked(evt);
|
||||
}
|
||||
});
|
||||
|
||||
loadButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
loadButton.setLabel("Load MIDI");
|
||||
loadButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
loadButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
loadButtonloadSequence(evt);
|
||||
}
|
||||
});
|
||||
|
||||
sequenceProgressSlider.setToolTipText("");
|
||||
sequenceProgressSlider.setValue(0);
|
||||
sequenceProgressSlider.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
|
||||
public void mouseDragged(java.awt.event.MouseEvent evt) {
|
||||
sequenceProgressDragged(evt);
|
||||
}
|
||||
});
|
||||
sequenceProgressSlider.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||
public void mouseClicked(java.awt.event.MouseEvent evt) {
|
||||
sequenceProgressDragged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
currentPositionLabel.setText("00:00");
|
||||
|
||||
totalPositionLabel.setText("00:00");
|
||||
|
||||
resetListButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
resetListButton.setText("Reset List");
|
||||
resetListButton.setToolTipText("");
|
||||
resetListButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
resetListButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
resetListButtonstopResetClicked(evt);
|
||||
}
|
||||
});
|
||||
|
||||
resetDrivesCheckbox.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
resetDrivesCheckbox.setText("Reset drives");
|
||||
resetDrivesCheckbox.setToolTipText("If selected, will reset the drives to the intial position between songs");
|
||||
resetDrivesCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
resetDrivesCheckboxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
loadListButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
loadListButton.setText("Load List");
|
||||
loadListButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
loadListButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
loadListButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
saveListButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
saveListButton.setText("Save List");
|
||||
saveListButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
saveListButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
saveListButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
playlistTable.setModel(new javax.swing.table.DefaultTableModel(
|
||||
new Object [][] {
|
||||
|
||||
},
|
||||
new String [] {
|
||||
|
||||
}
|
||||
));
|
||||
playlistTable.getTableHeader().setReorderingAllowed(false);
|
||||
playlistScrollPane.setViewportView(playlistTable);
|
||||
|
||||
previousButton.setText("◄◄");
|
||||
previousButton.setToolTipText("Previous");
|
||||
previousButton.setEnabled(false);
|
||||
previousButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
previousButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
previousButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
jPanel1.add(previousButton);
|
||||
|
||||
startButton.setText(" ► ");
|
||||
startButton.setToolTipText("Start/Pause");
|
||||
startButton.setEnabled(false);
|
||||
startButton.setMargin(new java.awt.Insets(2, 3, 2, 3));
|
||||
startButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
startButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
jPanel1.add(startButton);
|
||||
|
||||
stopButton.setText("■");
|
||||
stopButton.setToolTipText("Stop/Reset - Click while stopped to reset drives");
|
||||
stopButton.setMargin(new java.awt.Insets(2, 7, 2, 7));
|
||||
stopButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
stopButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
jPanel1.add(stopButton);
|
||||
|
||||
nextButton.setText("►►");
|
||||
nextButton.setToolTipText("Next");
|
||||
nextButton.setEnabled(false);
|
||||
nextButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
nextButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
nextButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
jPanel1.add(nextButton);
|
||||
|
||||
loadDirectoryButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
loadDirectoryButton.setText("Load Directory");
|
||||
loadDirectoryButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
loadDirectoryButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
loadDirectoryButtonloadSequence(evt);
|
||||
}
|
||||
});
|
||||
|
||||
randomizeButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
randomizeButton.setText("Randomize");
|
||||
randomizeButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
randomizeButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
randomizeButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
loadLastListCheckbox.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||
loadLastListCheckbox.setText("Load last MPL on startup");
|
||||
loadLastListCheckbox.setToolTipText("If selected, will load the last successfully loaded MPL file");
|
||||
loadLastListCheckbox.setActionCommand("Load last MPL on startup");
|
||||
loadLastListCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
loadLastListCheckboxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(2, 2, 2)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(currentPositionLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(sequenceProgressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(totalPositionLabel))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(loadListButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(saveListButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(randomizeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(loadLastListCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(sequenceNameLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(bpmLabel))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(playlistScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 425, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(2, 2, 2)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(loadButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(resetDrivesCheckbox, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 87, Short.MAX_VALUE)
|
||||
.addComponent(loadDirectoryButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
|
||||
.addComponent(clearButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(resetListButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
||||
.addGap(2, 2, 2))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(2, 2, 2)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(loadButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(loadDirectoryButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(resetListButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(clearButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(resetDrivesCheckbox))
|
||||
.addComponent(playlistScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(loadListButton)
|
||||
.addComponent(saveListButton)
|
||||
.addComponent(randomizeButton)
|
||||
.addComponent(loadLastListCheckbox))
|
||||
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 20, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(sequenceNameLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(sequenceProgressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(bpmLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(currentPositionLabel)
|
||||
.addComponent(totalPositionLabel))))
|
||||
.addContainerGap())
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void playSequencer() {
|
||||
if(!(fileLoaded) && !(playlist.isFinished())) {
|
||||
loadSequenceFile(playlist.getNextSong());
|
||||
}
|
||||
seq.startSequencer();
|
||||
controlWindow.setStatus("Playing!");
|
||||
startButton.setText("▐ ▌");
|
||||
}
|
||||
|
||||
private void pauseSequencer() {
|
||||
seq.stopSequencer();
|
||||
startButton.setText(" ► ");
|
||||
controlWindow.setStatus("...Paused");
|
||||
}
|
||||
|
||||
private void stopResetSequencer() {
|
||||
if (seq.isRunning()) {
|
||||
controlWindow.setStatus("Stopping...");
|
||||
seq.stopSequencer();
|
||||
seq.resetSequencer();
|
||||
startButton.setText(" ► ");
|
||||
controlWindow.setStatus("Stopped.");
|
||||
} else {
|
||||
app.rm.reset();
|
||||
controlWindow.setStatus("Reset.");
|
||||
}
|
||||
}
|
||||
|
||||
private void clearButtonstopResetClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonstopResetClicked
|
||||
clearPlaylist();
|
||||
}//GEN-LAST:event_clearButtonstopResetClicked
|
||||
|
||||
private void loadButtonloadSequence(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadButtonloadSequence
|
||||
String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_LIST, null);
|
||||
if (previouslyLoaded != null) {
|
||||
sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
|
||||
}
|
||||
sequenceChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
sequenceChooser.setFileFilter(MIDIFilter);
|
||||
int returnVal = sequenceChooser.showOpenDialog(this);
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
app.prefs.put(Constants.PREF_LOADED_LIST, sequenceChooser.getSelectedFile().getPath());
|
||||
playlist.addSong(sequenceChooser.getSelectedFile());
|
||||
|
||||
if (isConnected && !(playlist.isFinished())) {
|
||||
startButton.setEnabled(true);
|
||||
}
|
||||
} else {
|
||||
//Cancelled
|
||||
}
|
||||
}//GEN-LAST:event_loadButtonloadSequence
|
||||
|
||||
private void sequenceProgressDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_sequenceProgressDragged
|
||||
int seconds = ((JSlider) evt.getSource()).getValue();
|
||||
seq.setSecondsPosition(seconds);
|
||||
currentPositionLabel.setText(String.format("%d:%02d",
|
||||
TimeUnit.SECONDS.toMinutes(seconds),
|
||||
seconds % 60));
|
||||
}//GEN-LAST:event_sequenceProgressDragged
|
||||
|
||||
private void resetListButtonstopResetClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetListButtonstopResetClicked
|
||||
resetPlaylist();
|
||||
}//GEN-LAST:event_resetListButtonstopResetClicked
|
||||
|
||||
private void loadListButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadListButtonActionPerformed
|
||||
loadPlaylist(getPlaylistFile(true));
|
||||
}//GEN-LAST:event_loadListButtonActionPerformed
|
||||
|
||||
private void saveListButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveListButtonActionPerformed
|
||||
savePlaylist(getPlaylistFile(false));
|
||||
}//GEN-LAST:event_saveListButtonActionPerformed
|
||||
|
||||
private void resetDrivesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetDrivesCheckboxActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_resetDrivesCheckboxActionPerformed
|
||||
|
||||
private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonActionPerformed
|
||||
if (startButton.getText().equals(" ► ")) {
|
||||
interruptNextSong = false;
|
||||
playSequencer();
|
||||
} else {
|
||||
pauseSequencer();
|
||||
}
|
||||
}//GEN-LAST:event_startButtonActionPerformed
|
||||
|
||||
private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
|
||||
stopResetSequencer();
|
||||
}//GEN-LAST:event_stopButtonActionPerformed
|
||||
|
||||
private void nextButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextButtonActionPerformed
|
||||
if(!playlist.isLastSong()) {
|
||||
try {
|
||||
loadSequenceFile(playlist.getNextSong());
|
||||
if(isConnected) {Thread.sleep(1000); playSequencer();}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(PlaylistControls.class.getName()).log(Level.SEVERE, null, ex);
|
||||
controlWindow.setStatus("Error playing next song!");
|
||||
JOptionPane.showMessageDialog(this.getRootPane(), ex);
|
||||
}
|
||||
}
|
||||
}//GEN-LAST:event_nextButtonActionPerformed
|
||||
|
||||
private void previousButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previousButtonActionPerformed
|
||||
if(!playlist.isFirstSong()) {
|
||||
try {
|
||||
loadSequenceFile(playlist.getPreviousSong());
|
||||
if(isConnected) {Thread.sleep(1000); playSequencer();}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(PlaylistControls.class.getName()).log(Level.SEVERE, null, ex);
|
||||
controlWindow.setStatus("Error playing previous song!");
|
||||
JOptionPane.showMessageDialog(this.getRootPane(), ex);
|
||||
}
|
||||
}
|
||||
}//GEN-LAST:event_previousButtonActionPerformed
|
||||
|
||||
private void loadDirectoryButtonloadSequence(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadDirectoryButtonloadSequence
|
||||
String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_LIST, null);
|
||||
if (previouslyLoaded != null) {
|
||||
sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
|
||||
}
|
||||
|
||||
sequenceChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
sequenceChooser.setFileFilter(sequenceChooser.getAcceptAllFileFilter());
|
||||
int returnVal = sequenceChooser.showOpenDialog(this);
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
app.prefs.put(Constants.PREF_LOADED_LIST, sequenceChooser.getSelectedFile().getPath());
|
||||
for (File file : sequenceChooser.getSelectedFile().listFiles()) {
|
||||
String extension = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length());
|
||||
if("mid".equals(extension) || "midi".equals(extension)) {playlist.addSong(file);}
|
||||
}
|
||||
|
||||
sequenceChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
if (isConnected && !(playlist.isFinished())) {startButton.setEnabled(true);}
|
||||
} else {
|
||||
//Cancelled
|
||||
}
|
||||
sequenceChooser.setAcceptAllFileFilterUsed(true);
|
||||
}//GEN-LAST:event_loadDirectoryButtonloadSequence
|
||||
|
||||
private void randomizeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_randomizeButtonActionPerformed
|
||||
playlist.randomize();
|
||||
}//GEN-LAST:event_randomizeButtonActionPerformed
|
||||
|
||||
private void loadLastListCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadLastListCheckboxActionPerformed
|
||||
app.prefs.putBoolean(Constants.PREF_LOAD_MPL_ON_START, loadLastListCheckbox.isSelected());
|
||||
}//GEN-LAST:event_loadLastListCheckboxActionPerformed
|
||||
|
||||
@Override
|
||||
public void tempoChanged(int newTempo) {
|
||||
bpmLabel.setText(newTempo + " bpm");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sequenceEnded() {
|
||||
try {
|
||||
playlist.currentSongFinished();
|
||||
if (!(playlist.isFinished())) {
|
||||
loadSequenceFile(playlist.getNextSong());
|
||||
if(resetDrivesCheckbox.isSelected()) {Thread.sleep(500); app.rm.reset(); Thread.sleep(500);}
|
||||
Thread.sleep(3000);
|
||||
if(interruptNextSong) {interruptNextSong = false;}
|
||||
else {playSequencer();}
|
||||
}
|
||||
else {
|
||||
playlistEnded();
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Logger.getLogger(MoppyControlWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
controlWindow.setStatus("Error playing next song!");
|
||||
JOptionPane.showMessageDialog(this.getRootPane(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSequenceFile(File sequenceFile) {
|
||||
try {
|
||||
controlWindow.setStatus("Loading file...");
|
||||
seq.loadFile(sequenceFile.getPath());
|
||||
sequenceNameLabel.setText(playlist.getCurrentSongName());
|
||||
sequenceProgressSlider.setMaximum((int) (seq.getSecondsLength()));
|
||||
controlWindow.setStatus("Loaded " + sequenceFile.getName());
|
||||
updateProgressDisplay();
|
||||
fileLoaded = true;
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MoppyControlWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
controlWindow.setStatus("File loading error!");
|
||||
JOptionPane.showMessageDialog(this.getRootPane(), ex);
|
||||
fileLoaded = false;
|
||||
}
|
||||
enableNextPrev();
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel bpmLabel;
|
||||
private javax.swing.JButton clearButton;
|
||||
private javax.swing.JLabel currentPositionLabel;
|
||||
private javax.swing.JPanel jPanel1;
|
||||
private javax.swing.JButton loadButton;
|
||||
private javax.swing.JButton loadDirectoryButton;
|
||||
private javax.swing.JCheckBox loadLastListCheckbox;
|
||||
private javax.swing.JButton loadListButton;
|
||||
private javax.swing.JButton nextButton;
|
||||
private javax.swing.JScrollPane playlistScrollPane;
|
||||
private javax.swing.JTable playlistTable;
|
||||
private javax.swing.JButton previousButton;
|
||||
private javax.swing.JButton randomizeButton;
|
||||
private javax.swing.JCheckBox resetDrivesCheckbox;
|
||||
private javax.swing.JButton resetListButton;
|
||||
private javax.swing.JButton saveListButton;
|
||||
private javax.swing.JLabel sequenceNameLabel;
|
||||
private javax.swing.JSlider sequenceProgressSlider;
|
||||
private javax.swing.JButton startButton;
|
||||
private javax.swing.JButton stopButton;
|
||||
private javax.swing.JLabel totalPositionLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@Override
|
||||
public Transmitter getTransmitter() {
|
||||
return seq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected() {
|
||||
progressTimer.start();
|
||||
isConnected = true;
|
||||
if (!(playlist.isFinished())) {startButton.setEnabled(true);}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected() {
|
||||
startButton.setEnabled(false);
|
||||
pauseSequencer();
|
||||
isConnected = false;
|
||||
progressTimer.stop();
|
||||
seq.setReceiver(null); //Clear receiver so there's no connection here.
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="Playlist specific functions">
|
||||
|
||||
private void enableNextPrev() {
|
||||
previousButton.setEnabled(!playlist.isFirstSong());
|
||||
nextButton.setEnabled(!playlist.isLastSong());
|
||||
}
|
||||
|
||||
private void playlistEnded() {
|
||||
interruptNextSong = false;
|
||||
controlWindow.setStatus("Stopping...");
|
||||
seq.resetSequencer();
|
||||
startButton.setText(" ► ");
|
||||
startButton.setEnabled(false);
|
||||
sequenceProgressSlider.setValue(0);
|
||||
fileLoaded = false;
|
||||
controlWindow.setStatus("Stopped.");
|
||||
}
|
||||
|
||||
private void clearPlaylist() {
|
||||
interruptNextSong = true;
|
||||
if (seq.isRunning()) {stopResetSequencer();} //I know this seems redundant, but I did not want to rewrite code and only wanted that part of the function
|
||||
playlist.clear();
|
||||
playlistEnded();
|
||||
if (isConnected) {startButton.setEnabled(true);}
|
||||
}
|
||||
|
||||
private void resetPlaylist() {
|
||||
interruptNextSong = true;
|
||||
if (seq.isRunning()) {stopResetSequencer();} //Same as above comment
|
||||
playlist.reset();
|
||||
playlistEnded();
|
||||
if (isConnected) {startButton.setEnabled(true);}
|
||||
}
|
||||
|
||||
private File getPlaylistFile(boolean direction) {
|
||||
String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_LIST, null);
|
||||
|
||||
if (previouslyLoaded != null) {
|
||||
sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
|
||||
}
|
||||
sequenceChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
sequenceChooser.setFileFilter(MPLFilter);
|
||||
|
||||
int returnVal;
|
||||
if(direction) {returnVal = sequenceChooser.showOpenDialog(this);}
|
||||
else {returnVal = sequenceChooser.showSaveDialog(this);}
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
File returnFile = sequenceChooser.getSelectedFile();
|
||||
app.prefs.put(Constants.PREF_LOADED_LIST, sequenceChooser.getSelectedFile().getPath());
|
||||
if(!direction) { //Make sure file ends in appropriate extension
|
||||
if(!returnFile.getAbsolutePath().endsWith(".mpl")) {returnFile = new File(sequenceChooser.getSelectedFile() + ".mpl");}
|
||||
}
|
||||
return returnFile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean savePlaylist(File f) {
|
||||
if(playlist.savePlaylistFile(f)) {}
|
||||
else {return false;}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean loadPlaylist(File f) {
|
||||
if(playlist.loadPlaylistFile(f)) {
|
||||
app.prefs.put(Constants.PREF_LOADED_MPL, f.getPath());
|
||||
if (isConnected && !playlist.isEmpty()) {startButton.setEnabled(true);}
|
||||
}
|
||||
else {return false;}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setupPlaylistTable() {
|
||||
playlistTable.setModel(playlist);
|
||||
playlistTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
TableColumnModel ColumnModel = playlistTable.getColumnModel();
|
||||
|
||||
ColumnModel.getColumn(0).setResizable(false);
|
||||
ColumnModel.getColumn(1).setResizable(false);
|
||||
|
||||
ColumnModel.getColumn(0).setPreferredWidth(25);
|
||||
ColumnModel.getColumn(0).setMaxWidth(25);
|
||||
ColumnModel.getColumn(1).setPreferredWidth(55);
|
||||
ColumnModel.getColumn(1).setMaxWidth(55);
|
||||
|
||||
}// </editor-fold>
|
||||
}
|
250
Java/MoppyDesk/src/moppydesk/ui/PoolingControls.form
Normal file
250
Java/MoppyDesk/src/moppydesk/ui/PoolingControls.form
Normal file
|
@ -0,0 +1,250 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<NonVisualComponents>
|
||||
<Component class="javax.swing.ButtonGroup" name="poolStratBG">
|
||||
</Component>
|
||||
</NonVisualComponents>
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[525, 149]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="enablePoolingCB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="poolingChannelPannel" min="-2" pref="211" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="poolStratPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="187" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="enablePoolingCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="poolingChannelPannel" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="poolStratPanel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JCheckBox" name="enablePoolingCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Enable Drive-Pooling"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="enablePoolingCBActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="poolingChannelPannel">
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="inputStartSpinner" min="-2" pref="41" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="inputEndSpinner" min="-2" pref="41" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="outputStartSpinner" min="-2" pref="41" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="outputEndSpinner" min="-2" pref="41" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="inputStartSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="inputEndSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="outputStartSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="outputEndSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Pool channels:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="inputStartSpinner">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
<SpinnerModel initial="1" maximum="16" minimum="1" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="poolingControlChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="inputEndSpinner">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
<SpinnerModel initial="1" maximum="16" minimum="1" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="poolingControlChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="outputStartSpinner">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
<SpinnerModel initial="1" maximum="16" minimum="1" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="poolingControlChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel2">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Into channels:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="outputEndSpinner">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
<SpinnerModel initial="1" maximum="16" minimum="1" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="poolingControlChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="poolStratPanel">
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="straightThroughRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="rndRbnRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="stkRB" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="straightThroughRB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="rndRbnRB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="stkRB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="15" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jLabel3">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Using strategy:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="straightThroughRB">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="poolStratBG"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Straight-Through"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Essentially does nothing. Mostly here for testing."/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="poolingStratChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="rndRbnRB">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="poolStratBG"/>
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" value="Round-Robin"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Outputs to each channel in a round-robin fashion, attempting to find empty channels first."/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="poolingStratChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="stkRB">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="poolStratBG"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Stacking"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Uses first available output channel (drops notes if all drives are busy)"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="poolingStratChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
337
Java/MoppyDesk/src/moppydesk/ui/PoolingControls.java
Normal file
337
Java/MoppyDesk/src/moppydesk/ui/PoolingControls.java
Normal file
|
@ -0,0 +1,337 @@
|
|||
package moppydesk.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.Enumeration;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JRadioButton;
|
||||
import moppydesk.Constants;
|
||||
import moppydesk.MoppyUI;
|
||||
import moppydesk.midputs.DrivePooler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class PoolingControls extends javax.swing.JPanel {
|
||||
|
||||
private DrivePooler pooler;
|
||||
private MoppyUI app;
|
||||
|
||||
/**
|
||||
* This constructor is only for use in the NetBeans editor window. The constructor
|
||||
* below that takes a {@link MoppyUI} as an argument should always be used.
|
||||
*/
|
||||
public PoolingControls() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
public PoolingControls(MoppyUI app) {
|
||||
this.app = app;
|
||||
|
||||
initComponents();
|
||||
pooler = new DrivePooler();
|
||||
|
||||
loadSettings();
|
||||
updatePooler();
|
||||
setControlsEnabled(enablePoolingCB.isSelected());
|
||||
}
|
||||
|
||||
public boolean isPoolingEnabled() {
|
||||
return enablePoolingCB.isSelected();
|
||||
}
|
||||
|
||||
public DrivePooler getDrivePooler() {
|
||||
return pooler;
|
||||
}
|
||||
|
||||
public void connected() {
|
||||
saveSettings();
|
||||
for (Component c : this.getComponents()) {
|
||||
c.setEnabled(false);
|
||||
setControlsEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnected() {
|
||||
pooler.close();
|
||||
for (Component c : this.getComponents()) {
|
||||
c.setEnabled(true);
|
||||
setControlsEnabled(enablePoolingCB.isSelected());
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSettings() {
|
||||
enablePoolingCB.setSelected(app.prefs.getBoolean(Constants.PREF_POOL_ENABLE, false));
|
||||
inputStartSpinner.setValue(app.prefs.getInt(Constants.PREF_POOL_FROM_START, 1));
|
||||
inputEndSpinner.setValue(app.prefs.getInt(Constants.PREF_POOL_FROM_END, 1));
|
||||
outputStartSpinner.setValue(app.prefs.getInt(Constants.PREF_POOL_TO_START, 1));
|
||||
outputEndSpinner.setValue(app.prefs.getInt(Constants.PREF_POOL_TO_END, 1));
|
||||
|
||||
switch (app.prefs.getInt(Constants.PREF_POOL_STRATEGY, 0)){
|
||||
case 0:
|
||||
straightThroughRB.setSelected(true);
|
||||
break;
|
||||
case 1:
|
||||
rndRbnRB.setSelected(true);
|
||||
break;
|
||||
case 2:
|
||||
stkRB.setSelected(true);
|
||||
break;
|
||||
}
|
||||
|
||||
updatePooler();
|
||||
}
|
||||
|
||||
private void saveSettings() {
|
||||
app.prefs.putBoolean(Constants.PREF_POOL_ENABLE, enablePoolingCB.isSelected());
|
||||
|
||||
app.prefs.putInt(Constants.PREF_POOL_FROM_START, (Integer) inputStartSpinner.getValue());
|
||||
app.prefs.putInt(Constants.PREF_POOL_FROM_END, (Integer) inputEndSpinner.getValue());
|
||||
app.prefs.putInt(Constants.PREF_POOL_TO_START, (Integer) outputStartSpinner.getValue());
|
||||
app.prefs.putInt(Constants.PREF_POOL_TO_END, (Integer) outputEndSpinner.getValue());
|
||||
|
||||
app.prefs.putInt(Constants.PREF_POOL_STRATEGY, getSelectedStrat().ordinal());
|
||||
app.savePreferences();
|
||||
}
|
||||
|
||||
private void updatePooler() {
|
||||
pooler.setInputRange((Integer) inputStartSpinner.getValue(), (Integer) inputEndSpinner.getValue());
|
||||
pooler.setOutputRange((Integer) outputStartSpinner.getValue(), (Integer) outputEndSpinner.getValue());
|
||||
|
||||
pooler.setStrategy(getSelectedStrat());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
poolStratBG = new javax.swing.ButtonGroup();
|
||||
enablePoolingCB = new javax.swing.JCheckBox();
|
||||
poolingChannelPannel = new javax.swing.JPanel();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
inputStartSpinner = new javax.swing.JSpinner();
|
||||
inputEndSpinner = new javax.swing.JSpinner();
|
||||
outputStartSpinner = new javax.swing.JSpinner();
|
||||
jLabel2 = new javax.swing.JLabel();
|
||||
outputEndSpinner = new javax.swing.JSpinner();
|
||||
poolStratPanel = new javax.swing.JPanel();
|
||||
jLabel3 = new javax.swing.JLabel();
|
||||
straightThroughRB = new javax.swing.JRadioButton();
|
||||
rndRbnRB = new javax.swing.JRadioButton();
|
||||
stkRB = new javax.swing.JRadioButton();
|
||||
|
||||
setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
setPreferredSize(new java.awt.Dimension(525, 149));
|
||||
|
||||
enablePoolingCB.setText("Enable Drive-Pooling");
|
||||
enablePoolingCB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
enablePoolingCBActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel1.setText("Pool channels:");
|
||||
|
||||
inputStartSpinner.setModel(new javax.swing.SpinnerNumberModel(1, 1, 16, 1));
|
||||
inputStartSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
poolingControlChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
inputEndSpinner.setModel(new javax.swing.SpinnerNumberModel(1, 1, 16, 1));
|
||||
inputEndSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
poolingControlChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
outputStartSpinner.setModel(new javax.swing.SpinnerNumberModel(1, 1, 16, 1));
|
||||
outputStartSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
poolingControlChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel2.setText("Into channels:");
|
||||
|
||||
outputEndSpinner.setModel(new javax.swing.SpinnerNumberModel(1, 1, 16, 1));
|
||||
outputEndSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
poolingControlChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout poolingChannelPannelLayout = new javax.swing.GroupLayout(poolingChannelPannel);
|
||||
poolingChannelPannel.setLayout(poolingChannelPannelLayout);
|
||||
poolingChannelPannelLayout.setHorizontalGroup(
|
||||
poolingChannelPannelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(poolingChannelPannelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(poolingChannelPannelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel1)
|
||||
.addGroup(poolingChannelPannelLayout.createSequentialGroup()
|
||||
.addComponent(inputStartSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(inputEndSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(poolingChannelPannelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel2)
|
||||
.addGroup(poolingChannelPannelLayout.createSequentialGroup()
|
||||
.addComponent(outputStartSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(outputEndSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
poolingChannelPannelLayout.setVerticalGroup(
|
||||
poolingChannelPannelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(poolingChannelPannelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(poolingChannelPannelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(poolingChannelPannelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(poolingChannelPannelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(inputStartSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(inputEndSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGroup(poolingChannelPannelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel2)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(poolingChannelPannelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(outputStartSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(outputEndSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
jLabel3.setText("Using strategy:");
|
||||
|
||||
poolStratBG.add(straightThroughRB);
|
||||
straightThroughRB.setText("Straight-Through");
|
||||
straightThroughRB.setToolTipText("Essentially does nothing. Mostly here for testing.");
|
||||
straightThroughRB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
poolingStratChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
poolStratBG.add(rndRbnRB);
|
||||
rndRbnRB.setSelected(true);
|
||||
rndRbnRB.setText("Round-Robin");
|
||||
rndRbnRB.setToolTipText("Outputs to each channel in a round-robin fashion, attempting to find empty channels first.");
|
||||
rndRbnRB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
poolingStratChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
poolStratBG.add(stkRB);
|
||||
stkRB.setText("Stacking");
|
||||
stkRB.setToolTipText("Uses first available output channel (drops notes if all drives are busy)");
|
||||
stkRB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
poolingStratChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout poolStratPanelLayout = new javax.swing.GroupLayout(poolStratPanel);
|
||||
poolStratPanel.setLayout(poolStratPanelLayout);
|
||||
poolStratPanelLayout.setHorizontalGroup(
|
||||
poolStratPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel3)
|
||||
.addComponent(straightThroughRB)
|
||||
.addComponent(rndRbnRB)
|
||||
.addComponent(stkRB)
|
||||
);
|
||||
poolStratPanelLayout.setVerticalGroup(
|
||||
poolStratPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(poolStratPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel3)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(straightThroughRB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(rndRbnRB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(stkRB)
|
||||
.addGap(0, 15, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(enablePoolingCB)
|
||||
.addComponent(poolingChannelPannel, javax.swing.GroupLayout.PREFERRED_SIZE, 211, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(poolStratPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(187, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(enablePoolingCB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(poolingChannelPannel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addComponent(poolStratPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void poolingControlChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_poolingControlChanged
|
||||
updatePooler();
|
||||
}//GEN-LAST:event_poolingControlChanged
|
||||
|
||||
|
||||
private void enablePoolingCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_enablePoolingCBActionPerformed
|
||||
setControlsEnabled(enablePoolingCB.isSelected());
|
||||
}//GEN-LAST:event_enablePoolingCBActionPerformed
|
||||
|
||||
private void setControlsEnabled(boolean enabled){
|
||||
for (Component c : poolingChannelPannel.getComponents()){
|
||||
c.setEnabled(enabled);
|
||||
}
|
||||
for (Component c : poolStratPanel.getComponents()){
|
||||
c.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void poolingStratChanged(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_poolingStratChanged
|
||||
updatePooler();
|
||||
}//GEN-LAST:event_poolingStratChanged
|
||||
|
||||
private DrivePooler.PoolingStrategy getSelectedStrat(){
|
||||
if (stkRB.isSelected()){
|
||||
return DrivePooler.PoolingStrategy.STACK;
|
||||
} else if (rndRbnRB.isSelected()){
|
||||
return DrivePooler.PoolingStrategy.ROUND_ROBIN;
|
||||
} else {
|
||||
return DrivePooler.PoolingStrategy.STRAIGHT_THROUGH;
|
||||
}
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JCheckBox enablePoolingCB;
|
||||
private javax.swing.JSpinner inputEndSpinner;
|
||||
private javax.swing.JSpinner inputStartSpinner;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
private javax.swing.JLabel jLabel3;
|
||||
private javax.swing.JSpinner outputEndSpinner;
|
||||
private javax.swing.JSpinner outputStartSpinner;
|
||||
private javax.swing.ButtonGroup poolStratBG;
|
||||
private javax.swing.JPanel poolStratPanel;
|
||||
private javax.swing.JPanel poolingChannelPannel;
|
||||
private javax.swing.JRadioButton rndRbnRB;
|
||||
private javax.swing.JRadioButton stkRB;
|
||||
private javax.swing.JRadioButton straightThroughRB;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
227
Java/MoppyDesk/src/moppydesk/ui/SequencerControls.form
Normal file
227
Java/MoppyDesk/src/moppydesk/ui/SequencerControls.form
Normal file
|
@ -0,0 +1,227 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="110" max="-2" attributes="0"/>
|
||||
<Component id="bpmLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="sequenceNameLabel" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="loadButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="DelayResetSpinner" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="ResetDrivesCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="RepeatCB" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="currentPositionLabel" min="-2" pref="30" max="-2" attributes="0"/>
|
||||
<EmptySpace min="4" pref="4" max="-2" attributes="0"/>
|
||||
<Component id="sequenceProgressSlider" min="-2" pref="376" max="-2" attributes="0"/>
|
||||
<EmptySpace min="4" pref="4" max="-2" attributes="0"/>
|
||||
<Component id="totalPositionLabel" min="-2" pref="30" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jSlider1" min="-2" pref="267" max="-2" attributes="0"/>
|
||||
<EmptySpace min="18" pref="18" max="-2" attributes="0"/>
|
||||
<Component id="startButton" min="-2" pref="76" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="stopButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="11" pref="11" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="46" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="loadButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="sequenceNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="bpmLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jSlider1" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="8" pref="8" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="startButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="stopButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="RepeatCB" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="ResetDrivesCB" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="DelayResetSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="currentPositionLabel" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<Component id="sequenceProgressSlider" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="totalPositionLabel" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Current Sequence:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="sequenceNameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="<None loaded>"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="bpmLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="jSlider1.getValue() + " bpm"" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSlider" name="jSlider1">
|
||||
<Properties>
|
||||
<Property name="majorTickSpacing" type="int" value="10"/>
|
||||
<Property name="maximum" type="int" value="310"/>
|
||||
<Property name="minimum" type="int" value="20"/>
|
||||
<Property name="paintTicks" type="boolean" value="true"/>
|
||||
<Property name="value" type="int" value="120"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseDragged" listener="java.awt.event.MouseMotionListener" parameters="java.awt.event.MouseEvent" handler="jSlider1tempoSliderChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="startButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Start"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="startButtonClicked"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="stopButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Stop/Reset"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Press once to stop sequencer and return to beginning of track. Press again to reset drives."/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="stopButtonstopResetClicked"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="loadButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Load Sequence"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="loadButtonloadSequence"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSlider" name="sequenceProgressSlider">
|
||||
<Properties>
|
||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
||||
<Property name="value" type="int" value="0"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="sequenceProgressDragged"/>
|
||||
<EventHandler event="mouseDragged" listener="java.awt.event.MouseMotionListener" parameters="java.awt.event.MouseEvent" handler="sequenceProgressDragged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="currentPositionLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="00:00"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="totalPositionLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="00:00"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="RepeatCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Repeat"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Repeats the song when selected."/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="ResetDrivesCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Reset Drives"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Resets the drives after the end of the current song."/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ResetDrivesCBActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="DelayResetSpinner">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
<SpinnerModel initial="0" maximum="600" minimum="0" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Delays resetting the drives after the song ends by a number of seconds."/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel2">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Delay Reset:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
433
Java/MoppyDesk/src/moppydesk/ui/SequencerControls.java
Normal file
433
Java/MoppyDesk/src/moppydesk/ui/SequencerControls.java
Normal file
|
@ -0,0 +1,433 @@
|
|||
package moppydesk.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import moppydesk.inputs.MoppySequencer;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sound.midi.Transmitter;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.Timer;
|
||||
import moppydesk.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public final class SequencerControls extends InputPanel implements MoppyStatusConsumer {
|
||||
|
||||
MoppySequencer seq;
|
||||
MoppyControlWindow controlWindow;
|
||||
MoppyUI app;
|
||||
final JFileChooser sequenceChooser = new JFileChooser();
|
||||
Timer progressTimer;
|
||||
private boolean isConnected = false;
|
||||
private boolean fileLoaded = false;
|
||||
|
||||
/**
|
||||
* Creates new form SequencerControls
|
||||
*/
|
||||
public SequencerControls(MoppyUI app, MoppyControlWindow mcw, MoppySequencer newSequencer) {
|
||||
this.seq = newSequencer;
|
||||
this.app = app;
|
||||
this.controlWindow = mcw;
|
||||
|
||||
initComponents();
|
||||
|
||||
progressTimer = new Timer(1000, new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
updateProgressDisplay();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPreferences() {
|
||||
ResetDrivesCB.setSelected(app.prefs.getBoolean(Constants.PREF_RESET_DRIVES, false));
|
||||
RepeatCB.setSelected(app.prefs.getBoolean(Constants.PREF_REPEAT_SEQ, false));
|
||||
DelayResetSpinner.setValue(app.prefs.getInt(Constants.PREF_DELAY_RESET, 0));
|
||||
DelayResetSpinner.setEnabled(ResetDrivesCB.isSelected());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePreferences() {
|
||||
app.prefs.putBoolean(Constants.PREF_RESET_DRIVES, ResetDrivesCB.isSelected());
|
||||
app.prefs.putBoolean(Constants.PREF_REPEAT_SEQ, RepeatCB.isSelected());
|
||||
app.prefs.putInt(Constants.PREF_DELAY_RESET, (Integer)DelayResetSpinner.getValue());
|
||||
}
|
||||
|
||||
private void updateProgressDisplay() {
|
||||
long currentSeconds = seq.getSecondsPosition();
|
||||
sequenceProgressSlider.setValue((int) (currentSeconds));
|
||||
String currentPosition = String.format("%d:%02d",
|
||||
TimeUnit.SECONDS.toMinutes(currentSeconds),
|
||||
currentSeconds % 60);
|
||||
String totalPosition = String.format("%d:%02d",
|
||||
TimeUnit.SECONDS.toMinutes(seq.getSecondsLength()),
|
||||
seq.getSecondsLength() % 60);
|
||||
currentPositionLabel.setText(currentPosition);
|
||||
totalPositionLabel.setText(totalPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
sequenceNameLabel = new javax.swing.JLabel();
|
||||
bpmLabel = new javax.swing.JLabel();
|
||||
jSlider1 = new javax.swing.JSlider();
|
||||
startButton = new javax.swing.JButton();
|
||||
stopButton = new javax.swing.JButton();
|
||||
loadButton = new javax.swing.JButton();
|
||||
sequenceProgressSlider = new javax.swing.JSlider();
|
||||
currentPositionLabel = new javax.swing.JLabel();
|
||||
totalPositionLabel = new javax.swing.JLabel();
|
||||
RepeatCB = new javax.swing.JCheckBox();
|
||||
ResetDrivesCB = new javax.swing.JCheckBox();
|
||||
DelayResetSpinner = new javax.swing.JSpinner();
|
||||
jLabel2 = new javax.swing.JLabel();
|
||||
|
||||
jLabel1.setText("Current Sequence:");
|
||||
|
||||
sequenceNameLabel.setText("<None loaded>");
|
||||
|
||||
bpmLabel.setText(jSlider1.getValue() + " bpm");
|
||||
|
||||
jSlider1.setMajorTickSpacing(10);
|
||||
jSlider1.setMaximum(310);
|
||||
jSlider1.setMinimum(20);
|
||||
jSlider1.setPaintTicks(true);
|
||||
jSlider1.setValue(120);
|
||||
jSlider1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
|
||||
public void mouseDragged(java.awt.event.MouseEvent evt) {
|
||||
jSlider1tempoSliderChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
startButton.setText("Start");
|
||||
startButton.setEnabled(false);
|
||||
startButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
startButtonClicked(evt);
|
||||
}
|
||||
});
|
||||
|
||||
stopButton.setText("Stop/Reset");
|
||||
stopButton.setToolTipText("Press once to stop sequencer and return to beginning of track. Press again to reset drives.");
|
||||
stopButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
stopButtonstopResetClicked(evt);
|
||||
}
|
||||
});
|
||||
|
||||
loadButton.setText("Load Sequence");
|
||||
loadButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
loadButtonloadSequence(evt);
|
||||
}
|
||||
});
|
||||
|
||||
sequenceProgressSlider.setToolTipText("");
|
||||
sequenceProgressSlider.setValue(0);
|
||||
sequenceProgressSlider.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||
public void mouseClicked(java.awt.event.MouseEvent evt) {
|
||||
sequenceProgressDragged(evt);
|
||||
}
|
||||
});
|
||||
sequenceProgressSlider.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
|
||||
public void mouseDragged(java.awt.event.MouseEvent evt) {
|
||||
sequenceProgressDragged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
currentPositionLabel.setText("00:00");
|
||||
|
||||
totalPositionLabel.setText("00:00");
|
||||
|
||||
RepeatCB.setText("Repeat");
|
||||
RepeatCB.setToolTipText("Repeats the song when selected.");
|
||||
|
||||
ResetDrivesCB.setText("Reset Drives");
|
||||
ResetDrivesCB.setToolTipText("Resets the drives after the end of the current song.");
|
||||
ResetDrivesCB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
ResetDrivesCBActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
DelayResetSpinner.setModel(new javax.swing.SpinnerNumberModel(0, 0, 600, 1));
|
||||
DelayResetSpinner.setToolTipText("Delays resetting the drives after the song ends by a number of seconds.");
|
||||
|
||||
jLabel2.setText("Delay Reset:");
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(110, 110, 110)
|
||||
.addComponent(bpmLabel)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jLabel1)
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addComponent(sequenceNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(loadButton))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jLabel2)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(DelayResetSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(ResetDrivesCB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(RepeatCB))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(currentPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(4, 4, 4)
|
||||
.addComponent(sequenceProgressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, 376, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(4, 4, 4)
|
||||
.addComponent(totalPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(startButton, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(stopButton)))))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(11, 11, 11)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jLabel1)
|
||||
.addGap(46, 46, 46))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(loadButton)
|
||||
.addComponent(sequenceNameLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(bpmLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(8, 8, 8)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(startButton)
|
||||
.addComponent(stopButton))))
|
||||
.addGap(8, 8, 8)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(RepeatCB)
|
||||
.addComponent(ResetDrivesCB)
|
||||
.addComponent(DelayResetSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabel2))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(currentPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(sequenceProgressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(totalPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void jSlider1tempoSliderChanged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jSlider1tempoSliderChanged
|
||||
JSlider s = (JSlider) evt.getSource();
|
||||
seq.setTempo(s.getValue());
|
||||
bpmLabel.setText(s.getValue() + " bpm");
|
||||
}//GEN-LAST:event_jSlider1tempoSliderChanged
|
||||
|
||||
private void startButtonClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonClicked
|
||||
if (startButton.getText().equals("Start")) {
|
||||
playSequencer();
|
||||
} else {
|
||||
pauseSequencer();
|
||||
}
|
||||
}//GEN-LAST:event_startButtonClicked
|
||||
|
||||
private void playSequencer() {
|
||||
seq.startSequencer();
|
||||
seq.setTempo(jSlider1.getValue());
|
||||
controlWindow.setStatus("Playing!");
|
||||
startButton.setText("Pause");
|
||||
}
|
||||
|
||||
private void pauseSequencer() {
|
||||
seq.stopSequencer();
|
||||
startButton.setText("Start");
|
||||
controlWindow.setStatus("...Paused");
|
||||
}
|
||||
|
||||
private void stopResetSequencer() {
|
||||
if (seq.isRunning()) {
|
||||
stopSeq();
|
||||
} else {
|
||||
resetSeq();
|
||||
}
|
||||
updateProgressDisplay(); // Always update the progress here in case we're not connected but want to reset the sequencer
|
||||
}
|
||||
|
||||
private void stopSeq(){
|
||||
controlWindow.setStatus("Stopping...");
|
||||
seq.stopSequencer();
|
||||
seq.resetSequencer();
|
||||
startButton.setText("Start");
|
||||
controlWindow.setStatus("Stopped.");
|
||||
}
|
||||
|
||||
private void resetSeq(){
|
||||
app.rm.reset();
|
||||
seq.resetSequencer();
|
||||
controlWindow.setStatus("Reset.");
|
||||
}
|
||||
|
||||
private void stopButtonstopResetClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonstopResetClicked
|
||||
stopResetSequencer();
|
||||
}//GEN-LAST:event_stopButtonstopResetClicked
|
||||
|
||||
private void loadButtonloadSequence(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadButtonloadSequence
|
||||
String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_SEQ, null);
|
||||
if (previouslyLoaded != null) {
|
||||
sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
|
||||
}
|
||||
int returnVal = sequenceChooser.showOpenDialog(this);
|
||||
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
loadSequenceFile(sequenceChooser.getSelectedFile());
|
||||
} else {
|
||||
//Cancelled
|
||||
}
|
||||
}//GEN-LAST:event_loadButtonloadSequence
|
||||
|
||||
private void sequenceProgressDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_sequenceProgressDragged
|
||||
int seconds = ((JSlider) evt.getSource()).getValue();
|
||||
seq.setSecondsPosition(seconds);
|
||||
currentPositionLabel.setText(String.format("%d:%02d",
|
||||
TimeUnit.SECONDS.toMinutes(seconds),
|
||||
seconds % 60));
|
||||
}//GEN-LAST:event_sequenceProgressDragged
|
||||
|
||||
private void ResetDrivesCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ResetDrivesCBActionPerformed
|
||||
DelayResetSpinner.setEnabled(ResetDrivesCB.isSelected());
|
||||
}//GEN-LAST:event_ResetDrivesCBActionPerformed
|
||||
|
||||
@Override
|
||||
public void tempoChanged(int newTempo) {
|
||||
jSlider1.setValue(newTempo);
|
||||
bpmLabel.setText(newTempo + " bpm");
|
||||
}
|
||||
|
||||
private void loadSequenceFile(File sequenceFile) {
|
||||
try {
|
||||
stopSeq();
|
||||
controlWindow.setStatus("Loading file...");
|
||||
seq.loadFile(sequenceFile.getPath());
|
||||
sequenceNameLabel.setText(sequenceFile.getName());
|
||||
sequenceProgressSlider.setMaximum((int) (seq.getSecondsLength()));
|
||||
app.prefs.put(Constants.PREF_LOADED_SEQ, sequenceFile.getPath());
|
||||
fileLoaded = true;
|
||||
controlWindow.setStatus("Loaded " + sequenceFile.getName());
|
||||
updateProgressDisplay();
|
||||
if (isConnected) {
|
||||
startButton.setEnabled(true);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MoppyControlWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
controlWindow.setStatus("File loading error!");
|
||||
JOptionPane.showMessageDialog(this.getRootPane(), ex);
|
||||
}
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JSpinner DelayResetSpinner;
|
||||
private javax.swing.JCheckBox RepeatCB;
|
||||
private javax.swing.JCheckBox ResetDrivesCB;
|
||||
private javax.swing.JLabel bpmLabel;
|
||||
private javax.swing.JLabel currentPositionLabel;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
private javax.swing.JSlider jSlider1;
|
||||
private javax.swing.JButton loadButton;
|
||||
private javax.swing.JLabel sequenceNameLabel;
|
||||
private javax.swing.JSlider sequenceProgressSlider;
|
||||
private javax.swing.JButton startButton;
|
||||
private javax.swing.JButton stopButton;
|
||||
private javax.swing.JLabel totalPositionLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@Override
|
||||
public Transmitter getTransmitter() {
|
||||
return seq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected() {
|
||||
progressTimer.start();
|
||||
isConnected = true;
|
||||
if (fileLoaded) {
|
||||
startButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected() {
|
||||
startButton.setEnabled(false);
|
||||
pauseSequencer();
|
||||
isConnected = false;
|
||||
progressTimer.stop();
|
||||
seq.setReceiver(null); //Clear receiver so there's no connection here.
|
||||
}
|
||||
|
||||
//MrSolidSnake745: Simple use for the SequenceEnded event
|
||||
//Resets the sequence and drives if ResetDrivesCB is selected once the song has finished
|
||||
@Override
|
||||
public void sequenceEnded() {
|
||||
controlWindow.setStatus("Song has ended.");
|
||||
app.rm.silence(); //In case there are any stuck notes, most likely from pooling, silence all receivers
|
||||
seq.resetSequencer();
|
||||
startButton.setText("Start");
|
||||
if(ResetDrivesCB.isSelected()) {
|
||||
int y = ((Integer)DelayResetSpinner.getValue());
|
||||
if(y > 0) {
|
||||
try {
|
||||
setEnabledAllControls(false); //Don't want users messing with controls while we delay
|
||||
controlWindow.setStatus("Waiting " + y + " seconds before reset...");
|
||||
Thread.sleep(y * 1000); //Thread is sooooo sleepy...
|
||||
}
|
||||
catch(Exception x){}
|
||||
finally{setEnabledAllControls(true);}
|
||||
}
|
||||
controlWindow.setStatus("Resetting!");
|
||||
app.rm.reset();
|
||||
controlWindow.setStatus("Reset.");
|
||||
}
|
||||
if(RepeatCB.isSelected()) { playSequencer(); }
|
||||
}
|
||||
|
||||
public void setEnabledAllControls(boolean value) {
|
||||
for (Component c : this.getComponents()) {c.setEnabled(value);}
|
||||
}
|
||||
}
|
BIN
Java/MoppyDesk/src/moppydesk/ui/moppy_ico.png
Normal file
BIN
Java/MoppyDesk/src/moppydesk/ui/moppy_ico.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
73
Java/MoppySim/build.xml
Normal file
73
Java/MoppySim/build.xml
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- You may freely edit this file. See commented blocks below for -->
|
||||
<!-- some examples of how to customize the build. -->
|
||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||
<!-- the Compile on Save feature is turned off for the project. -->
|
||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||
<!-- in the project's Project Properties dialog box.-->
|
||||
<project name="MoppySim" default="default" basedir=".">
|
||||
<description>Builds, tests, and runs the project MoppySim.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
<!--
|
||||
|
||||
There exist several targets which are by default empty and which can be
|
||||
used for execution of your tasks. These targets are usually executed
|
||||
before and after some main targets. They are:
|
||||
|
||||
-pre-init: called before initialization of project properties
|
||||
-post-init: called after initialization of project properties
|
||||
-pre-compile: called before javac compilation
|
||||
-post-compile: called after javac compilation
|
||||
-pre-compile-single: called before javac compilation of single file
|
||||
-post-compile-single: called after javac compilation of single file
|
||||
-pre-compile-test: called before javac compilation of JUnit tests
|
||||
-post-compile-test: called after javac compilation of JUnit tests
|
||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||
-pre-jar: called before JAR building
|
||||
-post-jar: called after JAR building
|
||||
-post-clean: called after cleaning build products
|
||||
|
||||
(Targets beginning with '-' are not intended to be called on their own.)
|
||||
|
||||
Example of inserting an obfuscator after compilation could look like this:
|
||||
|
||||
<target name="-post-compile">
|
||||
<obfuscate>
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
</obfuscate>
|
||||
</target>
|
||||
|
||||
For list of available properties check the imported
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
|
||||
Another way to customize the build is by overriding existing main targets.
|
||||
The targets of interest are:
|
||||
|
||||
-init-macrodef-javac: defines macro for javac compilation
|
||||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar: JAR building
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
||||
An example of overriding the target for project execution could look like this:
|
||||
|
||||
<target name="run" depends="MoppySim-impl.jar">
|
||||
<exec dir="bin" executable="launcher.exe">
|
||||
<arg file="${dist.jar}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
Notice that the overridden target depends on the jar target and not only on
|
||||
the compile target as the regular run target does. Again, for a list of available
|
||||
properties which you can use, check the target you are overriding in the
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
</project>
|
4
Java/MoppySim/build/built-jar.properties
Normal file
4
Java/MoppySim/build/built-jar.properties
Normal file
|
@ -0,0 +1,4 @@
|
|||
#Thu, 23 Jul 2015 19:46:18 +0200
|
||||
|
||||
|
||||
/home/alexander/tmp/SammyIAm/Moppy/Java/MoppySim=
|
BIN
Java/MoppySim/build/classes/moppysim/comm/SimController.class
Normal file
BIN
Java/MoppySim/build/classes/moppysim/comm/SimController.class
Normal file
Binary file not shown.
BIN
Java/MoppySim/build/classes/moppysim/components/SimDrive.class
Normal file
BIN
Java/MoppySim/build/classes/moppysim/components/SimDrive.class
Normal file
Binary file not shown.
BIN
Java/MoppySim/build/classes/moppysim/ui/DrivePanel.class
Normal file
BIN
Java/MoppySim/build/classes/moppysim/ui/DrivePanel.class
Normal file
Binary file not shown.
BIN
Java/MoppySim/build/classes/moppysim/ui/MainWindow$1.class
Normal file
BIN
Java/MoppySim/build/classes/moppysim/ui/MainWindow$1.class
Normal file
Binary file not shown.
BIN
Java/MoppySim/build/classes/moppysim/ui/MainWindow$2.class
Normal file
BIN
Java/MoppySim/build/classes/moppysim/ui/MainWindow$2.class
Normal file
Binary file not shown.
BIN
Java/MoppySim/build/classes/moppysim/ui/MainWindow.class
Normal file
BIN
Java/MoppySim/build/classes/moppysim/ui/MainWindow.class
Normal file
Binary file not shown.
BIN
Java/MoppySim/build/classes/moppysim/ui/floppy_xs.png
Normal file
BIN
Java/MoppySim/build/classes/moppysim/ui/floppy_xs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
Java/MoppySim/lib/floppy_s.png
Normal file
BIN
Java/MoppySim/lib/floppy_s.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 765 KiB |
BIN
Java/MoppySim/lib/floppy_xs.png
Normal file
BIN
Java/MoppySim/lib/floppy_xs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
Java/MoppySim/lib/jsyn_16_7_3.jar
Normal file
BIN
Java/MoppySim/lib/jsyn_16_7_3.jar
Normal file
Binary file not shown.
3
Java/MoppySim/manifest.mf
Normal file
3
Java/MoppySim/manifest.mf
Normal file
|
@ -0,0 +1,3 @@
|
|||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
1413
Java/MoppySim/nbproject/build-impl.xml
Normal file
1413
Java/MoppySim/nbproject/build-impl.xml
Normal file
File diff suppressed because it is too large
Load Diff
5
Java/MoppySim/nbproject/genfiles.properties
Normal file
5
Java/MoppySim/nbproject/genfiles.properties
Normal file
|
@ -0,0 +1,5 @@
|
|||
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
||||
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
||||
nbproject/build-impl.xml.data.CRC32=68eeca74
|
||||
nbproject/build-impl.xml.script.CRC32=1dbd8490
|
||||
nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
|
1
Java/MoppySim/nbproject/private/private.properties
Normal file
1
Java/MoppySim/nbproject/private/private.properties
Normal file
|
@ -0,0 +1 @@
|
|||
user.properties.file=/home/alexander/.netbeans/8.0.2/build.properties
|
77
Java/MoppySim/nbproject/project.properties
Normal file
77
Java/MoppySim/nbproject/project.properties
Normal file
|
@ -0,0 +1,77 @@
|
|||
annotation.processing.enabled=true
|
||||
annotation.processing.enabled.in.editor=false
|
||||
annotation.processing.processor.options=
|
||||
annotation.processing.processors.list=
|
||||
annotation.processing.run.all.processors=true
|
||||
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.classes.excludes=**/*.java,**/*.form
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=build
|
||||
build.generated.dir=${build.dir}/generated
|
||||
build.generated.sources.dir=${build.dir}/generated-sources
|
||||
# Only compile against the classpath explicitly listed here:
|
||||
build.sysclasspath=ignore
|
||||
build.test.classes.dir=${build.dir}/test/classes
|
||||
build.test.results.dir=${build.dir}/test/results
|
||||
# Uncomment to specify the preferred debugger connection transport:
|
||||
#debug.transport=dt_socket
|
||||
debug.classpath=\
|
||||
${run.classpath}
|
||||
debug.test.classpath=\
|
||||
${run.test.classpath}
|
||||
# Files in build.classes.dir which should be excluded from distribution jar
|
||||
dist.archive.excludes=
|
||||
# This directory is removed when the project is cleaned:
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/MoppySim.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
excludes=
|
||||
file.reference.jsyn_16_7_3.jar=lib\\jsyn_16_7_3.jar
|
||||
file.reference.nrjavaserial-3.9.3.jar=..\\SerialDrivers\\nrjavaserial-3.9.3.jar
|
||||
includes=**
|
||||
jar.compress=false
|
||||
javac.classpath=\
|
||||
${file.reference.nrjavaserial-3.9.3.jar}:\
|
||||
${file.reference.jsyn_16_7_3.jar}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
javac.processorpath=\
|
||||
${javac.classpath}
|
||||
javac.source=1.7
|
||||
javac.target=1.7
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
javac.test.processorpath=\
|
||||
${javac.test.classpath}
|
||||
javadoc.additionalparam=
|
||||
javadoc.author=false
|
||||
javadoc.encoding=${source.encoding}
|
||||
javadoc.noindex=false
|
||||
javadoc.nonavbar=false
|
||||
javadoc.notree=false
|
||||
javadoc.private=false
|
||||
javadoc.splitindex=true
|
||||
javadoc.use=true
|
||||
javadoc.version=false
|
||||
javadoc.windowtitle=
|
||||
main.class=moppysim.ui.MainWindow
|
||||
manifest.file=manifest.mf
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
mkdist.disabled=false
|
||||
platform.active=default_platform
|
||||
run.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
# Space-separated list of JVM arguments used when running the project.
|
||||
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
|
||||
# To set system properties for unit tests define test-sys-prop.name=value:
|
||||
run.jvmargs=
|
||||
run.test.classpath=\
|
||||
${javac.test.classpath}:\
|
||||
${build.test.classes.dir}
|
||||
source.encoding=UTF-8
|
||||
src.dir=src
|
||||
test.src.dir=test
|
15
Java/MoppySim/nbproject/project.xml
Normal file
15
Java/MoppySim/nbproject/project.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.java.j2seproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>MoppySim</name>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
127
Java/MoppySim/src/moppysim/comm/SimController.java
Normal file
127
Java/MoppySim/src/moppysim/comm/SimController.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
package moppysim.comm;
|
||||
|
||||
import com.jsyn.JSyn;
|
||||
import com.jsyn.Synthesizer;
|
||||
import com.jsyn.unitgen.LineOut;
|
||||
import com.jsyn.unitgen.Pan;
|
||||
import gnu.io.NRSerialPort;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import moppysim.components.SimDrive;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class SimController implements Runnable{
|
||||
|
||||
NRSerialPort serial;
|
||||
static int SERIAL_RATE = 9600;
|
||||
private boolean running = false;
|
||||
private SimDrive[] simDrives;
|
||||
static int ARDUINO_RESOLUTION = 40; // Used to convert incoming data into actual microseconds
|
||||
private int numberOfDrives;
|
||||
|
||||
Synthesizer synth = JSyn.createSynthesizer();
|
||||
LineOut lout = new LineOut();
|
||||
|
||||
public SimController(int numOfDrives){
|
||||
numberOfDrives = numOfDrives;
|
||||
simDrives = new SimDrive[numberOfDrives];
|
||||
|
||||
// Set up the synthesizer
|
||||
synth.add(lout);
|
||||
Pan pan = new Pan();
|
||||
pan.pan.set(0.0);
|
||||
pan.output.connect(0,lout.input,0);
|
||||
pan.output.connect(1,lout.input,1);
|
||||
|
||||
for (int d=0;d<numberOfDrives;d++){
|
||||
SimDrive sd = new SimDrive();
|
||||
simDrives[d] = sd;
|
||||
synth.add(sd.so);
|
||||
sd.so.output.connect(pan.input);
|
||||
}
|
||||
}
|
||||
|
||||
public SimDrive[] getDrives(){
|
||||
return simDrives;
|
||||
}
|
||||
|
||||
public static String[] getComPorts(){
|
||||
Set<String> ports = NRSerialPort.getAvailableSerialPorts();
|
||||
return ports.toArray(new String[ports.size()]);
|
||||
}
|
||||
|
||||
public void connect(String comPort){
|
||||
serial = new NRSerialPort(comPort, SERIAL_RATE);
|
||||
serial.connect();
|
||||
}
|
||||
|
||||
public void disconnect(){
|
||||
stop();
|
||||
resetAll();
|
||||
if (serial != null){
|
||||
serial.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
this.running = false;
|
||||
synth.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
running = true;
|
||||
synth.start();
|
||||
lout.start();
|
||||
if (serial.isConnected()){
|
||||
|
||||
DataInputStream in = new DataInputStream(serial.getInputStream());
|
||||
|
||||
byte messageCommand;
|
||||
int messageData;
|
||||
|
||||
while (running && !Thread.currentThread().isInterrupted()){
|
||||
try {
|
||||
if (in.available() > 2){
|
||||
messageCommand = in.readByte();
|
||||
messageData = in.readUnsignedShort();
|
||||
|
||||
if (messageCommand == 100){
|
||||
resetAll();
|
||||
} else {
|
||||
setNote(messageCommand,messageData);
|
||||
}
|
||||
|
||||
} else {
|
||||
Thread.sleep(5);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SimController.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(SimController.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetAll(){
|
||||
for (SimDrive s : simDrives){
|
||||
s.setNote(0);
|
||||
s.resetDrive();
|
||||
}
|
||||
}
|
||||
|
||||
private void setNote(int driveNumber, int periodData){
|
||||
if ((driveNumber/2)-1 < numberOfDrives){
|
||||
simDrives[(driveNumber/2)-1].setNote(periodData * (ARDUINO_RESOLUTION*2));
|
||||
}
|
||||
|
||||
//System.out.println("Set drive "+((driveNumber/2)-1)+" to "+periodData);
|
||||
}
|
||||
}
|
43
Java/MoppySim/src/moppysim/components/SimDrive.java
Normal file
43
Java/MoppySim/src/moppysim/components/SimDrive.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moppysim.components;
|
||||
|
||||
import com.jsyn.ports.UnitOutputPort;
|
||||
import com.jsyn.unitgen.SquareOscillator;
|
||||
import moppysim.ui.DrivePanel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam
|
||||
*/
|
||||
public class SimDrive {
|
||||
|
||||
public SquareOscillator so = new SquareOscillator();
|
||||
public DrivePanel drivePanel = new DrivePanel();
|
||||
|
||||
public SimDrive(){
|
||||
so.noteOff();
|
||||
}
|
||||
|
||||
public void setNote(int periodData){
|
||||
|
||||
if (periodData>0){
|
||||
so.noteOn(1000000/periodData, 0.05);
|
||||
drivePanel.playingNote(1000000/periodData);
|
||||
} else {
|
||||
so.noteOff();
|
||||
drivePanel.playingNote(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetDrive(){
|
||||
drivePanel.resetDrive();
|
||||
}
|
||||
|
||||
public UnitOutputPort getOutput(){
|
||||
return so.getOutput();
|
||||
}
|
||||
}
|
42
Java/MoppySim/src/moppysim/ui/DrivePanel.form
Normal file
42
Java/MoppySim/src/moppysim/ui/DrivePanel.form
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabel1" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/moppysim/ui/floppy_xs.png"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
|
||||
<LineBorder thickness="3"/>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
71
Java/MoppySim/src/moppysim/ui/DrivePanel.java
Normal file
71
Java/MoppySim/src/moppysim/ui/DrivePanel.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moppysim.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam
|
||||
*/
|
||||
public class DrivePanel extends javax.swing.JPanel {
|
||||
|
||||
double lastFrequency;
|
||||
|
||||
/**
|
||||
* Creates new form DrivePanel
|
||||
*/
|
||||
public DrivePanel() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
|
||||
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/moppysim/ui/floppy_xs.png"))); // NOI18N
|
||||
jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0), 3));
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel1)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
public void playingNote(double frequency){
|
||||
if (frequency > 0){
|
||||
lastFrequency = frequency;
|
||||
jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder(Color.getHSBColor((float)(frequency/500), 1, 1), 3));
|
||||
} else if(lastFrequency>0) {
|
||||
jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder(Color.getHSBColor((float)(lastFrequency/500), 1, (float)0.5), 3));
|
||||
} else {
|
||||
jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder(Color.BLACK, 3));
|
||||
}
|
||||
}
|
||||
|
||||
public void resetDrive(){
|
||||
lastFrequency = 0;
|
||||
jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder(Color.BLACK, 3));
|
||||
}
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel jLabel1;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
89
Java/MoppySim/src/moppysim/ui/MainWindow.form
Normal file
89
Java/MoppySim/src/moppysim/ui/MainWindow.form
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="3"/>
|
||||
<Property name="title" type="java.lang.String" value="Moppy Sim"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="drivesPanel" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="comSelectBox" min="-2" pref="167" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="connectButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="311" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="comSelectBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="connectButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="drivesPanel" pref="259" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JComboBox" name="comSelectBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new DefaultComboBoxModel<String>(sc.getComPorts())
" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Serial Port:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="connectButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Connect"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="connectButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="drivesPanel">
|
||||
<Properties>
|
||||
<Property name="name" type="java.lang.String" value="Moppy Sim" noResource="true"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
146
Java/MoppySim/src/moppysim/ui/MainWindow.java
Normal file
146
Java/MoppySim/src/moppysim/ui/MainWindow.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
package moppysim.ui;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import moppysim.comm.SimController;
|
||||
import moppysim.components.SimDrive;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sammy1Am
|
||||
*/
|
||||
public class MainWindow extends javax.swing.JFrame {
|
||||
|
||||
SimController sc;
|
||||
|
||||
/**
|
||||
* Creates new form MainWindow
|
||||
*/
|
||||
public MainWindow() {
|
||||
initComponents();
|
||||
sc = new SimController(8);
|
||||
for (SimDrive d : sc.getDrives()){
|
||||
drivesPanel.add(d.drivePanel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
comSelectBox = new javax.swing.JComboBox();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
connectButton = new javax.swing.JButton();
|
||||
drivesPanel = new javax.swing.JPanel();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
||||
setTitle("Moppy Sim");
|
||||
|
||||
comSelectBox.setModel(new DefaultComboBoxModel<String>(sc.getComPorts())
|
||||
);
|
||||
|
||||
jLabel1.setText("Serial Port:");
|
||||
|
||||
connectButton.setText("Connect");
|
||||
connectButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
connectButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
drivesPanel.setName("Moppy Sim"); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(drivesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jLabel1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(comSelectBox, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(connectButton)
|
||||
.addGap(0, 311, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(comSelectBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabel1)
|
||||
.addComponent(connectButton))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(drivesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void connectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectButtonActionPerformed
|
||||
if (connectButton.getText().equals("Connect")){
|
||||
connectButton.setText("Disconnect");
|
||||
comSelectBox.setEnabled(false);
|
||||
sc.connect((String) comSelectBox.getSelectedItem());
|
||||
new Thread(sc).start();
|
||||
} else {
|
||||
connectButton.setText("Connect");
|
||||
comSelectBox.setEnabled(true);
|
||||
sc.stop();
|
||||
sc.disconnect();
|
||||
}
|
||||
}//GEN-LAST:event_connectButtonActionPerformed
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
/* Set the Nimbus look and feel */
|
||||
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
|
||||
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
|
||||
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
|
||||
*/
|
||||
try {
|
||||
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
|
||||
if ("Nimbus".equals(info.getName())) {
|
||||
javax.swing.UIManager.setLookAndFeel(info.getClassName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (InstantiationException ex) {
|
||||
java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
|
||||
java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/* Create and display the form */
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new MainWindow().setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JComboBox comSelectBox;
|
||||
private javax.swing.JButton connectButton;
|
||||
private javax.swing.JPanel drivesPanel;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
BIN
Java/MoppySim/src/moppysim/ui/floppy_xs.png
Normal file
BIN
Java/MoppySim/src/moppysim/ui/floppy_xs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
Java/SerialDrivers/nrjavaserial-3.9.3.jar
Normal file
BIN
Java/SerialDrivers/nrjavaserial-3.9.3.jar
Normal file
Binary file not shown.
|
@ -1,57 +0,0 @@
|
|||
Trent Here. I do those ugly brown pages at rxtx.org. Documentation is not
|
||||
what I do well :) So please help me when you see problems or something is
|
||||
confusing.
|
||||
|
||||
For more information provided by end users please visit the rxtx wiki at
|
||||
http://rxtx.qbang.org/wiki. This is also where you can help.
|
||||
|
||||
Short Install Instructions
|
||||
|
||||
Windows
|
||||
|
||||
RXTXcomm.jar goes in \jre\lib\ext (under java)
|
||||
rxtxSerial.dll goes in \jre\bin
|
||||
|
||||
Mac OS X (x86 and ppc) (there is an Installer with the source)
|
||||
|
||||
RXTXcomm.jar goes in /Library/Java/Extensions
|
||||
librxtxSerial.jnilib goes in /Library/Java/Extensions
|
||||
Run fixperm.sh thats in the directory. Fix perms is in the Mac_OS_X
|
||||
subdirectory.
|
||||
|
||||
Linux (only x86, x86_64, ia64 here but more in the ToyBox)
|
||||
|
||||
RXTXcomm.jar goes in /jre/lib/ext (under java)
|
||||
librxtxSerial.so goes in /jre/lib/[machine type] (i386 for instance)
|
||||
Make sure the user is in group lock or uucp so lockfiles work.
|
||||
|
||||
Solaris (sparc only so far)
|
||||
|
||||
RXTXcomm.jar goes in /jre/lib/ext (under java)
|
||||
librxtxSerial.so goes in /jre/lib/[machine type]
|
||||
Make sure the user is in group uucp so lockfiles work.
|
||||
|
||||
|
||||
|
||||
|
||||
A person is added to group lock or uucp by editing /etc/groups. Distributions
|
||||
have various tools but this works:
|
||||
|
||||
lock:x:54: becomes:
|
||||
lock:x:53:jarvi,taj
|
||||
|
||||
Now jarvi and taj are in group lock.
|
||||
|
||||
Also make sure jarvi and taj have read and write permissions on the port.
|
||||
|
||||
|
||||
|
||||
|
||||
If there are problems please help each other on the wiki and ask questions
|
||||
on the mail-list. User contributed changes will be used here in the next
|
||||
release. If you don't like the documentation, you can improve it.
|
||||
|
||||
|
||||
--
|
||||
Trent Jarvi
|
||||
tjarvi@qbang.org
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,4 +0,0 @@
|
|||
Wed Mar 1 12:05:10 MST 2006
|
||||
We forgot to update the Mac OS X binary. Previously, it was an old version
|
||||
(RXTX-2.1-7pre20). This has now been corrected.
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,9 +0,0 @@
|
|||
Build Date: Sun 12/07/2008 10:45
|
||||
Compiled on Processor Architecture: AMD64
|
||||
Compiled on Processor Identifier: Intel64 Family 15 Model 6 Stepping 4, GenuineIntel
|
||||
Compiled on Processor Level: 15
|
||||
Compiled on Processor Revision: 0604
|
||||
Java Virtual Machine:
|
||||
java version "1.6.0_10"
|
||||
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
|
||||
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)
|
|
@ -1,33 +0,0 @@
|
|||
|
||||
Windows
|
||||
----------------------------------------------------
|
||||
|
||||
Choose your binary build - x64 or x86 (based on which version of
|
||||
the JVM you are installing to)
|
||||
|
||||
NOTE: You MUST match your architecture. You can't install the i386
|
||||
version on a 64-bit version of the JDK and vice-versa.
|
||||
|
||||
For a JDK installation:
|
||||
|
||||
Copy RXTXcomm.jar ---> <JAVA_HOME>\jre\lib\ext
|
||||
Copy rxtxSerial.dll ---> <JAVA_HOME>\jre\bin
|
||||
Copy rxtxParallel.dll ---> <JAVA_HOME>\jre\bin
|
||||
|
||||
Linux
|
||||
----------------------------------------------------
|
||||
|
||||
Choose your binary build - x86_64 or i386 (based on which version of
|
||||
the JVM you are installing to)
|
||||
|
||||
NOTE: You MUST match your architecture. You can't install the i386
|
||||
version on a 64-bit version of the JDK and vice-versa.
|
||||
|
||||
For a JDK installation on architecture=i386
|
||||
|
||||
Copy RXTXcomm.jar ---> <JAVA_HOME>/jre/lib/ext
|
||||
Copy librxtxSerial.so ---> <JAVA_HOME>/jre/lib/i386/
|
||||
Copy librxtxParallel.so ---> <JAVA_HOME>/jre/lib/i386/
|
||||
|
||||
NOTE: For a JDK installation on architecture=x86_64, just change the
|
||||
i386 to x86_64 above.
|
Binary file not shown.
|
@ -1,63 +0,0 @@
|
|||
Overview
|
||||
-----------------------------------------------
|
||||
This package contains a custom binary distribution of
|
||||
the RXTX serial package for Java.
|
||||
|
||||
Courtesy of Cloudhopper, Inc.
|
||||
http://rxtx.cloudhopper.net/
|
||||
http://www.cloudhopper.net/opensource/rxtx/
|
||||
|
||||
NOTE: If you include my builds in any of your distributions,
|
||||
please make sure to at least provide a note of thanks to
|
||||
Cloudhopper in your own ReleaseNotes. For example,
|
||||
|
||||
"RXTX binary builds provided as a courtesy of Cloudhopper.
|
||||
Please see http://rxtx.cloudhopper.net/ for more info."
|
||||
|
||||
RXTX is a great package, but they were lacking pre-built
|
||||
binaries for x64 versions of Windows. I also wanted a
|
||||
version built explicitly with Microsoft Visual Studio
|
||||
rather than MinGW.
|
||||
|
||||
Please see ReleaseNotes.txt for information about this
|
||||
specific release.
|
||||
|
||||
|
||||
Customization
|
||||
-----------------------------------------------
|
||||
|
||||
1. I've based my build on recent CVS snapshots. Please
|
||||
see the ReleaseNotes.txt for information about which
|
||||
snapshot I based this distribution on.
|
||||
|
||||
2. Removed UTS_NAME warning from .c files to match
|
||||
kernel with the version you compiled against.
|
||||
|
||||
3. Changed version in RXTXVersion.jar and in SerialImp.c
|
||||
to match my release so that I know its compiled via a CVS
|
||||
snapshot.
|
||||
|
||||
|
||||
win-x86, win-x64, ia64
|
||||
-----------------------------------------------
|
||||
Built using Microsoft Visual C++ 2008 - not MinGW. The
|
||||
x86 and x64 versions are native and do not rely on
|
||||
any other non-standard windows libraries. Just drop
|
||||
in the compiled .dlls that are specific to the version
|
||||
of Java you run. If you installed the 64-bit version
|
||||
of the JDK, then install the x64 build.
|
||||
|
||||
I've tested the x86 and x64 version with Windows 2008,
|
||||
2003, and Vista SP1.
|
||||
|
||||
|
||||
linux-i386 & linux-x86_64
|
||||
-----------------------------------------------
|
||||
Built using CentOS 5.2 and gcc 4.1.2.
|
||||
|
||||
Just drop in the compiled .dlls that are specific to
|
||||
the version of Java you run. If you installed the 64-bit
|
||||
version of the JDK, then install the x64 build.
|
||||
|
||||
I've tested the x86 and x64 versions with x86 and x64
|
||||
versions of CentOS 5.0 and 5.2.
|
|
@ -1,23 +0,0 @@
|
|||
Release Notes
|
||||
--------------------------------------------------
|
||||
|
||||
Cloudhopper distibution of RXTX serial package for Java.
|
||||
|
||||
http://rxtx.cloudhopper.net/
|
||||
http://www.cloudhopper.net/opensource/rxtx/
|
||||
|
||||
|
||||
2.2-20081207
|
||||
|
||||
* Initial distribution
|
||||
* linux-i386 and linux-x86_64 using CentOS 5.2 and GCC 4.1.2
|
||||
* win-x86, win-x64, and win-ia64 builds using MSCV 2008
|
||||
* CVS snapshot of RXTX-2.2 from 12/07/2008
|
||||
* Please see BuildInfo.txt for more information about the
|
||||
particular build you downloaded
|
||||
* All windows builds crash the JVM if a COM port becomes
|
||||
unavailable. For example, if using a USB-to-serial port
|
||||
cable and you pull it out while your app is connected to the
|
||||
port. The linux version throws an exception in this scenario.
|
||||
Please note that even when compiled using mingw vs. MSVC, the
|
||||
build will have the same behavior.
|
Binary file not shown.
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
Wed Mar 1 12:01:05 MST 2006
|
||||
rxtxSerial.dll had to be recomopiled to link in missing native methods.
|
||||
|
Binary file not shown.
Binary file not shown.
67
README.md
Normal file
67
README.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
<pre>
|
||||
__ ___ ___ __ __
|
||||
/ |/ /___ ____ ____ __ __/ | ____/ / ______ _____ ________ ____/ /
|
||||
/ /|_/ / __ \/ __ \/ __ \/ / / / /| |/ __ / | / / __ `/ __ \/ ___/ _ \/ __ /
|
||||
/ / / / /_/ / /_/ / /_/ / /_/ / ___ / /_/ /| |/ / /_/ / / / / /__/ __/ /_/ /
|
||||
/_/ /_/\____/ .___/ .___/\__, /_/ |_\__,_/ |___/\__,_/_/ /_/\___/\___/\__,_/
|
||||
/_/ /_/ /____/
|
||||
</pre>
|
||||
|
||||
by Sammy1Am
|
||||
|
||||
Moppy is a **M**usical Fl **oppy** controller program built for the [Arduino Uno](http://arduino.cc/en/Main/ArduinoBoardUno).
|
||||
|
||||
This version attempts to improve upon the original Moppy by adding additional functionality including:
|
||||
|
||||
- MIDI-IN support
|
||||
- Per-channel output control
|
||||
- Support for multiple Arduinos/MIDI devices
|
||||
- Drive pooling
|
||||
|
||||
|
||||
This document is meant to be a sort of quick-start guide. You can find an FAQ and troubleshooting guide on the [Wiki](https://github.com/SammyIAm/Moppy/wiki).
|
||||
|
||||
Installation
|
||||
------------
|
||||
The Arduino code requires the TimeOne library available here: http://www.arduino.cc/playground/Code/Timer1
|
||||
|
||||
|
||||
The latest build is using NRJavaSerial, which should include suitable native drives for most systems. If you've previously run an older version of Moppy, you'll need to make sure that the RXTX jar file(s) are **not** being loaded (i.e. not on the classpath, &c.), since the two libraries will conflict if both present.
|
||||
|
||||
|
||||
Upload the included Arduino code to the Arduino of your choice (requires [Arduino IDE](http://arduino.cc/en/Main/Software)), and open up the included Java code in your favorite IDE. This code includes a NetBeans project for your convenience, so you should be able to open the project directly in NetBeans.
|
||||
|
||||
Hardware
|
||||
--------
|
||||
I built Moppy using an Arduino Uno, though it should work just fine on most Arduinos. The pins are connected in pairs to floppy drives as follows: Even pins (2,4,6...) are connected to each drive's STEP pin, the matching odd pins (3,5,7...) are connected to the each drive's DIRECTION control pin. So the first floppy would be connected to pin 2 & 3, the second floppy to 4 & 5, and so on.
|
||||
|
||||
|
||||
Some pinout information can be found here: http://pinouts.ru/Storage/InternalDisk_pinout.shtml
|
||||
|
||||
|
||||
Make sure you ground the correct drive-select pin, or the drive won't respond to any input (just connect the drive-select pin on the floppy to the pin directly below it). You can tell when you have the right drive selected, because the light on the front of the drive will come on.
|
||||
|
||||
|
||||
Also, it's VERY IMPORTANT that your Arduino is grounded with the drives, or the drives will not register the pulses correctly. To do this, make sure that the GND pin on the Arduino is connected to the odd-numbered pin below the STEP pin on the floppy (i.e. if the STEP pin is 20, connect the Audnio's GND pin to Floppy-pin 19). You might need to do this for the DIRECTION pin as well (I did it for both, but I don't know if it's required).
|
||||
|
||||
Configuration and use
|
||||
---------------------
|
||||
- Open up the code in [NetBeans](http://netbeans.org) (or your favorite IDE) and run it. Alternatively, you can build the MoppyDesk.jar file and run that directly.
|
||||
- On the right half of the screen, check the channel output boxes for the number of drives you have connected, select "Moppy", and choose the COM port that you have your Arduino connected to.
|
||||
- Click the "Load Sequence" button and select a suitable MIDI file (see below).
|
||||
- Click the "Connect" button to connect the program to the devices specified in the output area.
|
||||
- Click "Start" to start playback (if all goes well).
|
||||
- The Stop/Reset button will stop playback and reset the drives.
|
||||
|
||||
MIDI file information and guidelines
|
||||
------------------------------------
|
||||
- MIDI files should have one MIDI channel for each controller pin on the Arduino. Channel 1 will be sent to pin2, channel 2 to pin4, &c.
|
||||
- Each drive can only play a single note at a time.
|
||||
- The software will only attempt to play notes between C1 and B4. Floppy drives don't seem to respond well to notes outside of this range (especially higher).
|
||||
- Generally shorter notes tend to sound better, as longer notes are marred by the read-heads changing directions repeatedly.
|
||||
|
||||
Cross your fingers, and enjoy!
|
||||
|
||||
Help / contributions
|
||||
--------------------
|
||||
https://github.com/SammyIAm/Moppy
|
42
README.txt
42
README.txt
|
@ -1,42 +0,0 @@
|
|||
Moppy is a musical floppy controller program built for the Arduino UNO.
|
||||
|
||||
--INSTALLATION--
|
||||
The Arduino code requires the TimeOne library available here: http://www.arduino.cc/playground/Code/Timer1
|
||||
|
||||
You will need to follow the directions in the appropriate Java/SerialDrivers folder for your system to install the serial drivers prior to running Moppy.
|
||||
|
||||
Upload the included Arduino code to the Arduino of your choice, and open up the included Java code in your favorite IDE.
|
||||
|
||||
--HARDWARE--
|
||||
|
||||
Moppy was built for Arduino UNO, though it should work just fine on most
|
||||
Arduinos. The pins are connected in pairs to floppy drives as follows: Even
|
||||
pins (2,4,6,...,A0,A2) are connected to each drive's STEP pin (pin 20) , the matching
|
||||
odd pins (3,5,7,...,A1,A3) are connected to the each drive's DIRECTION control pin
|
||||
(pin 18). So the first floppy would be connected to pin 2 & 3, the second floppy to 4 & 5, and so on.
|
||||
|
||||
Make sure you ground the correct drive-select pin (pin 12), or the drive won't respond to any input (just connect the drive-select pin on the floppy to the pin directly below it). You can tell when you have the right drive selected, because the light on the front of the drive will come on.
|
||||
|
||||
Also, it's VERY IMPORTANT that your Arduino is grounded with the drives, or
|
||||
the drives will not register the pulses correctly. To do this, make sure that
|
||||
the GND pin on the Arduino is connected to any of the odd-numbered pins on the
|
||||
floppy drive (usually all odd-numbered pins are directly connected anyway, as
|
||||
can easily be checked with an ohmmeter).
|
||||
|
||||
|
||||
--CONFIGURAITON / USE--
|
||||
|
||||
- Open up the code in your favorite IDE and run it. Alternatively, you can build the MoppyDesk.jar file and run that.
|
||||
- Select the COM port that the Arduino is hooked up to from the "Arduino Port" drop-down. You will need to have this configured before you launch MoppyDesk.
|
||||
- Click the "Connect" button to create a new Sequencer connected to the specified COM port.
|
||||
- Click the "Load Sequence" button and select a suitable MIDI file (see below).
|
||||
- Click "Start" to start playback (if all goes well).
|
||||
- The Stop/Reset button will stop playback and reset the drives. Pressing "Start" again will resume from where the sequencer left off. You will need to reload the MIDI to start from the beginning.
|
||||
|
||||
|
||||
--MIDI FILE INFORMATION / GUIDELINES--
|
||||
|
||||
- MIDI files should have one MIDI channel for each controller pin on the Arduino. Channel 1 will be sent to pin2, channel 2 to pin4, &c.
|
||||
- Each drive can only play a single note at a time.
|
||||
- The software will only attempt to play notes between C1 and B4. Floppy drives don't seem to respond well to notes outside of this range (especially higher).
|
||||
- Generally shorter notes tend to sound better, as longer notes are marred by the read-heads changing directions repeatedly.
|
Loading…
Reference in New Issue
Block a user