From ed54cd866e7b3774d24e69740cdf008194f54849 Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 14 Nov 2018 19:45:18 +0200 Subject: [PATCH] 01 --- src/Main.java | 31 + src/midedit/AbstractListener.java | 14 + src/midedit/BufDataInputStream.java | 208 +++ src/midedit/CompositionForm.java | 566 ++++++++ src/midedit/Constants.java | 142 ++ src/midedit/DrumsCanvas.java | 125 ++ src/midedit/FileChooser.java | 233 ++++ src/midedit/L.java | 154 +++ src/midedit/LangParser.java | 219 +++ src/midedit/MidiFile.java | 716 ++++++++++ src/midedit/MixerCanvas.java | 1766 +++++++++++++++++++++++++ src/midedit/MixerMain.java | 404 ++++++ src/midedit/MixerModel.java | 242 ++++ src/midedit/Note.java | 29 + src/midedit/NoteList.java | 304 +++++ src/midedit/NoteListUtils.java | 315 +++++ src/midedit/NoteLong.java | 26 + src/midedit/NotesCanvas.java | 128 ++ src/midedit/PrintSmallFont.java | 176 +++ src/midedit/Rms.java | 76 ++ src/midedit/Settings.java | 129 ++ src/midedit/TempoList.java | 171 +++ src/midedit/UndoableAction.java | 257 ++++ src/midedit/VolumeForm.java | 140 ++ src/midedit/WaitForm.java | 87 ++ src/midedit/Waitable.java | 24 + src/midedit/io/AbstractFile.java | 142 ++ src/midedit/io/JSR75File.java | 284 ++++ src/midedit/io/RMSFile.java | 203 +++ src/midedit/media/AbstractPlayer.java | 38 + src/midedit/media/Composition.java | 537 ++++++++ src/midedit/media/JSR135Player.java | 66 + src/text.txt | 11 + 33 files changed, 7963 insertions(+) create mode 100644 src/Main.java create mode 100644 src/midedit/AbstractListener.java create mode 100644 src/midedit/BufDataInputStream.java create mode 100644 src/midedit/CompositionForm.java create mode 100644 src/midedit/Constants.java create mode 100644 src/midedit/DrumsCanvas.java create mode 100644 src/midedit/FileChooser.java create mode 100644 src/midedit/L.java create mode 100644 src/midedit/LangParser.java create mode 100644 src/midedit/MidiFile.java create mode 100644 src/midedit/MixerCanvas.java create mode 100644 src/midedit/MixerMain.java create mode 100644 src/midedit/MixerModel.java create mode 100644 src/midedit/Note.java create mode 100644 src/midedit/NoteList.java create mode 100644 src/midedit/NoteListUtils.java create mode 100644 src/midedit/NoteLong.java create mode 100644 src/midedit/NotesCanvas.java create mode 100644 src/midedit/PrintSmallFont.java create mode 100644 src/midedit/Rms.java create mode 100644 src/midedit/Settings.java create mode 100644 src/midedit/TempoList.java create mode 100644 src/midedit/UndoableAction.java create mode 100644 src/midedit/VolumeForm.java create mode 100644 src/midedit/WaitForm.java create mode 100644 src/midedit/Waitable.java create mode 100644 src/midedit/io/AbstractFile.java create mode 100644 src/midedit/io/JSR75File.java create mode 100644 src/midedit/io/RMSFile.java create mode 100644 src/midedit/media/AbstractPlayer.java create mode 100644 src/midedit/media/Composition.java create mode 100644 src/midedit/media/JSR135Player.java create mode 100644 src/text.txt diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000..42aec16 --- /dev/null +++ b/src/Main.java @@ -0,0 +1,31 @@ +/* + * aNNiMON 2011 + * For more info visit http://annimon.com/ + */ + +import javax.microedition.lcdui.*; +import javax.microedition.midlet.*; + +/** + * @author aNNiMON + */ +public class Main extends MIDlet { + + public Display dsp; + public static Main midlet; + + public Main() { + midlet = Main.this; + dsp = Display.getDisplay(Main.this); + } + + public void startApp() { + } + + public void pauseApp() { + } + + public void destroyApp(boolean ex) { + notifyDestroyed(); + } +} diff --git a/src/midedit/AbstractListener.java b/src/midedit/AbstractListener.java new file mode 100644 index 0000000..2992663 --- /dev/null +++ b/src/midedit/AbstractListener.java @@ -0,0 +1,14 @@ +package midedit; + +/** + * + * @author user + */ +public interface AbstractListener { + + /** + * + * @param itemNum + */ + public void actionPerformed(int itemNum); +} diff --git a/src/midedit/BufDataInputStream.java b/src/midedit/BufDataInputStream.java new file mode 100644 index 0000000..2abcbad --- /dev/null +++ b/src/midedit/BufDataInputStream.java @@ -0,0 +1,208 @@ +package midedit; + +import java.io.*; + +/** + * Буфферизированный ввод-вывод + * @author vmx + */ +public class BufDataInputStream extends InputStream implements DataInput { + public byte[] buffer; + public int capacity, is_available, bpos, blen; + protected InputStream is; + + public BufDataInputStream(InputStream iis) throws IOException { + bpos = blen = 0; + is = iis; + capacity = is_available = is.available (); + buffer = new byte[capacity]; + if (is != null) is.read(buffer); + } + + public void close() throws IOException { + if (is != null) is.close(); + } + + public int available() { + return blen - bpos + is_available; + } + + public int getCapacity() { + return capacity; + } + + public void seek(int pos) { + bpos = pos; + } + + public int tell() throws IOException { + return capacity - available(); + } + + public int read() throws IOException { + if (bpos > buffer.length) { + return -1; + } + return ((int) buffer[bpos++]) & 0xFF; + } + + public int readBack() throws IOException { + if (bpos == 0) { + if (available() == capacity) return -1; + int old = tell(); + bpos = old; + } + return ((int) buffer[--bpos]) & 0xFF; + } + + public boolean readBoolean() throws IOException { + int r = read(); + if (r == -1) { + throw new IOException("EOF"); + } + return r != 0; + } + + public byte readByte() throws IOException { + int r = read(); + if (r == -1) { + throw new IOException("EOF"); + } + return (byte) r; + } + + public char readChar() throws IOException { + return (char) ((readUnsignedByte() << 8) | readUnsignedByte()); + } + + public void readFully(byte[] b) throws IOException { + if (read(b) < b.length) { + throw new IOException("EOF"); + } + } + + public void readFully(byte[] b, int off, int len) throws IOException { + if (read(b, off, len) < len) { + throw new IOException("EOF"); + } + } + + public int readInt() throws IOException { + return (readUnsignedByte() << 24) | + (readUnsignedByte() << 16) | + (readUnsignedByte() << 8) | + (readUnsignedByte()); + } + + public long readLong() throws IOException { + byte bb[] = new byte[8]; + readFully(bb); + return (bb[0] << 24) | + (bb[1] << 16) | + (bb[2] << 8) | + (bb[3]); + } + + public short readShort() throws IOException { + return (short) ((readUnsignedByte() << 8) | readUnsignedByte()); + } + + public int readUnsignedByte() throws IOException { + return ((int) readByte()) & 0xFF; + } + + public int readUnsignedShort() throws IOException { + return ((int) readShort()) & 0xFFFF; + } + + public int skipBytes(int len) throws IOException { + return (int) skip(len); + } + + public String readUTF() throws IOException, UTFDataFormatException { + int n = readUnsignedShort(); + byte b[] = new byte[n]; + readFully(b); + return new String(b, 0, b.length, "UTF-8"); + } + + public char readCharUTF() throws IOException, UTFDataFormatException { + int b, c, d; + b = read(); + if (b == -1) { + return (char) -1; + } + if ((b & 0x80) == 0) { + return (char) b; + } else if ((b & 0xE0) == 0xC0) { + c = read(); + if ((c & 0xC0) != 0x80) { + throw new UTFDataFormatException(); + } + return (char) (((b & 0x1F) << 6) | (c & 0x3F)); + } else if ((b & 0xF0) == 0xE0) { + c = read(); + d = read(); + if ((c & 0xC0) != 0x80 || (d & 0xC0) != 0x80) { + throw new UTFDataFormatException(); + } + return (char) (((b & 0x0F) << 12) | ((c & 0x3F) << 6) | (d & 0x3F)); + } + throw new UTFDataFormatException(); + } + + public char readCharBackUTF() throws IOException, UTFDataFormatException { + int b, c, d; + d = readBack(); + c = readBack(); + b = readBack(); + if (d == -1) { + return (char) -1; + } + if ((d & 0x80) == 0) { + read(); + read(); + return (char) d; + } else if ((c & 0xE0) == 0xC0 && (d & 0xC0) == 0x80) { + read(); + return (char) (((c & 0x1F) << 6) | (d & 0x3F)); + } else if ((b & 0xF0) == 0xE0 && (c & 0xC0) == 0x80 && (d & 0xC0) == 0x80) { + return (char) (((b & 0x0F) << 12) | ((c & 0x3F) << 6) | (d & 0x3F)); + } + throw new UTFDataFormatException(); + } + + public boolean checkBOM() { + try { + if (available() < 3 || + read() != 0xEF || + read() != 0xBB || + read() != 0xBF) { + return false; + } + } catch (IOException iox) { + return false; + } + return true; + } + + public boolean find(byte[] b) { + if (b == null) return false; + int po = 0; + for (int i = bpos + 1; i < buffer.length; i++) { + po = 0; + if (buffer[i] == b[0]) { + for (int j = 0; j < b.length; j++) { //System.out.println("b "+b[j]); + if (buffer[i + j] == b[j]) { + po += 1; + } else break; + } + } + if (po == b.length) { + bpos = i; + break; + } + } + return (po > 0); + } +} diff --git a/src/midedit/CompositionForm.java b/src/midedit/CompositionForm.java new file mode 100644 index 0000000..ffc5d49 --- /dev/null +++ b/src/midedit/CompositionForm.java @@ -0,0 +1,566 @@ +package midedit; + + +import midedit.media.Composition; +import java.util.*; +import javax.microedition.lcdui.*; + +/** + * + * @author user + */ +public class CompositionForm extends Form implements CommandListener, Runnable, ItemCommandListener { + + /** + * + */ + public static CompositionForm curForm; + private static final byte SEEK_GAUGE_MAX = 10; + private byte seekGaugeCur = 0; + private MixerMain control; + private MixerModel model; + private Display display; + private NotesCanvas notesCanvas; + private DrumsCanvas drumsCanvas; + private MixerCanvas curCanvas; + private ChannelChoiceGroup choiseInstrument; + private Gauge seekingGauge; + private static Form listInstrumentsForm; + private Composition composition; + private String fileName; + public static boolean isPlaying, + isWorking, + isNew = false, + isAdd; + private Command addInstrument = new Command(Constants.getStringName(50), Command.HELP, 3), + edit = new Command(Constants.getStringName(51), Command.HELP, 1), + setInstrument = new Command(Constants.getStringName(52), Command.ITEM, 1), + delInstrument = new Command(Constants.getStringName(53), Command.ITEM, 2), + temp = new Command(Constants.getStringName(54), Command.ITEM, 3), + volume = new Command(Constants.getStringName(55), Command.ITEM, 4), + meter = new Command(Constants.getStringName(56), Command.ITEM, 5), + rmsMode = new Command(Constants.getStringName(9), Command.ITEM, 6), + jsr75Mode = new Command(Constants.getStringName(6), Command.ITEM, 7); + + ; + /** + * + */ + /** + * + */ + /** + * + */ + /** + * + */ + /** + * + */ + /** + * + */ + public static Command play = new Command(Constants.getStringName(57), Command.ITEM, 1), + playOrig = new Command(Constants.getStringName(58), Command.ITEM, 1), + stop = new Command(Constants.getStringName(35), Command.BACK, 0), + back = new Command(Constants.getStringName(25), Command.BACK, 2), + //cancel = new Command("Cancel",Command.BACK,1), + ok = new Command(Constants.getStringName(59), Command.ITEM, 1); + + /** + * + * @param ctrl + * @throws Exception + */ + public CompositionForm(MixerMain ctrl) throws Exception { + this(ctrl, null); + isNew = true; + + + + } + + /** + * + * @param ctrl + * @param fName + * @throws Exception + */ + public CompositionForm(MixerMain ctrl, String fName) throws Exception { + super((fName != null) ? fName : "New"); + control = ctrl; + model = control.getModel(); + model.crossPlayer.setCommandForm(this); + fileName = fName; + curForm = this; + } + + /** + * + * @return + */ + public boolean isNew() { + return isNew; + } + + /** + * + * @param isNewComposition + */ + public void setNew(boolean isNewComposition) { + isNew = isNewComposition; + } + + /** + * + */ + public void setComposForm() { + seekingGauge.setValue((composition.getCurWInPercent() + SEEK_GAUGE_MAX / 2) / SEEK_GAUGE_MAX); + seekGaugeCur = (byte) seekingGauge.getValue(); + display.setCurrent(this); + } + + /** + * + * @return + */ +// public boolean isntCancel() { +// return isWorking; +// } +// + /** + * + */ + public void run() { + display = Display.getDisplay(MixerMain.curMIDlet); + + WaitForm waitForm = new WaitForm(Constants.getStringName(19),//@@@ + model.getWaitableFile(), + control.getCurrentlistMenu(), + model); + display.setCurrent(waitForm); + model.resetProgress(); + new Thread(waitForm).start(); + try { + composition = model.openMix(fileName); + buildContent(); + display.callSerially(new Runnable() { + + public void run() { + display.setCurrent(CompositionForm.this); + } + }); + + isWorking = true; + } catch (Exception ex) { + Alert a = new Alert(Constants.getStringName(12), Constants.getStringName(13) + "\n" + ex, null, null);//@@@ + a.setTimeout(Alert.FOREVER); + waitForm.cancel(); + isWorking = false; + control.setCurrentlistMenu(a); + } + } + + /** + * + */ + public void releaseMem() { + if (composition != null) { + composition.deleteNoteList(); + } + } + + private void buildContent() throws Exception { + + //Constants constants = new Constants(); + notesCanvas = null; + drumsCanvas = null; + curCanvas = null; + MixerCanvas.xBase = 0; + MixerCanvas.curX = 0; + + String[] instrumentsStrings = composition.getInstrumentsStrings(); + if (instrumentsStrings == null) { + throw new Exception("instruments==null"); + } + + choiseInstrument = new ChannelChoiceGroup(Constants.getStringName(23), instrumentsStrings, this.buildChansList()); + if (choiseInstrument == null) { + throw new Exception("choiseInstrument==null"); + } + this.append(choiseInstrument); + seekingGauge = new Gauge(Constants.getStringName(71), true, SEEK_GAUGE_MAX, 0); + this.append(seekingGauge); + this.addCommand(edit); + this.addCommand(play); + isPlaying = false; + this.addCommand(volume); + this.addCommand(temp); + this.addCommand(meter); + this.addCommand(addInstrument); + this.addCommand(setInstrument); + this.addCommand(delInstrument); + this.addCommand(back); + //this.addCommand(rmsMode); + this.setCommandListener(this); + MixerModel.isRMSMode = true; + } + + private byte[] buildChansList() { + int[] instruments = composition.getInstruments(); + int size = 0; + for (int i = 0; i < Constants.NCHANNEL; ++i) { + if (instruments[i] != Composition.NOTHING) { + size++; + } + } + byte[] chans = new byte[size]; + int j = 0; + for (int i = 0; i < Constants.NCHANNEL; ++i) { + if (instruments[i] != Composition.NOTHING) { + chans[j++] = (byte) i; + } + } + return chans; + } + + /** + * + * @param c + * @param i + */ + //public void itemStateChanged(Item item){ + //System.out.println ("itemStateChanged"); + //if (item instanceof Choice){ + // int instNum = ((Choice) item).getSelectedIndex(); + //} + //} + public void commandAction(Command c, Item i) { + String instrName; + int instrumNum; + model.stopPlay(); + if (i instanceof StringItem) { + instrName = Constants.getInstrName(0); + instrumNum = 0; + } + else { + instrName = ((ChoiceGroup) i).getString(((ChoiceGroup) i).getSelectedIndex()); + instrumNum =Constants.instrVectorArr.indexOf(instrName)+1; + } +// System.out.println("instrName = " + instrName); +// System.out.println("instrumNum = " + instrumNum); + if (c == play) { + int channel=-1; + int lengthOfChannel=0; + try { + channel = choiseInstrument.getSelectedChannel(); + lengthOfChannel = composition.tracks[channel].getLen(); + } catch (IllegalAccessException ex) { + //ex.printStackTrace(); + } + //System.out.println ("Channel="+channel+" length="+lengthOfChannel); + if (channel == Constants.DRUMS_CHANNEL || isAdd || lengthOfChannel < 3) { + try { + model.playTest((byte) (instrumNum - 1)); + } catch (Exception e) { + } + } else { + try { + model.playTrack(composition, channel, instrumNum - 1); + } catch (Exception e) { + try { + model.playTest((byte) (instrumNum - 1)); + } catch (Exception ex) { + } + } + } + } else if (c == ok) { + if (isAdd) { + byte channel = composition.addInstrument(instrumNum - 1); + if (channel != -1) { + choiseInstrument.appendChannel(instrName, channel); + } else { + Alert a = new Alert(Constants.getStringName(14), Constants.getStringName(15), null, null); + display.setCurrent(a); + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + } + } + } else { + try { + int channel = choiseInstrument.getSelectedChannel(); + if (channel != -1 && channel != Constants.DRUMS_CHANNEL) { + choiseInstrument.setChannel(choiseInstrument.getSelectedIndex(), instrName, (byte) channel); + composition.setInstrument(channel, instrumNum - 1); + } + } catch (IllegalAccessException ex) { + //ex.printStackTrace(); + } + } + display.setCurrent(CompositionForm.this); + } + } + + /** + * + * @param command + * @param displayable + */ + public void commandAction(Command command, Displayable displayable) { +// System.out.println("displayable = " + displayable); +// System.out.println("command = " + command); +// if (command!=delInstrument) { +// return; +// } + int newVal = seekingGauge.getValue(); + if (newVal != seekGaugeCur) { + byte channel=0; + try { + channel = choiseInstrument.getSelectedChannel(); + } catch (IllegalAccessException ex) { + //ex.printStackTrace(); + } + try { + composition.setCurW(seekingGauge.getValue() * 100 / SEEK_GAUGE_MAX, channel); + } catch (NullPointerException nullExc) { + seekingGauge.setValue(0); + } + } + if ((command == play) && (displayable == this)) { + try { + model.playMix(composition, 0); + } catch (Exception e) { + msg("" + e); + } + } else if (command == Settings.comCancel) { + model.stopPlay(); + display.setCurrent(CompositionForm.this); + } else if (command == stop) { + model.stopPlay(); + } else if (command == edit) { + int channel; + try { + channel = choiseInstrument.getSelectedChannel(); + } catch (IllegalAccessException ex) { + channel=-1; + } + if (channel == -1) { + Alert a = new Alert("CompositionForm", "getChannelFromInstrumName=" + channel, null, null); + display.setCurrent(a); + return; + } + + if (channel == Constants.DRUMS_CHANNEL) { + if (drumsCanvas == null) { + drumsCanvas = new DrumsCanvas(control, composition); + } + curCanvas = drumsCanvas; + } else { + if (notesCanvas == null) { + notesCanvas = new NotesCanvas(control, composition, channel); + } else { + notesCanvas.setChannel(channel); + } + curCanvas = notesCanvas; + } + + display.setCurrent(curCanvas); + curCanvas.setNeedPaint(); + } else if (command == addInstrument) { + isAdd = true; + display.setCurrent(getListOfInstruments()); + System.out.println("displayable = " + displayable); + } else if (command == setInstrument) { + isAdd = false; + display.setCurrent(getListOfInstruments()); + } else if (command == delInstrument) { + byte channel; + try { + channel = choiseInstrument.getSelectedChannel(); + } catch (IllegalAccessException ex) { + return; + } + choiseInstrument.deleteChannel(choiseInstrument.getSelectedIndex()); + composition.setInstrument(channel, Composition.NOTHING); + composition.delNotes(0, 0x7fffffff, (byte) channel, (byte) -1, (byte) 127); + } else if (command == temp) { + TempoList tempos = new TempoList(composition, model, this); + display.setCurrent(tempos); + } else if (command == volume) { + VolumeForm volForm = new VolumeForm(composition, choiseInstrument.getChansVector(), model, this); + display.setCurrent(volForm); + } else if (command == meter) { + Form textBoxTemp = new Form(Constants.getInstrName(72)); + final TextField nomField = new TextField(Constants.getStringName(73), "" + composition.getNom(), 2, TextField.NUMERIC); + textBoxTemp.append(nomField); + final TextField denomField = new TextField(Constants.getStringName(74), "" + composition.getDenomE(), 1, TextField.NUMERIC); + textBoxTemp.append(denomField); + textBoxTemp.append(MixerMain.createStringItem(Constants.getStringName(76), 2)); + textBoxTemp.addCommand(CompositionForm.ok); + textBoxTemp.addCommand(Settings.comCancel); + textBoxTemp.setCommandListener(new CommandListener() { + + public void commandAction(Command command, Displayable displayable) { + if (command == CompositionForm.ok) { + composition.setMeter(Integer.parseInt(nomField.getString(), 10), + Integer.parseInt(denomField.getString(), 10)); + } + display.setCurrent(CompositionForm.this); + } + }); + model.display.setCurrent(textBoxTemp); + + } //else if(command == rmsMode) + //{ + //MixerModel.isRMSMode=true; + //this.removeCommand (rmsMode); + //this.addCommand (jsr75Mode); + //} + //else if(command == jsr75Mode) + //{ + //MixerModel.isRMSMode=false; + //this.removeCommand (jsr75Mode); + //this.addCommand (rmsMode); + //} + else if (command == back) { + control.comBack(); + } + } + + /** + * + * @param name + * @throws Exception + */ + public void saveComposition(String name) throws Exception { + this.setTitle(name); + final String nameFinal = name; + Thread runner = new Thread() { + + public void run() { + WaitForm waitForm = new WaitForm(Constants.getStringName(18) + "...", + model.getWaitableFile(), + control.getCurrentlistMenu(), + model); + display.setCurrent(waitForm); + model.resetProgress(); + new Thread(waitForm).start(); + composition.setName(nameFinal); + try { + String ans = model.saveMix(composition, nameFinal); + Alert a = new Alert(Constants.getStringName(16), ans, null, null); + a.setTimeout(Alert.FOREVER); + control.setCurrentlistMenu(a); + } catch (Exception ex) { + Alert a = new Alert(Constants.getStringName(12), + Constants.getStringName(17) + "\n" + ex.getMessage(), null, null); + a.setTimeout(Alert.FOREVER); + waitForm.cancel(); + control.setCurrentlistMenu(a); + + } + } + }; + runner.start(); + + } + + /** + * + * @return + */ + public String getCompositionName() { + return composition.getName(); + } + + /** + * + * @param s + */ + public static void msg(String s) { + Alert a = new Alert(Constants.getStringName(12), Constants.getStringName(12) + "\n" + s, null, null); + MixerMain.display.setCurrent(a); + } + /*Form tabsInstruments (){ + MyItem []groupsOfElements = new MyItem [16]; + String [] groupOfElements = new String [8]; + int numElementsInGroup = 8, + numIcosOnScreen = MyItem.SCREEN_WIDTH/32; + StringItem instruments[] = new StringItem [128]; + return null; + }*/ + private Form getListOfInstruments() { + System.out.println("in getListInstruments"); + if (listInstrumentsForm == null) { + ChoiceGroup[] groupsChoiseGroup = new ChoiceGroup[16]; + for (int i = 0; i < 16; i++) { +// for (int j = 0; j < 8; j++) { +// listOfElements[j] = j + i * 8 + 1 + ' ' + Constants.getInstrName(j + i * 8 + 1); +// } + String[] listOfElements = new String[8]; + System.arraycopy(Settings.parserInstr.stringResourses, i*8+1, listOfElements,0, 8); + groupsChoiseGroup[i] = new ChoiceGroup(Constants.getInstrName(129 + i), 4, listOfElements, null); + //for (int j=0; j<8; j++) + //groupsOfElements[i].setFont(j,MixerMain.SMALL_FONT); + groupsChoiseGroup[i].addCommand(play); + groupsChoiseGroup[i].addCommand(ok); + groupsChoiseGroup[i].setItemCommandListener(this); + } + listInstrumentsForm = new Form(Constants.getStringName(75), groupsChoiseGroup); + Item drums = new StringItem(Constants.getInstrName(0), null); + drums.addCommand(ok); + drums.setItemCommandListener(this); + listInstrumentsForm.append(drums); + listInstrumentsForm.addCommand(Settings.comCancel); + listInstrumentsForm.setCommandListener(this); + } + //form.setItemStateListener(this); + return listInstrumentsForm; + } +} + +class ChannelChoiceGroup extends ChoiceGroup { + + private Vector instrumentsVector; + + public ChannelChoiceGroup(String label, String[] stringElements, byte[] chans) { + super(label, Choice.EXCLUSIVE, stringElements, null); + instrumentsVector = new Vector(Constants.NCHANNEL, 1); + for (int i = 0; i < chans.length; ++i) { + instrumentsVector.addElement(new Byte(chans[i])); + } + } + + public byte getSelectedChannel() throws IllegalAccessException{ + try{ + Byte b = (Byte) instrumentsVector.elementAt(this.getSelectedIndex()); + return b.byteValue(); + }catch (ArrayIndexOutOfBoundsException arI){ + throw new IllegalAccessException(arI.getMessage()); + } + } + + public int appendChannel(String stringElement, byte channel) { + if (instrumentsVector.size() < Constants.NCHANNEL) { + instrumentsVector.addElement(new Byte(channel)); + return super.append(stringElement, null); + } + return -1; + } + + public void deleteChannel(int index) { + instrumentsVector.removeElementAt(index); + super.delete(index); + } + + public void setChannel(int index, String stringElement, byte channel) { + instrumentsVector.setElementAt(new Byte(channel), index); + super.set(index, stringElement, null); + } + + public Vector getChansVector() { + return instrumentsVector; + } +} diff --git a/src/midedit/Constants.java b/src/midedit/Constants.java new file mode 100644 index 0000000..506251f --- /dev/null +++ b/src/midedit/Constants.java @@ -0,0 +1,142 @@ +package midedit; + + +import java.util.Vector; + + + +//import java.util.*; +//import java.lang.*; + +/** + * + * @author user + */ +public class Constants +{ +// private static Hashtable hashInstrums ; + /** + public Constants() + { + //instruments = getInstruments(); +// hashInstrums= new Hashtable(129); +// for(int i=0; i", getStringName(24), + "", getStringName(25), + ",<5>", getStringName(26)+"\n"+ + getStringName(27), + "<9>,", getStringName(28), + "", getStringName(29), + "", getStringName(30), + "<1>", getStringName(31), + "<3>", getStringName(32), + "<7>,", getStringName(33), + "<*>,<#>,<0>", getStringName(34), + //Settings.settingsIndex[4]==0? "<5>": "",getStringName(35), + Settings.settingsIndex[4]==0? ",,,": "<4>,<6>,<2>,<8> ",getStringName(36), + Settings.settingsIndex[4]==0? "<4>,<6>,<2>,<8>":",,,", getStringName(37), + }; + /** + * + */ + public final static String[]QUICK_COMMANDS = { + "<1> ",getStringName(38), + "<2> ",getStringName(39), + "<3> ",getStringName(40), + "<4> ",getStringName(41), + "<5> ",getStringName(42), + "<6> ",getStringName(43), + "<7> ",getStringName(44), + "<8> ",getStringName(45), + "<9> ",getStringName(46), + "<*> ",getStringName(29), + "<0> ",getStringName(48), + "<#> ",getStringName(49), + }; + static VectorArr instrVectorArr=new VectorArr(Settings.parserInstr.stringResourses, 1, 128); +} +class VectorArr extends Vector { + public VectorArr(Object src, int beg, int length) { + super(length); + setSize(length); + System.arraycopy(src, beg, elementData, 0, size()); + } + +} diff --git a/src/midedit/DrumsCanvas.java b/src/midedit/DrumsCanvas.java new file mode 100644 index 0000000..1fbab76 --- /dev/null +++ b/src/midedit/DrumsCanvas.java @@ -0,0 +1,125 @@ +package midedit; + +import midedit.media.Composition; + + + +/** + * + * @author user + */ +public class DrumsCanvas extends MixerCanvas +{ + /** + * + */ + public static final int drumsShift = Constants.DRUMS_SHIFT; + private byte[] drumsTable = null; + private byte[] drumsTableInverse = null; + /** + * + * @param ctrl + * @param c + */ + public DrumsCanvas(MixerMain ctrl, Composition c) + { + super(ctrl,c,Constants.DRUMS_CHANNEL); + prepareConstants(); + + byte[] b = new byte[Constants.NCHANNEL]; + for(int i=0; i Constants.DRUMS_LENGTH) + nH = Constants.DRUMS_LENGTH; + hStep = 4; + hMin = drumsShift; + hMax = (drumsShift + Constants.DRUMS_LENGTH-1); + hBase = hMin; + curY = 0; + } + /** + * + * @return + */ + protected boolean doKEY_NUM5() + { + if(super.doKEY_NUM5() == false) + composition.addNoteOn(getCurTime(),(byte)channel, + (byte)getNoteFromLine(curY), (byte)getCurVol(),0,true); + return true; + } +protected void doSmallDown (){ + if(hBase+curY < hMax) + super.doSmallDown(); + }; + + + /** + * + * @param val + public void setCurInstrument(int val) + { + int n = val + DrumsTable.SHIFT; + for(int i=0; i= 3) + { + ind = path.lastIndexOf(FILE_DELIMITER, path.length() - 2); + String newPath; + if (ind >= 0) { + newPath = path.substring(0, ind + 1); + } else { + newPath = "" + FILE_DELIMITER; + } + path = newPath; + } + updateView(); + } else if (command == delete) { + int ind = this.getSelectedIndex(); + if (path.length() > 0) { + char ch = path.charAt(path.length() - 1); + if (ch != '/' && ch != '\\') { + path += FILE_DELIMITER; + } + } + selectedFileName = fileNames[ind]; + if (listener != null) { + file.delete(selectedFileName); + } + } else if (command == Settings.comCancel) { + path = null; + if (listener != null) { + listener.actionPerformed(0); + } + } else if (command == saveThis) { + if (listener != null) { + try{ + listener.actionPerformed(0); + } + catch (Exception e){ + Alert a = new Alert(Constants.getStringName(12),Constants.getStringName(20)+":\nlistener.actionPerformed "+ e.getMessage(), null, null); + MixerMain.display.setCurrent(a, prevDisplay); + } + } + } + + else + { + int ind = this.getSelectedIndex(); + String fullName; + if (path.length() > 0) { + char ch = path.charAt(path.length() - 1); + if (ch != '/' && ch != '\\') { + path += FILE_DELIMITER; + } + } + fullName = path; + fullName += fileNames[ind]; + if (file.isDirectory( + fullName)) { + selectedFileName = ""; + path = fullName; + if (path.charAt(path.length() - 1) != '/') { + path += FILE_DELIMITER; + } + updateView(); + } else if (!isSave) + { + selectedFileName = fileNames[ind]; + { + if (listener != null) { + listener.actionPerformed(0); + } + } + } + } + } catch (Exception e) { + Alert a = new Alert(Constants.getStringName(12),Constants.getStringName(20)+":\nFileChooser "+ e.getMessage(), null, null); + MixerMain.display.setCurrent(a, prevDisplay); + } + } + + /** + * + */ + public void update() { + MixerMain.display.callSerially(new Runnable() { + + public void run() { + updateView(); + } + }); + } + + private void updateView() { + MixerMain.display.setCurrent(waitForm); + + new Thread(this).start(); + } + + /** + * + */ + public void run() + { + try { + if (path == null) { + path = defaultPath; + } + + fileNames = file.list( + path); + path = file.getLastListPath(); + + + + for (int i = this.size() - 1; i >= 0; --i) { + this.delete(i); + } + + if (fileNames != null) { + for (int i = 0; i < fileNames.length; ++i) { + this.insert(i, fileNames[i], null); + } + } + + this.setTicker(new Ticker(path)); + MixerMain.display.setCurrent(this); + + + } catch (Exception e) { + Alert a = new Alert(Constants.getStringName(21),Constants.getStringName(21)+ ":\n" + e.getMessage() + "\npath=" + path, null, null); + MixerMain.display.setCurrent(a, prevDisplay); + path = null; + selectedFileName = ""; + } + + + + } + + /** + * + * @return + */ + public String getSelectedFilePath() { + if (path == null) { + return null; + } + return path + selectedFileName; + } + + /** + * + * @return + */ + public String getSelectedFolderPath() { + return path; + } +} diff --git a/src/midedit/L.java b/src/midedit/L.java new file mode 100644 index 0000000..b664f2c --- /dev/null +++ b/src/midedit/L.java @@ -0,0 +1,154 @@ +package midedit; + +import java.io.*; +import java.util.Vector; + +/** + * Класс текстовых меток + * @author aNNiMON + */ +public class L { + + /** Номера строк текстовых меток */ + public static final byte + create = 0, + resume = 1, + about = 2, + open = 3, + save = 4, + saveAs = 5, + file = 6, + options = 7, + exit = 8, + RMS = 9, + cancel = 10, + error = 11, + openError = 12, + toolsList = 13, + impossible = 14, + saved = 15, + savingError = 16, + saving = 17, + opening = 18, + chooserError = 19, + updateError = 20, + apiError = 21, + instruments = 22, + menu = 23, + back = 24, + insertNoteWithCurrentAttributes = 25, + noteAttributeHelp = 26, + deleteNote = 27, + undo = 28, + noteVolume = 29, + playFromCurrent = 30, + playNoteOnCursor = 31, + selectNoteAttribute = 32, + changeNoteAttribute = 33, + stop = 34, + navigationOnComposition = 35, + quicknav = 36, + markBegin = 37, + markEnd = 38, + copy = 39, + pasteInsert = 40, + pasteReplace = 41, + pasteOverwrite = 42, + shiftDelete = 43, + clean = 44, + playChannelOnScreen = 45, + playChannelAll = 46, + redo = 47, + addInstrument = 48, + edit = 49, + setInstrument = 50, + delInstrument = 51, + tempoBox = 52, + volumeBox = 53, + meter = 54, + play = 55, + playOrigin = 56, + ok = 57, + upOneLevel = 58, + delete = 59, + chooseFolder = 60, + openFile = 61, + pleaseWait = 62, + updatingList = 63, + saveInThisFolder = 64, + insertTempo = 65, + deleteTempo = 66, + tempo = 67, + time = 68, + seek = 69, + numerator = 70, + denominator = 71, + meterInfo = 72, + delta = 73, + playStop = 74, + playAll = 75, + playScreen = 76, + trackAll = 77, + trackScreen = 78, + mark = 79, + unmark = 80, + modifyBlock = 81, + modifyMode = 82, + paste = 83, + insert = 84, + replace = 85, + blend = 86, + removeSelection = 87, + help = 88, + keymap = 89, + quickCommands = 90, + navigation = 91, + numkeysOptionString = 92, + iconsOptionString = 93; + + + /** Массив текстовых меток */ + public static String[] str, instr; + + /** + * Прочитать языковой ресурс + * @param lang имя локализации (en, ru) + * @param appLang читать языковой ресурс приложения (true), инструментов (false) + */ + public static void readLang(String lang, boolean appLang) { + try { + final String path = (appLang ? "strings" : "instr") + "_"; + System.out.println("/lang/" + path + lang + ".loc"); + BufDataInputStream bdis = new BufDataInputStream(Runtime.getRuntime().getClass().getResourceAsStream("/lang/" + path + lang + ".loc")); + if (!bdis.checkBOM()) { + bdis.close(); + } + char c = ' '; + Vector v = new Vector(); + StringBuffer s; + while (bdis.available() > 0) { + s = new StringBuffer(); + do { + c = bdis.readCharUTF(); + if (c == '\n') { + break; + } + s.append(c); + } while (bdis.available() > 0); + v.addElement(s.toString()); + } + if(appLang) { + str = new String[v.size()]; + v.copyInto(str); + } else { + instr = new String[v.size()]; + v.copyInto(instr); + } + bdis.close(); + v = null; + } catch (IOException ex) { + ex.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/src/midedit/LangParser.java b/src/midedit/LangParser.java new file mode 100644 index 0000000..102ada2 --- /dev/null +++ b/src/midedit/LangParser.java @@ -0,0 +1,219 @@ +package midedit; + +import java.io.*; +public class LangParser { +/** + +

Эта версия также демонстрирует простой способ определения +локализованных ресурсов. Она считывает файл, который является +частью файла JAR приложения (не файла JAD) +для загрузки локализованных ресурсов. Файл +состоит из набора пар «ключ-значение», одной на строку, +которые представляют локализованные строки. +MID-лет должен затем проанализировать содержимое файла +и создать внутреннюю хэшированную таблицу для поиска. + +

Этот подход требует слишком много усилий по обработке +потока, который содержит файл +локализованных ресурсов. Более того, этот подход +не отвечает за локализацию ресурсов, которые +не являются строками. + */ + /** Региональная настройка, указанная для выполнения данного + MID-лета. + * Извлекает региональную настройку из программного + обеспечения AMS. Региональная настройка должна быть + установлена до выполнения данного MID-лета. + */ + int isSupported=1; + private int maxSize; + String locale,extension;// = System.getProperty("microedition.locale"); + /** Файл, который содержит ресурсы для + активной локальной настройки. + * Названия файлов локализованных ресурсов, соответствующих + форме: <язык>_<страна>.txt. + Создает строку имени файла и передает ее в + метод, который открывает файл и извлекает + содержимое. + + */ + String resourceFile;// ="bin/"+locale + ".lang"; + /* Символьная кодировка, установленная по умолчанию, + используемая данной платформой. + * В данном случае не используется + */ + //private String encoding; + /** HashTable, которая содержит локализованные + ресурсы. + */ + String [] stringResourses; + /** + Конструктор No-arg. + Получает текущее название + региональной настройки. Использует его для создания + имени файла, который содержит локализованные + ресурсы региональной настройки. Файл ресурса + находится в файле JAR приложения. + */ + public LangParser(String newLocale,String newExtension, int parSize) { + + /** + */ +extension=newExtension; +maxSize=parSize; +stringResourses = new String [maxSize]; +setLocale(newLocale,extension); + if (isSupported == 0) { + //do something, eg. throws Exception or generate Alert; + return; + } + } + + /** + Выдает значение, связанное с указанным + ключом из пакета ресурсов приложения. + Если ресурс не найден возвращает указанный ключ + + @param key - ключ пары «ключ-значение». + + @ выдает значение, связанное с + указанным ключом. + */ + public String getStringResourses (int number){ + if (stringResourses[number] == null || number<0 || number>stringResourses.length) { + return "*******"; + } + + return stringResourses[number]; + } + + private void setLocale (String newLocale,String newExtension){ + locale=newLocale; + resourceFile ="/bin/"+locale + "."+newExtension; + loadResources(resourceFile); + } + /** + Загружает определенные пользователем ресурсы приложения + из указанного файла. Файл является частью файла JAR + приложения, расположенного на реальном устройстве. + J2MEWTK хранит файл в файле JAR приложения, расположенном + в директории приложения bin/. + + @param file - имя определенного пользователем файла + ресурса приложения. + */ + private void loadResources(String file) { + Class с = getClass(); + + if (file == null) { + isSupported=0; + file=("/bin/en."+extension); + } + InputStream is = null; + is = с.getResourceAsStream(file); + if (is == null) { + isSupported=0; + file=("/bin/en."+extension); + } + if (is == null){ + for (int i=0;i[ \t]*:[ и]*<значение>, где + <ключ> and <значение> являются метками, состоящими + из буквенных символов или знаков пунктуации, но не + из пустых знаков пробела. + */ + private int readLine( + StringBuffer value, + Reader stream) { + if (value == null || + stream == null) { + return -1; + } + + try { + char c=0; + try{ + while (true){ + c=(char)stream.read(); + if (c==0x0D||c==0x0A){ + continue; + } + break; + } + while (true) { + if (c==0x0D||c==0x0A||c==-1||c==0xffff){ + break; + } + value.append (c); + //System.out.println (value.toString()+" "+locale+"."+extension+" c="+(int)c); + c=(char)stream.read(); + } + } catch (OutOfMemoryError ome){ + //System.out.println ("OutOfMemoryError "+locale+"."+extension); + } + } catch (IOException ioe) { + //ioe.printStackTrace(); + return -1; + } + if (value==null) + return -1; + return 0; + } + + + + /** + + */ + /** + + */ +} + diff --git a/src/midedit/MidiFile.java b/src/midedit/MidiFile.java new file mode 100644 index 0000000..df0848a --- /dev/null +++ b/src/midedit/MidiFile.java @@ -0,0 +1,716 @@ +package midedit; + +import midedit.media.Composition; +import midedit.io.AbstractFile; +import java.io.*; +//import com.siemens.mp.io.File; + +public class MidiFile implements Waitable { + + private String outStr; + private String url; +// private static File file = null; + private static AbstractFile file = null; + //private MixerModel mod; + private int seekPos = 0; + private int seekLen = 1; + private int maxTime = 0; + private boolean cancelStatus; +// private final int size = 49; + private final static int sizeMax/*=200000;*/ = 15000; + //private static int temp = 0x123456; + private static byte[] MTHD = {0x4D, 0x54, 0x68, 0x64}; + private static byte[] MTRK = {0x4d, 0x54, 0x72, 0x6b}; + private static byte[] ENDTrk = {0x00, -0x01, 0x2f, 0x00}; + private static byte[] dat4PlayNote = { + 77, 84, 104, 100, 0, 0, 0, 6,//7 + 0, 0, 0, 1, 0, 96, 77, 84,//15 + 114, 107, 0, 0, 0, 38, 0, -1,//23 + 88, 4, 4, 2, 24, 8, 0, -1,//31 + 81, 3, 33, -14, -13, 0, -64, 26,//39//instr + 0, -112, 46, 1, 8, -103/*0x90*/, 46/*note height*/, 127,//55 + 127, -112/*0x80*/, 46, 1, 16, -112, 46/*note height*/, 1,//63 + 0, -1, 47, 0,}; + //{0x4D,0x54,0x68,0x64,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x1,0x0,0x60, + //0x4d,0x54,0x72,0x6b,0x0,0x0,0x0,0x26/*len*/,0x0,0xff,0x58,0x04,0x04,0x02,0x18,0x08, + //0x0,0xff,0x51,0x03, /*temp->*/0x21,0xf2,0xf3,/*<-*/ + ///*37>*/0x00,0xc0,0x1a, /*40>*/0x00,0x90,0x2e,0x01, + //0x08,0x99,0x2e,0x7f, 0x7f,0x90,0x2e,0x01, + //0x10,0x90,0x2e,0x01, 0x00,0xff,0x2f,0x00}; + private static byte[] bufTmp = new byte[16]; + private static int intTmp; + private static byte[] bMidi = new byte[sizeMax]; + + //public static void setTemp(int t) + //{ temp = t; } + //public static int getTemp() + //{ return temp; } + public MidiFile(AbstractFile aFile) { + file = aFile; + } + + private boolean increaseBuffer() { + int prevLen = bMidi.length; + int nextLen; + if (prevLen > 32000) { + nextLen = prevLen + 32000; + } else { + nextLen = prevLen * 2; + } + + byte[] newarr; + try { + newarr = new byte[nextLen]; + System.arraycopy(bMidi, 0, newarr, 0, bMidi.length); + bMidi = newarr; + //System.out.println("bMidi.length="+bMidi.length); + } catch (Throwable e) { + //System.out.println(""+e); + return false; + } + return true; + } + + public void setFile() { + file = MixerModel.isRMSMode ? MixerModel.rmsFile : MixerModel.jsr75File; + + } + + public String writeMix(Composition c, int t, boolean forPlay) throws Exception { + return writeMixWithName(c, t, forPlay, "out.mid", -1, -1); + } + + public String writeMixWithName(Composition c, int tBeg, boolean forPlay, String name) throws Exception { + return writeMixWithName(c, tBeg, forPlay, name, -1, -1); + } + + //public String writeMixWithName(Composition c,int tBeg, boolean forPlay, String name,int channel)throws Exception{ + //return writeMixWithName(c,tBeg,forPlay,name,channel, -1); + //} + public String writeMixWithName(Composition c, int tBeg, boolean forPlay, String name, int channel, int instrument) throws Exception { + System.gc(); + outStr = name; + //byte[] tnote; + int iMidi; // index of b + int i;//,ind; + //Note note; + + iMidi = 0; + //// begin header ------------------------- + /// print MThd (4) + for (i = 0; i < MTHD.length; ++i) { + bMidi[iMidi++] = MTHD[i]; + } + + /// print header lenght (4) + bMidi[iMidi] = 0; + bMidi[iMidi + 1] = 0; + bMidi[iMidi + 2] = 0; + bMidi[iMidi + 3] = 6; /// always =6 + iMidi += 4; + + /// print format (2) + bMidi[iMidi] = 0; + bMidi[iMidi + 1] = 1; + iMidi += 2; + + /// print num track (2) + int numTracks = 0; + NoteList curList; + //// print tracks + seekLen = 1; + seekPos = 1; + int lastTrack = 0; + if (channel == -1) { + for (i = 0; i < Constants.NCHANNEL; ++i) { + curList = c.getNoteListByChannel(i); + seekLen += curList.getLen(); + if (curList.getLen() > 0 && (!forPlay || c.isPlayChan(i))) { + numTracks++; + lastTrack = i; + } + } + } else { + curList = c.getNoteListByChannel(channel); + seekLen += curList.getLen(); + if (curList.getLen() > 0 && (!forPlay || c.isPlayChan(i))) { + numTracks++; + lastTrack = 0; + } + } + bMidi[iMidi] = 0; + bMidi[iMidi + 1] = (byte) numTracks; + iMidi += 2; + + /// print tick per quart (2) + short ticks = c.getTicksPer4(); + bMidi[iMidi] = (byte) (ticks / 256); + bMidi[iMidi + 1] = (byte) (ticks % 256); + iMidi += 2; + + /// end header ------------------- + + cancelStatus = false; + maxTime = 0; // global var + boolean isLastTrack = false; + if (channel == -1) { + for (i = 0; i < Constants.NCHANNEL; ++i) { + curList = c.getNoteListByChannel(i); + if (curList.getLen() > 0 && (!forPlay || c.isPlayChan(i))) { // track is not empty + if (i == lastTrack) { + isLastTrack = true; + } + int numByte = writeTrack(c, i, tBeg, iMidi, forPlay, isLastTrack, instrument); + iMidi += numByte; + } + } + } else { + curList = c.getNoteListByChannel(channel); + if (curList.getLen() > 0 && (!forPlay || c.isPlayChan(i))) { // track is not empty + isLastTrack = true; + int numByte = writeTrack(c, channel, tBeg, iMidi, forPlay, isLastTrack, instrument); + iMidi += numByte; + } + } + /// end print + int df = 0; + try { + /*if(file == null) + //file = new File(); + file = new SiemensFile();*/ + try { + if (file.exists(outStr) >= 0) { + file.delete(outStr); + } + } catch (/*IllegalArgument*/Exception e) { + } + + df = file.open(outStr, true); + + url = file.getURL(); + + file.write(df, bMidi, 0, iMidi); + file.close(df); + return file.getAns(); + } catch (IOException e) { + //throw new Exception("IO:writeMixWithName()\n"+e.toString()+"\noutStr="+outStr); + throw new Exception("Can't write " + outStr); + } finally { + //file.close(df); + seekPos = seekLen; + } + + } + + private int writeTrack(Composition c, int ch, int tBeg, int begInd, boolean forPlay, boolean isLastTrack, int instrument) throws Exception { + int ind = begInd; + int i; + /// track -------------- + /// print MTrk (4) + for (i = 0; i < MTRK.length; ++i) { + bMidi[ind++] = MTRK[i]; + } + + /// print track lenght (4) + int lenInd = ind; + //// write later + ind += 4; + int msgBegInd = ind; + if (instrument == -1) { + instrument = c.getInstrument(ch); + } + if (instrument != Composition.NOTHING && instrument != -1/*Drums*/) { + bMidi[ind] = (byte) 0; + bMidi[ind + 1] = (byte) (0xc0 | (0x0f & ch)); + bMidi[ind + 2] = (byte) (instrument); + ind += 3; + } + + //NoteList notes = c.getNoteListByChannel(ch); + + /// print notes + + byte[] volumeExpArr = c.getVolumeExpArr(); + + //int iMax = bMidi.length - 200; +/* seekLen = mix.getLen()+1; + seekPos = 1; + cancelStatus = false;*/ + int vol; + int kVol = 256 / c.channelVolExpMax; + byte[] tnote; + int tPrev = tBeg; + + if (forPlay/* && false*/) { + int dTime = 2 * Constants.timeConst; + tnote = getVarLenRepr(/*dTime*/0); // Delta-Time + for (i = tnote.length - 1; i >= 0; --i, ++ind) { + bMidi[ind] = tnote[i]; + } + + //bMidi[ind++] = (byte) (Constants.timeConst * 2) + maxTime - tPrev; + bMidi[ind++] = (byte) (ch | ((byte) 0x90/*0x80*/)); + //bMidi[ind++] = (byte) 0x99; + bMidi[ind++] = (byte) 0x2e; + bMidi[ind++] = (byte) 0x01; + + tnote = getVarLenRepr(/*dTime*/dTime - 0); // Delta-Time + for (i = tnote.length - 1; i >= 0; --i, ++ind) { + bMidi[ind] = tnote[i]; + } + bMidi[ind++] = (byte) (ch | ((byte) 0x80)); + //bMidi[ind++] = (byte) 0x99; + bMidi[ind++] = (byte) 0x2e; + bMidi[ind++] = (byte) 0x00; + + + //tPrev -= dTime; + //tPrev =0; + } + for (Note note = c.getFirstNote(tBeg, ch); note != null; note = note.prev) { + if (note instanceof NoteLong) { + NoteLong tempoNote = (NoteLong) note; + byte[] dat = tempoNote.dat; + if ((dat[0] == (byte) 0xff && dat[1] == (byte) 0x51)) { //////write tempo + bMidi[ind++] = (byte) 0x0; + for (i = 0; i < dat.length; ++i, ind++) { + bMidi[ind] = dat[i]; + } + break; + } + } + } + + + for (Note note = c.getFirstNote(tBeg, ch); note != null/* && ind= bMidi.length - 400) { + if (increaseBuffer() == false) { + break; + } + } + + /// calc maxTime for set end Note + if (note.t > maxTime) { + maxTime = note.t; + } + + tnote = getVarLenRepr(note.t - tPrev); // Delta-Time + if (tnote.length == 0) { + throw new Exception("len==0"); + } + + for (i = tnote.length - 1; i >= 0; --i, ++ind) { + bMidi[ind] = tnote[i]; + } + + if (note instanceof NoteLong) { + NoteLong notelong = (NoteLong) note; + for (i = 0; i < notelong.dat.length; ++i, ind++) { + bMidi[ind] = notelong.dat[i]; + } + + } else // simple Note + { + + bMidi[ind] = (byte) (note.c | ((note.v == 0) ? (byte) 0x80 : (byte) 0x90)); + + //bMidi[iMidi]=(byte)0x99; // 0x99 -- Note On + bMidi[ind + 1] = note.n; + //bMidi[iMidi+2]=note.v; edit 08.07.2004 + if ((note.v & 0x80) != 0) { + note.v = 0x7f; + } + vol = note.v + kVol * (volumeExpArr[note.c] - c.channelVolExpMax / 2); //*( 1<<(volumeExpArr[note.c]/2))/0x10000; + if (vol > 127) { + vol = 127; + } else if (vol < 0) { + vol = 0; + } + bMidi[ind + 2] = (byte) vol; + /////////// + ind += 3; + } + tPrev = note.t; + seekPos++; + Thread.yield(); + } + /// print last note + if (forPlay && isLastTrack/* && false*/) { + tnote = getVarLenRepr((Constants.timeConst * 2) + maxTime - tPrev); // Delta-Time + for (i = tnote.length - 1; i >= 0; --i, ++ind) { + bMidi[ind] = tnote[i]; + } + + //bMidi[ind++] = (byte) (Constants.timeConst * 2) + maxTime - tPrev; + bMidi[ind++] = (byte) 0x99; + bMidi[ind++] = (byte) 0x2e; + bMidi[ind++] = (byte) 0x01; + } + + + /// print end track (4) + for (i = 0; i < ENDTrk.length; ++i) { + bMidi[ind++] = ENDTrk[i]; + } + + + writeIntBigEnding(bMidi, lenInd, ind - msgBegInd, 4); ///////????? + + return ind - begInd; + } + + private void writeIntBigEnding(byte[] dest, int begInd, int src, int numBytesToWrite) { + int t = src; + int ind = begInd + numBytesToWrite - 1; + for (; ind >= begInd; --ind) { + dest[ind] = (byte) t; + t >>= 8; + } + return /*numBytesToWrite*/; + } +// private byte getVolume + + public byte[] writeNote(byte instr, byte nn)//+ + { +// outStr = ""+nn+".mid"; + //outStr = "note.mid"; + // mod.msg("len dat ."+dat.length+" "); + //byte[] b = new byte[dat4PlayNote.length]; + //for(int i=0; i"); + throw new Exception("Can't read:\n" + e.getMessage()); + } finally { + file.close(df); + seekPos = seekLen; + } + // mod.msgAll("mix.add ok"); +// Composition c = new Composition(mix); + return composition; + } + + private int readTimeDelta(int df) throws IOException { + int timeDelta = 0; + //int i=0; + byte[] buf = new byte[1]; + do { + file.read(df, buf, 0, 1); + timeDelta = (timeDelta << 7) + (buf[0] & (byte) 0x7f); + //i++; + seekPos++; + } while ((buf[0] & (byte) 0x80) != 0); + + return timeDelta; + } + + private int readInt(int df, int len) throws IOException { + // byte[] buf = new byte[1]; + int t = 0; + int i; + for (i = 0; i < len; ++i) { + file.read(df, bufTmp, 0, 1); + t = (t << 8) | 0xff & bufTmp[0]; + } + seekPos += len; + return t; + } + + private void skip(int df, int n) throws IOException { + /* if(n>0) + { + byte[] buf = new byte[n]; + file.read(df, bufTmp,0,n); + seekPos += n; + }*/ + while (n > 0) { + intTmp = (n > bufTmp.length) ? bufTmp.length : n; + file.read(df, bufTmp, 0, intTmp); + seekPos += intTmp; + n -= intTmp; + } + } + + public int getCurPercent() { + return seekPos * 100 / seekLen; + } + + public void reset() { + seekPos = 0; + seekLen = 4; + cancelStatus = false; + } + + public void cancel() { + cancelStatus = true; + } +} diff --git a/src/midedit/MixerCanvas.java b/src/midedit/MixerCanvas.java new file mode 100644 index 0000000..b60593d --- /dev/null +++ b/src/midedit/MixerCanvas.java @@ -0,0 +1,1766 @@ +package midedit; + + +import midedit.media.Composition; +import java.util.*; +import java.io.*; +import javax.microedition.lcdui.*; + +/** + * + * @author user + */ +abstract public class MixerCanvas extends Canvas implements Runnable +{ + + private static final Font defFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); + + protected Composition composition; + protected int channel; + private Options options; + private boolean isOptionsView = false, + isMarkMode = false, + isMoveMode = false, + isModeDesc = false, + isNumsControl = (Settings.settingsIndex[4] == 1) ? true : false; + private Status status; + private MixerMain control; + private MixerModel model; + private Display display = MixerMain.display; + private Thread playingThread ; + private final Runnable playingRunnable= new Runnable() { + + public void run() { + System.out.println("getTimeToCanvasConct() = " + composition.getTime2CanvasConst()); + System.out.println("Thread.currentThread = " + Thread.currentThread()); + while (CompositionForm.isPlaying) { + try { + doSmallRight(); + Thread.sleep(31); + } catch (InterruptedException ex) { + System.out.println("ex = " + ex); + } + } + } + } ; + + + /** + * + * @param ctrl + * @param c + * @param ch + */ + public MixerCanvas(MixerMain ctrl, Composition c, int ch) { + //if (MixerMain.IS_MIDP2) + setFullScreenMode(true); + control = ctrl; + composition = c; + channel = ch; + wOne = Settings.settingsIndex[1]; + hOne = Settings.settingsIndex[0]; + screenHeight = getHeight(); + screenWidth = getWidth(); + statusBegY = screenHeight - statusHeight; + nW = (screenWidth - wBeg - 5) / wOne; + nH = (screenHeight - statusHeight - 12) / hOne; + rollWidth = (nW * wOne + 1); + rollHeight = (nH * hOne + 1); + model = control.getModel(); + runningStatus = true; + options = new Options(); + status = new Status(); + frameCount = 0; + viewModeDesc("Edit Mode"); + display.callSerially(this); + } + + /** + * + * @param ch + * @return + */ + abstract protected int getNoteFromLine(int ch); + + /** + * + * @param n + * @return + */ + abstract protected byte getLineFromNote(int n); + + /** + * + * @param keyCode + */ + protected void keyPressed(int keyCode) { + keyCodePressed = keyCode; + if (isOptionsView) { + options.keyPressed(keyCodePressed); + return; + } + if (keyPressedCount == 0) { + keyPressedCount = 1; + } + int gameAction=0; + try{ + gameAction = getGameAction(keyCodePressed); + } + catch (IllegalArgumentException illegArg){ + } + if ((gameAction == FIRE)&(keyCodePressed!=-1)&(keyCodePressed!=-4)) { + doKEY_NUM5(); + needPaint = true; + needPaintStatus = true; + return/*break*/; + } else if (gameAction == LEFT||keyCodePressed==KEY_NUM4) { + if (isNumsControl^(keyCodePressed==KEY_NUM4)) + doBigLeft(); + else + doSmallLeft(); + status.resetTimeTune(); + return; + } else if (gameAction == RIGHT||keyCodePressed==KEY_NUM6) { + if (isNumsControl^(keyCodePressed==KEY_NUM6)) + doBigRight(); + else + doSmallRight(); + status.resetTimeTune(); + return; + } else if (gameAction == UP||keyCodePressed==KEY_NUM2) { + if (isNumsControl^(keyCodePressed==KEY_NUM2)) + doBigUp(); + else + doSmallUp(); + status.resetTimeTune(); + return; + } else if (gameAction == DOWN||keyCodePressed==KEY_NUM8) { + if (isNumsControl^(keyCodePressed==KEY_NUM8)) + doBigDown(); + else + doSmallDown(); + status.resetTimeTune(); + return; + } + switch (keyCodePressed) { + case KEY_NUM1: + playFromCurrentPosition(); + break; + case KEY_NUM3: + model.playNote((byte) ((channel == Constants.DRUMS_CHANNEL) ? -10 : composition.getInstrument(channel)), + (byte) getNoteFromLine(curY)); + break; + + case KEY_NUM7: + case -10: case -4: + status.nextView(); + needPaintStatus = true; + break; + case KEY_NUM9: + case -8: + doKEY_NUM9(); + needPaint = true; + needPaintStatus = true; + break; + case KEY_NUM0: + status.action(); + needPaintStatus = true; + break; + case KEY_STAR: + status.curParamMinus(); + needPaintStatus = true; + break; + case KEY_POUND: + status.curParamPlus(); + needPaintStatus = true; + break; + case -6: case -1: + isOptionsView = true; + options.resetMenu(); + break; + case -7: case -12: + CompositionForm.curForm.setComposForm(); + break; + case -11: + composition.getUndoableAction().undo(); + needPaintStatus = true; + needPaint = true; + break; + case -36: + status.volumePlus(); + needPaintStatus = true; + break; + case -37: + status.volumeMinus(); + needPaintStatus = true; + break; + default: + isOptionsView = true; + options.resetMenu(); + break; + } + } + + private void doSmallLeft() { + if (curX > 0) { + curX--; + } else { + if (xBase >= wStep) { + xBase -= wStep; + curX += wStep - 1; + } else if (xBase > 0) { + curX += xBase - 1; + xBase = 0; + } + needPaint = true; + needPaintStatus = true; + } + } + + ; + + private void doSmallRight() { + if (curX < nW - 1) { + curX++; + } else { + xBase += wStep; + curX -= wStep - 1; + needPaint = true; + needPaintStatus = true; + } + } + + ; + + private void doSmallUp() { + if (curY > 0) { + curY--; + } else if (hBase >= hStep + hMin) { + hBase -= hStep; + curY += hStep - 1; + needPaint = true; + needPaintStatus = true; + } + } + + ; + + protected void doSmallDown() { + if (curY < nH - 1) { + curY++; + } else if (hBase + curY < hMax) { + hBase += hStep; + curY -= hStep - 1; + needPaint = true; + needPaintStatus = true; + } + } + + ; + + private void doBigLeft() { + wStepMeasure = (composition.getNom() * (32 >> composition.getDenomE())); + if (xBase >= wStepMeasure) { + xBase -= wStepMeasure; + needPaint = true; + needPaintStatus = true; + } + } + + ; + + private void doBigRight() { + wStepMeasure = (composition.getNom() * (32 >> composition.getDenomE())); + xBase += wStepMeasure; + needPaint = true; + needPaintStatus = true; + } + + ; + + private void doBigUp() { + if (curY >= hStep) { + curY -= hStep; + } else if (hBase >= hMin + hStep) { + hBase -= hStep; + needPaint = true; + } + needPaint = true; + needPaintStatus = true; + } + + ; + + private void doBigDown() { + if (curY < nH - hStep) { + curY += hStep; + } else if (hBase + curY < hMax - hStep) { + hBase += hStep; + needPaint = true; + } + needPaint = true; + needPaintStatus = true; + } + + ; + + /** + * + * @return + */ + protected boolean doKEY_NUM5() + { + if (isMoveMode == false && isMarkMode == false && curNote != null) { + timeMarkBeg = getCurTime(); + timeMarkEnd = getCurTime(); + setMarkModeOn(); + } + + if (isMoveMode) + { + int noteShift = getCurNote() - OrigNote; + if (this instanceof DrumsCanvas) { + noteShift = -noteShift; + } + NoteListUtils.doMove(composition, (byte) channel, + getCurTime() - OrigTime, + noteShift, status.getVolTune()); + isMoveMode = false; + setMarkModeOff(); + return true; + } else if (isMarkMode) { + if (curNote != null) { + + if (curNote.len > 0) { + Note noteTmp; + for (noteTmp = curNote.next; noteTmp != null && + (noteTmp.c != curNote.c || noteTmp.n != curNote.n || noteTmp.v != 0); + noteTmp = noteTmp.next); + + if (noteTmp != null && noteTmp.c == note.c && noteTmp.n == note.n) { + noteTmp.mark = (byte) (1 - curNote.mark); + } + } + + curNote.mark = (byte) (1 - curNote.mark); + + } else { + setMarkModeOff(); + } + timeMarkBeg = NOT_MARKED; + timeMarkEnd = NOT_MARKED; + return true; + } + + return false; + } + + /** + * + */ + private void doKEY_NUM9() { + if (isMarkMode) { + setMarkModeOff(); + return; + } + + if (curNote != null) { + composition.delNote(curNote.t, curNote.c, curNote.n, curNote.v); + } else { + composition.delNote(getCurTime(), (byte) channel, (byte) getNoteFromLine(curY), (byte) 127); + } + } + + private void playFromCurrentPosition() { + try { + if (CompositionForm.isPlaying){ + model.stopPlay(); + playingThread.join(); + } + else{ + model.playMix(composition, xBase * Constants.timeConst); + playingThread=new Thread(playingRunnable); + playingThread.start(); + System.out.println("CompositionForm.isPlaying = " + CompositionForm.isPlaying); + } + } catch (Exception e) { + System.out.println("Exception = " + e); + } + + } + + /** + * + * @param keyCode + */ + protected void keyReleased(int keyCode) { + if (keyPressedCount > 0) {int gameAction=0; + try{ + gameAction = getGameAction(keyCodePressed); + } + catch (IllegalArgumentException illegArg){ + } + if (keyCodePressed == KEY_NUM4 || keyCodePressed == KEY_NUM6 || + keyCodePressed == KEY_NUM2 || keyCodePressed == KEY_NUM8 || + keyCodePressed == KEY_POUND || keyCodePressed == KEY_STAR|| + gameAction==LEFT||gameAction==RIGHT||gameAction==UP||gameAction==DOWN) { + setNeedPaint(); + } + } + keyPressedCount = 0; + } + + /** + * + * @param g + */ + public void paint(Graphics g) { + g.translate(0 - g.getTranslateX(), 0 - g.getTranslateY()); + g.setClip(0, 0, screenWidth, screenHeight); + + if (isOptionsView) { + options.paint(g); + runningStatus = false; + return; + } + + if (keyPressedCount > 0) { + if (keyPressedCount < 25) + { + keyPressedCount++; + + } else{ + int gameAction=0; + try{ + gameAction = getGameAction(keyCodePressed); + } + catch (IllegalArgumentException illegArg){ + } + if (keyCodePressed == KEY_NUM4 || keyCodePressed == KEY_NUM6 || + gameAction==LEFT||gameAction==RIGHT||gameAction==UP||gameAction==DOWN|| + keyCodePressed == KEY_NUM2 || keyCodePressed == KEY_NUM8 || + keyCodePressed == KEY_POUND || keyCodePressed == KEY_STAR) { + isblack = true; + + + keyPressed(keyCodePressed); + }} + } + paintUniEditor(g); + + } + + /** + * + * @param g + */ + private void paintUniEditor(Graphics g) { + g.setColor(224, 192, 224); + g.setGrayScale(0); + g.setFont(MixerMain.SMALL_FONT); + if (needPaint == true) { + int tmpN = getNoteFromLine(curY); + if (tmpN < 0 || tmpN > 127) { + curY = 4; + } + paintRoll(g); + } + if (needPaintStatus == true) { + status.paint(g); + } + g.translate(wBeg - g.getTranslateX(), hBeg - g.getTranslateY()); + g.setColor(192, 192, 224); + xt = curXPrev * wOne; + yt = curYPrev * hOne + 1; + paintArrows(g, xt, yt); + if (isblack) { + g.setColor(192, 0, 0); + } else { + g.setColor(192, 192, 224); + } + xt = curX * wOne; + yt = curY * hOne + 1; + paintArrows(g, xt, yt); + curXPrev = curX; + curYPrev = curY; + isblack = !isblack; + if (isModeDesc && needPaint) { + paintModeDesc(g); + isModeDesc = false; + } + needPaint = false; + needPaintStatus = false; + } + + private void paintRoll(Graphics g) { + g.setColor(192, 192, 224); + g.fillRect(0, 0, screenWidth, statusBegY); + g.setColor(0); + g.drawRect(0, 0, screenWidth - 1, statusBegY); + paintScale(g); + g.translate(wBeg, hBeg); + g.setGrayScale(96); + for (yt = 0; yt < rollHeight; yt += hOne) { + g.drawLine(0, yt, rollWidth - 1, yt); + } + g.setColor(192, 160, 160); + yt = curY * hOne + 1 ; + g.fillRect(0, yt, rollWidth - 1, hOne - 1); + g.setGrayScale(96); + int vLineStep = 32 >> composition.getDenomE(); + if (vLineStep == 0) { + vLineStep = 1; + } + for (xt = (vLineStep - xBase % vLineStep) * wOne; xt < rollWidth; xt += vLineStep * wOne) { + g.drawLine(xt, 0, xt, rollHeight - 1); + } + vLineStep = vLineStep * composition.getNom(); + g.setColor(0); + for (xt = (vLineStep - xBase % vLineStep) * wOne; xt < rollWidth; xt += vLineStep * wOne) { + g.drawLine(xt, 0, xt, rollHeight - 1); + } + g.setClip(1, -2, rollWidth - 2, rollHeight + 4); + g.setColor(0); + tBeg = (xBase - 2 * (1 << Constants.MAX_NOTE_LENGTH)) * Constants.timeConst; + tMax = (xBase + nW) * Constants.timeConst; + curTime = getCurTime(); + int curTimePlus = curTime + Constants.timeConst - 1; + int curN = getNoteFromLine(curY); + curNote = null; + g.setGrayScale(0); + for (note = composition.getFirstNote(tBeg, channel); + note != null && note.t <= tMax; note = note.next) { + if (note.c == channel && note.v != 0) { + if (note.t <= curTimePlus && note.n == curN && + (curTime < note.t + (note.len == 0 ? 1 : note.len))) { + curNote = note; + if (!isMarkMode) { + g.setColor(150, 0, 0); + } else if (curNote.mark == NoteListUtils.NOTE_NOT_MARKED) { + g.setColor(128, 0, 0); + } else { + g.setColor(150, 0, 0); + } + paintNote(g, note, 0, 0); + g.setColor(0); + } else if (note.mark == NoteListUtils.NOTE_MARKED) { + g.setColor(150, 0, 0); + paintNote(g, note, 0, 0); + g.setColor(0); + } else { + int col = (256 - note.v); + g.setColor(col, 0, 140); + paintNote(g, note, 0, 0); + } + } + } + if (isMoveMode) + { + int shiftTime = getCurTime() - OrigTime; + int shiftNote = getCurNote() - OrigNote; + + if (this instanceof DrumsCanvas) { + shiftNote = -shiftNote; + } + + for (note = composition.getUndoableAction().getDeletedList().getFirst(); + note != null; note = note.next) { + if (note.c == channel && note.v != 0) { + g.setColor(128, 0, 0); + paintNote(g, note, shiftTime, shiftNote); + g.setColor(0); + } + } + } + g.setClip(-wBeg, -hBeg, screenWidth, statusBegY); + g.setColor(192, 160, 160); + xt = curX * wOne; + g.drawLine(xt, 0, xt, rollHeight - 1); + g.setGrayScale(0); + g.drawRect(0, 0, rollWidth - 1, rollHeight - 1); + paintMarked(g); + g.translate(0 - g.getTranslateX(), 0 - g.getTranslateY()); + g.setClip(0, 0, getWidth(), getHeight()); + } + + private void paintMarked(Graphics g) { + g.setColor(64, 32, 224); + + int n = getX(timeMarkBeg); + xt = n * wOne; + if (n >= 0 && n < nW) { + g.drawLine(xt, -1, xt, rollHeight); + g.drawLine(xt, -1, xt + wOne, -1); + g.drawLine(xt, rollHeight, xt + wOne, rollHeight); + } + + n = getX(timeMarkEnd); + xt = n * wOne; + if (n > 0 && n < nW) { + g.drawLine(xt, -1, xt, rollHeight); + g.drawLine(xt, -1, xt - wOne, -1); + g.drawLine(xt, rollHeight, xt - wOne, rollHeight); + } + + } + + private void paintArrows(Graphics g, int x, int y) { + yt = -2; + for (dy = 0; dy < 3; ++dy) { + g.drawLine(x - dy, yt - dy, x + dy, yt - dy); + } + yt = rollHeight + 1; + for (dy = 0; dy < 3; ++dy) { + g.drawLine(x - dy, yt + dy, x + dy, yt + dy); + } + xt = -13; + for (dx = 0; dx < 3; ++dx) { + g.drawLine(xt - dx, y - dx, xt - dx, y + dx); + } + xt = rollWidth; + for (dx = 0; dx < 3; ++dx) { + g.drawLine(xt + dx, y - dx, xt + dx, y + dx); + } + + } + + /** + * + * @param g + * @param note + * @param shiftTime + * @param shiftNote + */ + protected void paintNote(Graphics g, Note note, int shiftTime, int shiftNote) { + xt = getXInPixel(note.t + shiftTime); + yt = getLineFromNote(note.n + shiftNote); + if (xt >= 0 && xt < rollWidth) { + if (yt < 0) { + yt = -1; + } else if (yt >= nH) { + yt = nH; + } + + g.fillRect(xt + 1 , yt * hOne + 1 , 2, hOne - 1); + } + } + + /** + * + * @param g + */ + protected void paintScale(Graphics g) { + g.drawLine(4, hBeg, 4, hBeg + rollHeight - 1); + g.drawLine(wBeg - 2, hBeg, wBeg - 2, hBeg + rollHeight - 1); + int hhtmp; + int blackButHeight = hOne + 1; + int blackButYBeg; + for (hhBase = hBeg; hhBase < hBeg + rollHeight - 1; hhBase += hOne * 12) { + g.drawLine(3, hhBase, wBeg - 2, hhBase); + blackButYBeg = hhBase + 1 - hOne / 2; + g.fillRect(4, blackButYBeg + hOne, wBeg - 10, blackButHeight); + g.fillRect(4, blackButYBeg + 3 * hOne, wBeg - 10, blackButHeight); + g.fillRect(4, blackButYBeg + 5 * hOne, wBeg - 10, blackButHeight); + g.fillRect(4, blackButYBeg + 8 * hOne, wBeg - 10, blackButHeight); + g.fillRect(4, blackButYBeg + 10 * hOne, wBeg - 10, blackButHeight); + hhtmp = hhBase + hOne + 1; + g.drawLine(4, hhtmp, wBeg - 2, hhtmp); + hhtmp = hhBase + 3 * hOne + 1; + g.drawLine(4, hhtmp, wBeg - 2, hhtmp); + hhtmp = hhBase + 5 * hOne + 1; + g.drawLine(4, hhtmp, wBeg - 2, hhtmp); + hhtmp = hhBase + 7 * hOne; + g.drawLine(4, hhtmp, wBeg - 2, hhtmp); + hhtmp = hhBase + 8 * hOne + 1; + g.drawLine(4, hhtmp, wBeg - 2, hhtmp); + hhtmp = hhBase + 10 * hOne + 1; + g.drawLine(4, hhtmp, wBeg - 2, hhtmp); + } + g.drawLine(3, hhBase, wBeg - 2, hhBase); + } + + private void paintModeDesc(Graphics g) { + int DESC_WIDTH = screenWidth; + int DESC_HEIGHT = statusHeight; + int DESC_BEGX = (screenWidth - DESC_WIDTH) / 2; + int DESC_BEGY = statusBegY; + + g.translate(0 - g.getTranslateX(), 0 - g.getTranslateY()); + g.setColor(160, 160, 224); + g.setClip(DESC_BEGX, DESC_BEGY, DESC_WIDTH, DESC_HEIGHT); + g.fillRect(DESC_BEGX, DESC_BEGY, DESC_WIDTH, DESC_HEIGHT); + g.setColor(0); + g.drawRect(DESC_BEGX, DESC_BEGY, DESC_WIDTH - 1, DESC_HEIGHT - 1); + int nInd = modeDesc.indexOf('\n'); + int strY; + if (nInd > 0) { + strY = DESC_BEGY + (DESC_HEIGHT - 2 * defFont.getBaselinePosition()) / 2; + if (DESC_HEIGHT < 2 * defFont.getHeight()) { + modeDesc = modeDesc.replace('\n', ' '); + strY = DESC_BEGY + (DESC_HEIGHT - defFont.getBaselinePosition()) / 2; + } + } else { + strY = DESC_BEGY + (DESC_HEIGHT - defFont.getBaselinePosition()) / 2; + } + g.drawString(modeDesc, DESC_BEGX + DESC_WIDTH / 2, + strY, Graphics.TOP | Graphics.HCENTER); + } + + /** + * + */ + public void setNeedPaint() { + needPaint = true; + needPaintStatus = true; + } + + /** + * + */ + public void run() { + try { + if (runningStatus) { + repaint(); + frameCount++; + if (frameCount % 200 == 0) { +// str = " "; + System.gc(); + } + Thread.sleep(10); + display.callSerially(this); + + } + } catch (Exception e) { +// errStr = "" + e + "\n"; + } + } + + /** + * + * @return + */ + protected int getCurTime() { + return (xBase + curX) * Constants.timeConst + status.getTimeTune(); + } + + /** + * + * @param t + * @return + */ + private int getX(int t) { + return t / Constants.timeConst - xBase; + } + + /** + * + * @param t + * @return + */ + protected int getXInPixel(int t) { + return t * wOne / Constants.timeConst - xBase * wOne; + } + + /** + * + * @return + */ + protected int getCurNote() { + return Constants.INV_CANVAS_CONST - (hBase + curY); + } + + /** + * + * @return + */ + protected byte getCurVol() { + return (byte) status.getVolTune(); + } + + /** + * + * @return + */ + protected int getCurLen() { + return status.getLenTune(); + } + + /** + * + */ + protected void showNotify() { + setNeedPaint(); + runningStatus = true; + display.callSerially(this); + } + + /** + * + */ + protected void hideNotify() { + runningStatus = false; + curNote = null; + } + + /** + * + */ + private void setMarkModeOn() { + if (timeMarkBeg != NOT_MARKED && timeMarkEnd != NOT_MARKED && timeMarkBeg <= timeMarkEnd) { + if (isMarkMode) { + NoteListUtils.unMarkNotes(composition, (byte) channel); + } + isMarkMode = true; + model.getBuffer().copy2Buffer(composition, (byte) channel, timeMarkBeg, timeMarkEnd, true); + + viewModeDesc("Mark Mode"); + } + note = composition.getFirstNote(timeMarkEnd, channel); + } + + /** + * + */ + private void setMarkModeOff() { + NoteListUtils.unMarkNotes(composition, (byte) channel); + isMarkMode = false; + timeMarkBeg = NOT_MARKED; + timeMarkEnd = NOT_MARKED; + viewModeDesc("Edit Mode"); + } + + private void viewModeDesc(String desc) { + isModeDesc = true; + modeDesc = desc; + } + private final static int NOT_MARKED = -1000; + private int OrigTime, + OrigNote, + statusHeight = 21, + screenHeight, + screenWidth, + statusBegY, + nW, + keyCodePressed = KEY_NUM1; + protected int + curY, + hMin, + hMax = 15, + hBase, + hStep = 12, + wBeg = 16, + hBeg = 5, + wOne = Settings.settingsIndex[1], + hOne = Settings.settingsIndex[0], + nH, + rollWidth, + rollHeight; + //protected String str = " Hello "; + static private Image statusImg, + statusImgSel, statusImgCur, statusImgData, statusImgDataCur, + imgDot, imgTriplet; + public static int curX, + xBase; + private String modeDesc = ""; + private boolean runningStatus, + needPaintStatus, + needPaint, + isblack; + private int keyPressedCount, + curYPrev, + curXPrev, + wStep = 5, + wStepMeasure = 32, + frameCount, + xt, yt, + dx, dy, + tBeg, tMax, + curTime, + hhBase, + timeMarkBeg = NOT_MARKED, + timeMarkEnd = NOT_MARKED; + private Note note, + curNote, + noteDelta; + + static { + try { + statusImg = Image.createImage("/img/attr.png"); + statusImgSel = Image.createImage("/img/attractive.png"); + statusImgCur = Image.createImage("/img/attrcur.png"); + statusImgDataCur = Image.createImage("/img/attrdatacur.png"); + statusImgData = Image.createImage("/img/attrdata.png"); + imgDot = Image.createImage("/img/dot.png"); + imgTriplet = Image.createImage("/img/triplet.png"); + } catch (IOException ex) { + } + } + + + private class Status { + + private int statusMode; + private final static int MODE_NONE = -1, + MODE_TIME = 0, + MODE_LEN = 1, + MODE_NOTE = 2, + MODE_VOL = 3, + STATUS_ONE_BUT = 25, + STATUS_BUT_HEIGHT = 9; + private int[] params; + private int[] absParams; + private int[] deltaParams; + private int pCount = 4; + private int indCurNoteLen; + private byte[] noteLen = {1, 2, 4, 8, 16, 32}; + private int extLen; + + public Status() { + statusMode = MODE_NONE; + if (MixerCanvas.this instanceof DrumsCanvas) { + statusMode = MODE_NOTE; + } + + + absParams = new int[pCount]; + deltaParams = new int[pCount]; + params = absParams; + + params[MODE_TIME] = 0; + params[MODE_LEN] = 10; + params[MODE_NOTE] = 0; + params[MODE_VOL] = 90; + + resetDelta(); + + indCurNoteLen = 3; + extLen = 0; + calcLen(); + } + + private void resetDelta() { + deltaParams[MODE_TIME] = 0; + deltaParams[MODE_LEN] = 0; + deltaParams[MODE_NOTE] = 0; + deltaParams[MODE_VOL] = 0; + + } + + private void setAbsParams() { + params = absParams; + } + + private void setDeltaParams() { + params = deltaParams; + } + + private void nextView() { + statusMode++; + if (statusMode >= pCount) { + statusMode = MODE_NONE; + } + if (params == deltaParams) { + if (!isValidTab()) { + nextView(); + } + } + + } + + private boolean isValidTab() { + boolean ok = true; + if (params == deltaParams && (statusMode == 1 || statusMode == 2)) { + ok = false; + } + return ok; + } + + private void resetTimeTune() { + params[MODE_TIME] = 0; + } + + private void curParamPlus() { + if (curNote != null && noteDelta != null) { + return; + } + + switch (statusMode) { + case MODE_TIME: + if (params[MODE_TIME] < Constants.timeConst - 1) { + params[MODE_TIME] += 1; + } + break; + case MODE_LEN: + if (indCurNoteLen < noteLen.length - 1) { + indCurNoteLen++; + } + calcLen(); + break; + case MODE_NOTE: + break; + case MODE_VOL: + if (params[MODE_VOL] < 127) { + params[MODE_VOL] += 1; + } + break; + } + } + + private void curParamMinus() { + if (curNote != null && noteDelta != null) { + return; + } + + switch (statusMode) { + case MODE_TIME: + if (params[statusMode] > 0) { + params[statusMode] -= 1; + } + break; + case MODE_LEN: + if (indCurNoteLen > 0) { + indCurNoteLen--; + } + calcLen(); + break; + case MODE_NOTE: + break; + case MODE_VOL: + if (params == absParams) { + if (params[statusMode] > 1) { + params[statusMode] -= 1; + } + } else if (params == deltaParams) { + if (params[statusMode] > -127) { + params[statusMode] -= 1; + } + } + break; + } + } + + private void volumePlus() { + if (curNote != null && noteDelta != null) { + return; + } + + + if (params[MODE_VOL] < 127) { + params[MODE_VOL] += 1; + } + + } + + private void volumeMinus() { + if (curNote != null && noteDelta != null) { + return; + } + if (params[MODE_VOL] > 0) { + params[MODE_VOL]--; + } + + + } + + private int getTimeTune() { + return params[MODE_TIME]; + } + + private byte getVolTune() { + return (byte) params[MODE_VOL]; + } + + private void calcLen() { + int len = Constants.timeConst * noteLen[indCurNoteLen]; + switch (extLen) { + case 0: + break; + case 1: + len = len * 3 / 2; + break; + case 2: + len = len * 2 / 3; + break; + } + params[MODE_LEN] = len; + } + + private int getLenTune() { + return params[MODE_LEN]; + } + + private void action() + { + if (statusMode == MODE_LEN) { + extLen = (extLen + 1) % 3; + calcLen(); + } + } + + public void paint(Graphics g) { + g.translate(0 - g.getTranslateX(), statusBegY - g.getTranslateY()); + g.setClip(0, 0, screenWidth, statusHeight); + boolean isCurNote = false; + if (isMoveMode == false) { + noteDelta = null; + setAbsParams(); + if (!isValidTab()) { + nextView(); + } + } else if (noteDelta == null) { + noteDelta = new Note(0, (byte) 0, (byte) 0, (byte) 0, 0); + setDeltaParams(); + resetDelta(); + } + if (curNote != null || isMoveMode) { + isCurNote = true; + } + int color = (isCurNote) ? 1 : 0; + g.drawImage(statusImg, 0, statusHeight, Graphics.LEFT | Graphics.BOTTOM); + if (screenWidth > statusImg.getWidth()) { + if (isCurNote) { + g.setColor(224, 160, 128); + } else { + g.setColor(160, 160, 224); + } + g.fillRect(statusImg.getWidth(), 0, screenWidth, statusHeight - STATUS_BUT_HEIGHT); + g.setColor(255, 255, 255); + g.fillRect(statusImg.getWidth(), statusHeight - STATUS_BUT_HEIGHT, screenWidth, statusHeight); + g.setColor(0, 0, 0); + g.drawLine(statusImg.getWidth(), statusHeight - STATUS_BUT_HEIGHT, screenWidth, statusHeight - STATUS_BUT_HEIGHT); + g.drawRect(statusImg.getWidth() - 1, 0, screenWidth - statusImg.getWidth(), statusHeight - 1); + } + + if (statusMode != MODE_NONE) { + g.setClip(statusMode * STATUS_ONE_BUT, statusHeight - STATUS_BUT_HEIGHT, + STATUS_ONE_BUT + 1, STATUS_BUT_HEIGHT); + if (isCurNote) { + g.drawImage(statusImgCur, 0, statusHeight, Graphics.LEFT | Graphics.BOTTOM); + } else { + g.drawImage(statusImgSel, 0, statusHeight, Graphics.LEFT | Graphics.BOTTOM); + } + + g.setClip(0, 0, screenWidth, statusHeight - STATUS_BUT_HEIGHT); + if (isCurNote) { + g.setColor(224, 160, 128); + } else { + g.setColor(160, 160, 224); + } + g.fillRect(0, 0, screenWidth, statusHeight - STATUS_BUT_HEIGHT); + g.setColor(0); + g.drawRect(0, 0, screenWidth - 1, statusHeight - STATUS_BUT_HEIGHT); + + } else { + g.setClip(0, 0, screenWidth, statusHeight - STATUS_BUT_HEIGHT); + if (isCurNote) { + g.drawImage(statusImgDataCur, 0, 0, Graphics.LEFT | Graphics.TOP); + } else { + g.drawImage(statusImgData, 0, 0, Graphics.LEFT | Graphics.TOP); + } + } + + g.setClip(0, 0, screenWidth, statusHeight - STATUS_BUT_HEIGHT); + int yIndent = 10; + int xIndent = 1; + int tick; + + if (isMoveMode) { + note = new Note(getTimeTune(), (byte) channel, (byte) 0, + getVolTune(), 0); + } else if (isCurNote) { + note = curNote; + } else { + note = new Note(getCurTime(), (byte) channel, (byte) getNoteFromLine(0), + getVolTune(), getLenTune()); + } + int m0, m1, m2, m3, m4; + int meterNom = composition.getNom(), meterDenom = 1 << composition.getDenomE(); + tick = composition.getTicksPer4() * 4 * meterNom / meterDenom; + int mod = (composition.getTicksPer4() << 2) >> (composition.getDenomE()); + switch (statusMode) { + case MODE_NONE: + m1 = 25; + m2 = 50; + m3 = 75; + m4 = 100; + PrintSmallFont.print(g, note.t * 100 / tick, 2, m1 - xIndent, yIndent, color); + PrintSmallFont.print(g, note.len * 1000 / tick, 3, m2 - xIndent, yIndent, color); + + if (MixerCanvas.this instanceof NotesCanvas) { + PrintSmallFont.printNote(g, note.n % 12, m3 - xIndent, yIndent, color); + PrintSmallFont.print(g, note.n / 12, 0, m3 - xIndent - 12, yIndent, color); + } else { + PrintSmallFont.print(g, note.n, 0, m3 - xIndent - 12, yIndent, color); + } + + PrintSmallFont.print(g, note.v, 0, m4 - xIndent, yIndent, color); + + break; + case 0: + m1 = 25; + m2 = 38; + m3 = 55; + m4 = 70; + + PrintSmallFont.print(g, note.t / tick, 0, m1, yIndent, color); + g.drawLine(m1 + 1, yIndent - 4, m1 + 1, yIndent - 4); + g.drawLine(m1 + 1, yIndent - 2, m1 + 1, yIndent - 2); + PrintSmallFont.print(g, (note.t * meterNom / tick) % meterNom, 0, m2, yIndent, color); + g.drawLine(m2 + 1, yIndent - 4, m2 + 1, yIndent - 4); + g.drawLine(m2 + 1, yIndent - 2, m2 + 1, yIndent - 2); + PrintSmallFont.print(g, note.t % mod, 0, m3, yIndent, color); + PrintSmallFont.print(g, mod, 0, m4, yIndent, color); + + break; + case 1: + m1 = 41; + m2 = 58; + m3 = 75; + m4 = 90; + m0 = 15; + + if (!isCurNote) { + PrintSmallFont.print(g, 1, 0, m0, yIndent, color); + g.drawLine(m0 + 1, yIndent, m0 + 3, yIndent - 5); + PrintSmallFont.print(g, noteLen[noteLen.length - 1 - indCurNoteLen], 0, m0 + 13, yIndent, color); + + switch (extLen) { + case 0: + break; + case 1: + g.drawImage(imgDot, m1, yIndent + 1, + Graphics.BOTTOM | Graphics.RIGHT); + break; + case 2: + g.drawImage(imgTriplet, m1, yIndent + 1, + Graphics.BOTTOM | Graphics.RIGHT); + break; + } + } + + PrintSmallFont.print(g, note.len * meterNom / tick, 0, m2, yIndent, color); + g.drawLine(m2 + 1, yIndent - 4, m2 + 1, yIndent - 4); + g.drawLine(m2 + 1, yIndent - 2, m2 + 1, yIndent - 2); + PrintSmallFont.print(g, note.len % mod, 0, m3, yIndent, color); + PrintSmallFont.print(g, mod, 0, m4, yIndent, color); + + break; + case 2: + if (MixerCanvas.this instanceof NotesCanvas) { + m3 = 50; + m4 = 75; + PrintSmallFont.printNote(g, note.n % 12, m3 - xIndent, yIndent, color); + PrintSmallFont.print(g, note.n / 12, 0, m3 - xIndent - 12, yIndent, color); + + PrintSmallFont.print(g, note.n, 0, m4 - xIndent - 12, yIndent, color); + } else if (MixerCanvas.this instanceof DrumsCanvas) { + m1 = 2; + g.setFont(MixerMain.SMALL_FONT); + g.drawString(getNoteFromLine(curY)+" "+Constants.getInstrName(getNoteFromLine(curY) - DrumsCanvas.drumsShift+145), + m1, yIndent + 3, Graphics.BOTTOM | Graphics.LEFT); + } + + break; + case 3: + m4 = 55; + + if (isMoveMode) { + g.drawString(Constants.getStringName(77), m4 - 18, yIndent + 3, Graphics.BOTTOM | Graphics.RIGHT); + + } + + PrintSmallFont.print(g, note.v, 0, m4 - xIndent, yIndent, color); + + break; + } + + needPaintStatus = false; + } + } + + private class Options implements CommandListener { + + private Menu menu; + private Menu mainMenu; + private int ONE_LINE_HEIGHT = 18; + private int menuNumLines = 5; + private int MENU_BEGX = 10; + private int MENU_BEGY = 10; + private int MENU_WIDTH = 100; + + public Options() { + //System.out.println(this.toString() + " created"); + if (screenHeight > 240) { + ONE_LINE_HEIGHT = 22; + MENU_WIDTH = 120; + } + + MENU_BEGX = (screenWidth - MENU_WIDTH) / 2; + MENU_BEGY = (screenHeight - menuNumLines * ONE_LINE_HEIGHT) / 4; + + + mainMenu = new Menu(Constants.getStringName(24), null, MENU_BEGX, MENU_BEGY, MENU_WIDTH, menuNumLines, ONE_LINE_HEIGHT); + + Menu playMenu = new Menu(Constants.getStringName(78), mainMenu, MENU_BEGX, MENU_BEGY, MENU_WIDTH, menuNumLines, ONE_LINE_HEIGHT); + MenuItem playAllItem = new MenuItem(Constants.getStringName(79), 0) { + + public boolean actionPerformed() { + try { + model.playMix(composition, 0); + } catch (Exception e) { + } + return true; + } + }; + playMenu.addItem(playAllItem); + MenuItem playItem = new MenuItem(Constants.getStringName(80), 0) { + + public boolean actionPerformed() { + try { + model.playMix(composition, xBase * Constants.timeConst); + } catch (Exception e) { + } + + return true; + } + }; + playMenu.addItem(playItem); + MenuItem playTrackAllItem = new MenuItem(Constants.getStringName(81), 0) { + + public boolean actionPerformed() { + try { + model.playTrack(composition, 0, channel); + } catch (Exception e) { + } + + return true; + } + }; + playMenu.addItem(playTrackAllItem); + MenuItem playTrackItem = new MenuItem(Constants.getStringName(82), 0) { + + public boolean actionPerformed() { + try { + model.playTrack(composition, xBase * Constants.timeConst, channel); + } catch (Exception e) { + } + + return true; + } + }; + playMenu.addItem(playTrackItem); + MenuItem stopItem = new MenuItem(Constants.getStringName(35), 0) { + + public boolean actionPerformed() { + model.stopPlay(); + return true; + } + }; + playMenu.addItem(stopItem); + + + mainMenu.addItem(playMenu); + + Menu editMenu = new Menu(Constants.getStringName(51), mainMenu, MENU_BEGX, MENU_BEGY, MENU_WIDTH, menuNumLines, ONE_LINE_HEIGHT); + + Menu markMenu = new Menu(Constants.getStringName(83), editMenu, MENU_BEGX, MENU_BEGY, MENU_WIDTH, menuNumLines, ONE_LINE_HEIGHT); + MenuItem item1 = new MenuItem(Constants.getStringName(84), KEY_NUM1); + markMenu.addItem(item1); + MenuItem item2 = new MenuItem(Constants.getStringName(85), KEY_NUM2); + markMenu.addItem(item2); + MenuItem item21 = new MenuItem(Constants.getStringName(86), 0) { + + public boolean actionPerformed() { + setMarkModeOff(); + return true; + } + }; + markMenu.addItem(item21); + editMenu.addItem(markMenu); + + MenuItem item22 = new MenuItem(Constants.getStringName(87), 0) { + + public boolean actionPerformed() { + isMoveMode = true; + NoteListUtils.deleteSelected(composition, (byte) channel); + OrigTime = getCurTime(); + OrigNote = getCurNote(); + viewModeDesc(Constants.getStringName(88)); + return true; + } + }; + editMenu.addItem(item22); + + MenuItem item3 = new MenuItem(Constants.getStringName(89), KEY_NUM3); + editMenu.addItem(item3); + + Menu menuPaste = new Menu(Constants.getStringName(90), editMenu, MENU_BEGX, MENU_BEGY, MENU_WIDTH, menuNumLines, ONE_LINE_HEIGHT); + MenuItem item4 = new MenuItem(Constants.getStringName(91), KEY_NUM4); + menuPaste.addItem(item4); + MenuItem item5 = new MenuItem(Constants.getStringName(92), KEY_NUM5); + menuPaste.addItem(item5); + MenuItem item6 = new MenuItem(Constants.getStringName(93), KEY_NUM6); + menuPaste.addItem(item6); + editMenu.addItem(menuPaste); + + MenuItem item8 = new MenuItem(Constants.getStringName(94), KEY_NUM8); + editMenu.addItem(item8); + MenuItem item7 = new MenuItem(Constants.getStringName(61), KEY_NUM7); + editMenu.addItem(item7); + mainMenu.addItem(editMenu); + + Menu undoMenu = new Menu(Constants.getStringName(29), mainMenu, MENU_BEGX, MENU_BEGY, MENU_WIDTH, menuNumLines, ONE_LINE_HEIGHT); + MenuItem itemStar = new MenuItem(Constants.getStringName(29), KEY_STAR); + undoMenu.addItem(itemStar); + MenuItem itemPound = new MenuItem(Constants.getStringName(95), KEY_POUND); + undoMenu.addItem(itemPound); + mainMenu.addItem(undoMenu); + + Menu helpMenu = new Menu(Constants.getStringName(96), mainMenu, MENU_BEGX, MENU_BEGY, MENU_WIDTH, menuNumLines, ONE_LINE_HEIGHT); + MenuItem mapItem = new MenuItem(Constants.getStringName(97), 0) { + + public boolean actionPerformed() { + Form form = new Form(Constants.getStringName(97), createStringItems(Constants.KEY_MAP)); + form.addCommand(CompositionForm.ok); + form.setCommandListener(Options.this); + MixerCanvas.this.display.setCurrent(form); + return true; + } + }; + helpMenu.addItem(mapItem); + MenuItem quickItem = new MenuItem(Constants.getStringName(98), 0) { + + public boolean actionPerformed() { + Form form = new Form(Constants.getStringName(98), createStringItems(Constants.QUICK_COMMANDS)); + form.addCommand(CompositionForm.ok); + form.setCommandListener(Options.this); + MixerCanvas.this.display.setCurrent(form); + return true; + } + }; + helpMenu.addItem(quickItem); + mainMenu.addItem(helpMenu); + MenuItem exitItem = new MenuItem(Constants.getStringName(25), 0) { + + public boolean actionPerformed() { + CompositionForm.curForm.setComposForm(); + return true; + } + }; + mainMenu.addItem(exitItem); + + menu = mainMenu; + + } + + private Item[] createStringItems(String strings[]) { + StringItem[] strItem = new StringItem[strings.length / 2]; + for (int i = 0; i < strings.length / 2; i++) { + strItem[i] = new StringItem(strings[i * 2], strings[i * 2 + 1], 1); + strItem[i].setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL)); + } + return strItem; + } + + public void commandAction(Command c, Displayable displayable) { + MixerCanvas.this.display.setCurrent(MixerCanvas.this); + } + + private void resetMenu() { + menu = mainMenu; + menu.reset(); + } + + protected void paint(Graphics g) { + menu.paint(g); + + } + + public void run() { + } + + private boolean processCommand(int keyCode) { + switch (keyCode) { + case KEY_NUM1: + timeMarkBeg = getCurTime(); + setMarkModeOn(); + break; + case KEY_NUM2: + timeMarkEnd = getCurTime(); + setMarkModeOn(); + break; + case KEY_NUM3: + model.getBuffer().copy2Buffer(composition, (byte) channel, timeMarkBeg, timeMarkEnd, false); + break; + case KEY_NUM4: + int shiftLen = model.getBuffer().paste2Composition(composition, (byte) channel, getCurTime(), NoteListUtils.INSERT); + setMarkModeOff(); + break; + case KEY_NUM5: + model.getBuffer().paste2Composition(composition, (byte) channel, getCurTime(), NoteListUtils.REPLACE); + setMarkModeOff(); + break; + case KEY_NUM6: + model.getBuffer().paste2Composition(composition, (byte) channel, getCurTime(), NoteListUtils.OVERWRITE); + setMarkModeOff(); + break; + case KEY_NUM7: + if (timeMarkBeg < timeMarkEnd) { + model.getBuffer().delete(composition, (byte) channel, timeMarkBeg, timeMarkEnd); + setMarkModeOff(); + } + break; + case KEY_NUM8: + + NoteListUtils.deleteSelected(composition, (byte) channel); + setMarkModeOff(); + + break; + case KEY_NUM9: + try { + model.playTrack(composition, xBase * Constants.timeConst, channel); + } catch (Exception e) { + } + break; + case KEY_NUM0: + try { + model.playTrack(composition, 0, channel); + } catch (Exception e) { + } + break; + case KEY_STAR: + composition.getUndoableAction().undo(); + break; + case KEY_POUND: + composition.getUndoableAction().redo(); + break; + case -10: + if (menu.getPrevMenu() != null) { + menu = menu.getPrevMenu(); + return false; + } + break; + default: + int dir=0; + try{ + dir=getGameAction(keyCode); + } + catch (IllegalArgumentException illegArg){} + switch (dir) { + case Canvas.UP: + menu.up(); + return false; + case Canvas.DOWN: + menu.down(); + return false; + case Canvas.RIGHT: + case Canvas.FIRE: + return menu.actionPerformed(); + case Canvas.LEFT: + case 0: + if (menu.getPrevMenu() != null) { + menu = menu.getPrevMenu(); + return false; + } + break; + default: + return false; + } + } + return true; + + } + + protected void keyPressed(int keyCode) { + if (processCommand(keyCode)) { + isOptionsView = false; + } + runningStatus = true; + setNeedPaint(); + display.callSerially(MixerCanvas.this); + } +// private int optXbeg = 8; +// private int optYbeg = 4; +// private int optWidth = (screenWidth - 2 * optXbeg); +// private int optHeight = (screenHeight - 2 * optYbeg); + + private class Menu extends MenuItem { + + private Vector items = null; + private Menu prevMenu; + private int x, y, w, h; + private int hMax; + private int lineBase, curLine; + private int numLines; + private int numLinesMaxVisible; + private int LINE_HEIGHT; + private boolean isScroll; + + private Menu(String name, Menu prev, + int x1, int y1, int width, + int nLines, int onelineHeight) { + super(name, 0); + + items = new Vector(); + prevMenu = prev; + x = x1; + y = y1; + w = width; + LINE_HEIGHT = onelineHeight; + numLinesMaxVisible = nLines; + numLines = 0; + h = numLinesMaxVisible * LINE_HEIGHT; + hMax = h + 1; + reset(); + } + + private void addItem(MenuItem item) { + items.addElement(item); + + numLines = hMax / LINE_HEIGHT; + if (numLines >= items.size()) { + numLines = items.size(); + isScroll = false; + } else { + isScroll = true; + } + + h = numLines * LINE_HEIGHT; + } + + protected void paint(Graphics g) { + g.translate(x, y); + + g.setColor(96, 64, 128); + g.fillRect(0, 1, w, LINE_HEIGHT - 1); + g.setColor(0); + g.drawRect(0, 1, w - 1, LINE_HEIGHT - 1); + g.setClip(0, 1, w - 1, LINE_HEIGHT - 1); + g.setColor(255, 255, 255); + + g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM)); + g.drawString(this.getName(), (w - 4) / 2, 3, + Graphics.TOP | Graphics.HCENTER); + g.setFont(Font.getDefaultFont()); + + g.setClip(0, 0, getWidth(), getHeight()); + g.translate(0, LINE_HEIGHT); + + g.setColor(0); + g.fillRect(0, 0, w, hMax); + g.setClip(1, 1, w - 1, hMax - 1); + MenuItem item; + int i; + for (i = 0; i < numLinesMaxVisible ; i++) { + + if (i == curLine) { + g.setColor(160, 160, 224); + } else { + g.setGrayScale(255); + } + + g.fillRect(0, i * LINE_HEIGHT + 1, w - 1, LINE_HEIGHT - 1); + + g.setGrayScale(0); + + if (i + lineBase < items.size()) { + item = (MenuItem) items.elementAt(lineBase + i); + g.drawString(item.getName(), 5, + i * LINE_HEIGHT + 2, Graphics.TOP | Graphics.LEFT); + if (item instanceof Menu) { + if (i == curLine) { + g.setColor(160, 160, 224); + } else { + g.setGrayScale(255); + } + g.fillRect(w - 6, i * LINE_HEIGHT + 1, 3, LINE_HEIGHT - 1); + + g.setColor(0); + int oxt = w - 3; + int oyt = i * LINE_HEIGHT + LINE_HEIGHT / 2; + for (int odx = 0; odx < 3; ++odx) { + g.drawLine(oxt - odx, oyt - odx, oxt - odx, oyt + odx); + } + + } + } + } + + } + + public boolean actionPerformed() { + MenuItem item = (MenuItem) items.elementAt(lineBase + curLine); + if (item instanceof Menu) { + ((Menu) item).reset(); + MixerCanvas.Options.this.menu = (Menu) item; + return false; + } + + return item.actionPerformed(); + + } + + private void up() { + if (lineBase + curLine > 0) { + if (isScroll && curLine <= 1 && lineBase > 0) { + lineBase--; + } else { + curLine--; + } + } else { + if (isScroll) { + curLine = numLines - 1; + lineBase = items.size() - numLines; + } else { + curLine = items.size() - 1; + } + } + } + + private void down() { + if (lineBase + curLine < items.size() - 1) { + if (isScroll && curLine >= numLines - 2 && + lineBase + numLines < items.size()) { + lineBase++; + } else { + curLine++; + } + } else { + this.reset(); + } + + } + + private void reset() { + lineBase = 0; + curLine = 0; + } + + private Menu getPrevMenu() { + return prevMenu; + } + } + + class MenuItem { + + private String name; + private int keyCode; + +// public MenuItem() { +// } + + private MenuItem(String str, int key) { + name = str; + keyCode = key; + } + + protected String getName() { + return name; + } + + public boolean actionPerformed() { + return processCommand(keyCode); + } + } + } +} diff --git a/src/midedit/MixerMain.java b/src/midedit/MixerMain.java new file mode 100644 index 0000000..e7241de --- /dev/null +++ b/src/midedit/MixerMain.java @@ -0,0 +1,404 @@ +package midedit; + +import javax.microedition.midlet.*; +import javax.microedition.lcdui.*; +import java.io.IOException; + +/** + * + * @author user + */ +public class MixerMain extends MIDlet implements CommandListener, AbstractListener { + + /** + * Маленький шрифт + */ + public static final Font SMALL_FONT = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); + + + static MIDlet curMIDlet; + static Display display; + + private static final int CREATE_NEW = 0; + private static final int RESUME = 1; + private static final int OPEN = 2; + private static final int SAVE = 3; + private static final int SAVE_AS = 4; + private static final int RMS_FS = 5; + private static final int OPTIONS = 6; + private static final int ABOUT = 7; + private static final int EXIT = 8; + + private Item[] items; + private Item itemsRMS; + private Image[] iconsImgs; + private TextBox textBoxSave; + private String openSaveString; + private MixerModel model; + private Settings settings; + /** + */ + private CompositionForm compositionForm; + private FileChooser chooser; + //static boolean isRMSMode = false; + private static Form aboutForm; + private static Screen iconsMenu; + /** + * + */ + private static int ifFirstReturn = 0; + + + public MixerMain() { + curMIDlet = MixerMain.this; + display = Display.getDisplay(MixerMain.this); + } + + /** + * + */ + public void startApp() { + Rms.restoreOptions(); + L.readLang(Rms.languageApp, true); + //L.readLang(Rms.languageInstr, false); + settings = new Settings(MixerMain.this); + model = new MixerModel(); + readImages(); + createMenu(); + display.setCurrent(iconsMenu); + } + + /** + * + */ + public void pauseApp() {} + + /** + * + * @param unconditional + */ + public void destroyApp(boolean unconditional) { + if(Rms.firstStart) Rms.firstStart = false; + Rms.saveOptions(); + notifyDestroyed(); + } + + /** + * Получить изображения иконок меню + */ + private void readImages() { + iconsImgs = new Image[9]; + for (int i = 0; i < iconsImgs.length; i++) { + try { + iconsImgs[i] = Image.createImage("/img/main/"+i+".png"); + } catch (IOException ioe) { + iconsImgs[i] = Image.createImage(1, 1); + } + } + } + + /** + * Создать меню (иконки, List с иконками, List без иконок) + */ + private void createMenu() { + try { + iconsMenu = createListMenu(true); + } catch (Throwable ex) { + iconsMenu = createListMenu(false); + } + } + + /** + * + * @param names + * @param cl + * @return + */ + private List createListMenu(boolean withImgs) { + String[] menuNames = { + L.str[L.create], + L.str[L.resume], + L.str[L.open], + L.str[L.save], + L.str[L.saveAs], + L.str[L.file], + L.str[L.options], + L.str[L.about] + /*Constants.getStringName(1), + Constants.getStringName(2), + Constants.getStringName(3), + Constants.getStringName(4), + Constants.getStringName(5), + Constants.getStringName(6), + Constants.getStringName(7), + Constants.getStringName(8),*/ + }; + List list = new List("MIDEdit", 3, menuNames, withImgs ? iconsImgs : null); + list.setCommandListener(this); + return list; + } + + /** + * + * @param text + * @param appearanceMode + * @return + */ + public static Item createStringItem(String text, int appearanceMode) { + StringItem strItem = new StringItem(null, text, appearanceMode); + strItem.setFont(SMALL_FONT); + return strItem; + } + + /** + * + * @param c + * @param d + */ + public void commandAction(Command c, Displayable d) { + if (d == iconsMenu) { + try { + actionPerformed(((List) iconsMenu).getSelectedIndex()); + return; + } catch (ClassCastException clasCastE) { + } + } + actionPerformed(c.getPriority()); + } + + /** + * + * @param itemNum + */ + public void actionPerformed(int itemNum) { + switch (itemNum) { + case CREATE_NEW: + try { + model.newMix(); + if (compositionForm != null) { + compositionForm.releaseMem(); + } + compositionForm = null; + System.gc(); + openSaveString = "newmix"; + MixerModel.isRMSMode = true; + compositionForm = new CompositionForm(this); + if (compositionForm == null) { + throw new Exception("compositionForm == null"); + } + display.setCurrent(compositionForm); + new Thread(compositionForm).start(); + } catch (Exception e) { + e.printStackTrace(); + Alert a = new Alert(Constants.getStringName(12), e.getMessage(), null, null); + display.setCurrent(a); + } + break; + case RESUME: + if (ifFirstReturn == 0) { + return; + } + MixerModel.isRMSMode = true; + display.setCurrent(compositionForm); + break; + case ABOUT: + Item aboutItems[] = {createStringItem("Midedit - mobile midi editor\nAuthor - Bingo\n", 0), + createStringItem("http://bing.at.tut.by\n", 2), + createStringItem("Mods - Cryingangel\n", 0), + createStringItem("http://midedit.wen.ru", 2), + new TextField("Forum seclub.org", "http://seclub.org/forum/index.php?tid=6551", 60, TextField.ANY), + createStringItem("Thanks to:", 2), + createStringItem("Cyber_PUNK - adapted for Nokia\nmaxtr86 - adapted for Sony Erricson\nHelion810\nDark_Dancer - ideas, beta-testing\nsegOro - graphics", 0),}; + aboutForm = new Form("About", aboutItems); + aboutForm.addCommand(Settings.comCancel); + aboutForm.setCommandListener(this); + display.setCurrent(aboutForm); + break; + case OPEN: + openFile(); + break; + case SAVE: + if (ifFirstReturn == 0) { + return; + } + if (compositionForm.isNew()) { + saveAsFile(); + return; + } + openSaveString = compositionForm.getCompositionName(); + try { + model.setLocalFile(); + compositionForm.saveComposition(openSaveString); + compositionForm.setTitle(openSaveString); + } catch (Exception e) { + Alert a = new Alert(Constants.getStringName(12), e.getMessage(), null, null); + display.setCurrent(a); + } + break; + case SAVE_AS: + if (ifFirstReturn == 0) { + return; + } + saveAsFile(); + break; + case RMS_FS: + MixerModel.isRMSMode = !MixerModel.isRMSMode; + //model.setLocalFile(MixerModel.isRMSMode); + try { + try { + ((Form) iconsMenu).set(6, MixerModel.isRMSMode ? itemsRMS : items[6]);//!!!!! + } catch (IllegalStateException illegState) { + } + } catch (ClassCastException clasCast) { + ((List) iconsMenu).set(6, Constants.getStringName(MixerModel.isRMSMode ? 9 : 6), iconsImgs[6]); + } + break; + case OPTIONS: + display.setCurrent(settings.optionsForm); + // System.out.println("qwerty"); + break; + case EXIT: + MixerMain.curMIDlet.notifyDestroyed(); + break; + case 10: + setCurrentlistMenu(null); + break; + } + } + + public MixerModel getModel() { + return model; + } + + /** + * + * @param a + */ + public void setCurrentlistMenu(Alert a) { + if (a != null) { + display.setCurrent(a, iconsMenu); + } else { + display.setCurrent(iconsMenu); + } + } + + /** + * + * @return + */ + public Displayable getCurrentlistMenu() { + return iconsMenu; + } + + /** + * + */ + private void saveAsFile() { + model.setLocalFile(); + final FileChooser chooserForSave = new FileChooser(iconsMenu, "/", true, MixerModel.getLocalFile()); + chooserForSave.setAbstractListener(new AbstractListener() { + + public void actionPerformed(int itemNum) { + if (chooserForSave.getSelectedFolderPath() != null) { + openSaveString = compositionForm.getCompositionName(); + int indBeg = openSaveString.lastIndexOf(Constants.FILE_DELIM); + int indEnd = openSaveString.lastIndexOf('.'); + if (indEnd == -1) { + indEnd = openSaveString.length(); + } + openSaveString = openSaveString.substring(indBeg + 1, indEnd); + if (openSaveString.length() > 64) { + openSaveString = openSaveString.substring(0, 63); + } + textBoxSave = new TextBox(Constants.getStringName(5) + "...", openSaveString, 64, TextField.ANY); + textBoxSave.addCommand(Settings.comSave); + textBoxSave.addCommand(Settings.comCancel); + + //System.out.println ("save as success 2\nopenSaveString="+openSaveString); + textBoxSave.setCommandListener(new CommandListener() { + + public void commandAction(Command c, Displayable d) { + if (c == Settings.comSave) { + try { + openSaveString = chooserForSave.getSelectedFilePath() + textBoxSave.getString().trim() + ".mid"; + compositionForm.saveComposition(openSaveString); + compositionForm.setTitle(openSaveString); + compositionForm.setNew(false); + } catch (Exception e) { + Alert a = new Alert(Constants.getStringName(12), e.getMessage(), null, null); + display.setCurrent(a); + } + } else { + setCurrentlistMenu(null); + } + } + }); + display.setCurrent(textBoxSave); + } else { + setCurrentlistMenu(null); + } + } + }); + } + + /** + * + */ + private void openFile() { + model.setLocalFile(); + if (chooser == null || chooser.getSelectedFilePath() == null) { + final FileChooser chooserLocale = new FileChooser(iconsMenu, "/", false, MixerModel.getLocalFile()); + chooserLocale.setAbstractListener(new AbstractListener() { + + public void actionPerformed(int itemNum) { + if (chooserLocale.getSelectedFilePath() != null) { + try { + if (compositionForm != null) { + compositionForm.releaseMem(); + } + compositionForm = null; + System.gc(); + display.setCurrent(iconsMenu); + openSaveString = chooserLocale.getSelectedFilePath(); + compositionForm = + new CompositionForm(MixerMain.this, + openSaveString); + display.setCurrent(compositionForm); + new Thread(compositionForm).start(); + + } catch (Exception e) { + Alert a = new Alert(Constants.getStringName(13), Constants.getStringName(13) + ":\n" + e.getMessage(), null, null); + display.setCurrent(a); + if (compositionForm != null) { + compositionForm.releaseMem(); + } + compositionForm = null; + } + } else { + setCurrentlistMenu(null); + } + } + }); + } else { + chooser.update(); + display.setCurrent(chooser); + } + } + + /** + * + */ + public void comBack() { + ifFirstReturn = 1; + MixerModel.isRMSMode = false; + try { + try { + ((Form) iconsMenu).set(6, items[6]); + } catch (ClassCastException clasCast) { + ((List) iconsMenu).set(6, Constants.getStringName(6), iconsImgs[6]); + } + } catch (IllegalStateException ise) { + } + setCurrentlistMenu(null); + } +} diff --git a/src/midedit/MixerModel.java b/src/midedit/MixerModel.java new file mode 100644 index 0000000..29827aa --- /dev/null +++ b/src/midedit/MixerModel.java @@ -0,0 +1,242 @@ +package midedit; + +//import java.io.IOException; +import midedit.media.Composition; +import midedit.media.AbstractPlayer; +import midedit.media.JSR135Player; +import midedit.io.RMSFile; +import midedit.io.JSR75File; +import midedit.io.AbstractFile; +import javax.microedition.lcdui.*; + +/** + * + * @author user + */ +public class MixerModel extends Thread { + + private MidiFile mfile = null; + static boolean isRMSMode = false; + /** + * Объект дисплея + */ + public final Display display = MixerMain.display; + /** + * + */ + //public final MixerModel thisModel; + private NoteListUtils buffer; + static AbstractFile rmsFile = new RMSFile(), + //localFile,//=rmsFile, + jsr75File;//=rmsFile;// = new JSR75File(); + AbstractPlayer crossPlayer = null; + + public MixerModel() { + try { + + //System.out.println("microedition.io.file.FileConnection.version="+System.getProperty("microedition.io.file.FileConnection.version")); + if (System.getProperty("microedition.io.file.FileConnection.version") != null) { + jsr75File = new JSR75File(); + } else { + jsr75File = rmsFile; + } + if (crossPlayer == null) { + + try { + Class.forName("javax.microedition.media.Player"); + crossPlayer = new JSR135Player(); + } catch (ClassNotFoundException ex1) { + } + } + } catch (Exception e) { + Alert a = new Alert(Constants.getStringName(22), Constants.getStringName(22) + ":\n" + e.getMessage(), null, null); + display.setCurrent(a); + + } + + + + mfile = new MidiFile(getLocalFile()); + buffer = new NoteListUtils(); + } + + /** + * + * @return + */ + public NoteListUtils getBuffer() { + return buffer; + } + +// /** +// * +// * @param c +// * @param count +// * @throws Exception +// */ +// public void playMix(Composition c, int count) throws Exception { +// playMix(c, 0, 0); +// } + /** + * + * @param c + * @param count + * @param t + * @throws Exception + */ + public void playMix(Composition c, int t) throws Exception { + + crossPlayer.close(); + getLocalFile().close(0); + setLocalFile(); + mfile.writeMix(c, t, true); + String path = mfile.getURI(); + crossPlayer.play(path); + } + + /** + * + * @param instrum + * @param nn + * @param vv + */ + public void playNote(byte instrum, byte nn) { + + try { + + crossPlayer.close(); + + crossPlayer.playTest(mfile.writeNote(instrum, nn)); + } catch (Exception e) { + CompositionForm.msg("MixerModel: 134: playNote " + e.getMessage()); + } + } + + public void playTest(byte instrum) { + + + crossPlayer.close(); + mfile.writeTest(instrum); + crossPlayer.playTest(mfile.writeTest(instrum)); + } + + /** + * + * @param c + * @param count + * @param t + * @param channel + * @param instrument + * @throws Exception + */ + public void playTrack(Composition c, int t, int channel, int instrument) throws Exception { + crossPlayer.close(); + getLocalFile().close(0); + setLocalFile(); + mfile.writeMixWithName(c, t, true, "out_track.mid", channel, instrument); + String path = mfile.getURI(); + crossPlayer.play(path); + } + + /** + * + * @param c + * @param count + * @param t + * @param channel + * @throws Exception + */ + public void playTrack(Composition c, int t, int channel) throws Exception { + playTrack(c, t, channel, -1); + } + + /** + * + */ + public void stopPlay() { + crossPlayer.close(); + } + + /** + * + */ + public void run() { + } + + /** + * + * @param c + * @param name + * @return + * @throws Exception + */ + public String saveMix(Composition c, String name) throws Exception { + return mfile.writeMixWithName(c, 0, false, + name); + } + + /** + * + */ + public void resetProgress() { + mfile.reset(); + } + + /** + * + * @param name + * @return + * @throws Exception + */ + public Composition openMix(String name) throws Exception { + Composition c; + if (name != null) { + c = mfile.readMix( + name); + c.setName(name); + } else { + c = new Composition(); + c.addTemp(0, 500000); + } + return c; + } + + /** + * + * @return + */ + public Composition newMix() { + Composition c = new Composition(); + return c; + } + + /** + * + * @return + */ + public Waitable getWaitableFile() { + return mfile; + } + +// /** +// * +// * @param RMSMode +// */ +// public void setLocalFile(boolean RMSMode) { +// isRMSMode = RMSMode; +// } + /** + * + */ + public void setLocalFile() { + mfile.setFile(); + } + + /** + * + * @return + */ + public static AbstractFile getLocalFile() { + return isRMSMode ? rmsFile : jsr75File; + } +} diff --git a/src/midedit/Note.java b/src/midedit/Note.java new file mode 100644 index 0000000..f9a357d --- /dev/null +++ b/src/midedit/Note.java @@ -0,0 +1,29 @@ +package midedit; + +/** + * + * @author user + */ +public class Note { + + /** + * + * @param tt + * @param ch + * @param nn + * @param vv + * @param ll + */ + public byte c, n, v, mark; + public int t, len; + public Note next = null, prev = null; + + public Note(int tt, byte ch, byte nn, byte vv, int ll) { + t = tt; + c = ch; + n = nn; + v = vv; + len = ll; + mark = NoteListUtils.NOTE_NOT_MARKED; + } +} diff --git a/src/midedit/NoteList.java b/src/midedit/NoteList.java new file mode 100644 index 0000000..c865fa0 --- /dev/null +++ b/src/midedit/NoteList.java @@ -0,0 +1,304 @@ +package midedit; + + + +/** + * + * @author user + */ +public class NoteList +{ + private Note note=null,noteBeg=null; + private Note noteTmp; + private Note noteNew; + private int len=0; + private int timeLastDelOn = -1; + private int timeNoteOff; + private int t; + /** + * + */ + public static final int CHANNEL_LONG_NOTE = -2; + + /** + * + */ + public NoteList() + {} + + /** + * + * @param noteExist + * @return + */ + public Note add(Note noteExist) + { + if(noteExist==null) + return null; + t = noteExist.t; + len++; + if(noteBeg == null) + noteBeg = note = noteExist; + else + { + noteNew = noteExist; + if(note == null) + note = noteBeg; + if(note.t != t) + { if(t < note.t) + { + for(noteTmp = note; + noteTmp != null && t < noteTmp.t; + noteTmp = noteTmp.prev) + ; + if(noteTmp == null) + { + addInto(null,noteNew,noteBeg); + return noteNew; + } + note = noteTmp; + } + else + { for(noteTmp = note; + noteTmp.next != null && (noteTmp.next.t < t ) ; + noteTmp = noteTmp.next) + ; + note = noteTmp; + } + } + if(noteExist.v!=0) + { + for( ; note.next != null && t == note.next.t ; note = note.next ) + ; + } + else + { + for( ; note.prev != null && t == note.t ; note = note.prev ) + ; + } + + addInto(note, noteNew, note.next); + note = noteNew; + } + return note; + } + private void addInto(Note n1, Note note, Note n2) + { + note.next = n2; + if(n2 != null) + n2.prev = note; + note.prev = n1; + if(n1 != null) + n1.next = note; + else + noteBeg = note; + } + + /** + * + * @param t + * @param c + * @param n + * @param v + */ + public void delOne(int t, byte c, byte n, byte v) + { + for(note = searchNoteByTime(t); note != null && note.t <= t; note = note.next) + if(t==note.t && c == note.c && n == note.n && (v!=0 ^ note.v==0)) + { + if (note.next != null) + note.next.prev = note.prev; + if (note.prev != null) + note.prev.next = note.next; + else + noteBeg = note.next; + + note = (note.next != null)? note.next : note.prev; + len--; + return; + } + } + /** + * + * @param delNote + */ + public void delOne(Note delNote) + { + for(note = getFirst(); note != null && note.t <= t; note = note.next) + if(note == delNote) + { + if (note.next != null) + note.next.prev = note.prev; + if (note.prev != null) + note.prev.next = note.next; + else + noteBeg = note.next; + + note = (note.next != null)? note.next : note.prev; + len--; + return; + } + } + /** + * + * @param undo + */ + public void delSelected(UndoableAction undo) + { + for(note = getFirst(); note != null; note = note.next) + if(note.mark == NoteListUtils.NOTE_MARKED) + { + if (note.next != null) + note.next.prev = note.prev; + if (note.prev != null) + note.prev.next = note.next; + else + noteBeg = note.next; + + if(undo!=null && note.v!=0) + { + undo.log2DelNoteList(note.t,note.c,note.n,note.v,note.len); + } + + len--; + } + } + /** + * + * @param t + * @param tMax + * @param c + * @param n + * @param v + * @param undo + * @return + */ + public int del(int t,int tMax, byte c, byte n, byte v,UndoableAction undo) + { + if(t == tMax) + tMax++; + int tOffMax = tMax; + boolean isdel=false; + timeNoteOff = -1; + + for(note = searchNoteByTime(t); note != null && note.t <= tMax; note = note.next) + if ( (note.c == c || c == (byte)-1) && + (note.t > t || v!=0 && note.t == t) && + (note.t < tMax || v==0 && note.t == tMax) && + (note.n == n || n == (byte)-1) && + ( (v != 0 && (note.v != 0 || note.t - note.len >= t)) || + (v == 0 && (note.v == 0 && timeLastDelOn <= note.t-note.len && note.t-note.len < t )))) + { + if(note.next != null) + note.next.prev = note.prev; + if(note.prev != null) + note.prev.next = note.next; + else + noteBeg = note.next; + + len--; + if( v != 0) + { + if(tOffMax < note.t+note.len) + tOffMax = note.t+note.len; + if(undo!=null && note.v!=0) + { + undo.log2DelNoteList(note.t,note.c,note.n,note.v,note.len); + } + } + if(note.v==0) + timeNoteOff = note.t; + isdel = true; + } + + if(v!=0 && tOffMax>tMax) + { + timeLastDelOn = t; + del(tMax, tOffMax, c, n, (byte) 0,null); + } + else + timeLastDelOn = -1; + if(isdel == false) + return -2; + return timeNoteOff; + } + + /** + * + * @param c + * @param n + * @return + */ + public Note searchBack(byte c, byte n) + { + if(note == null) + return null; + for(noteTmp = note; + noteTmp != null && (noteTmp.c!=c || noteTmp.n!=n); + noteTmp = noteTmp.prev) + ; + + return noteTmp; + } + /** + * + * @param t + * @return + */ + public Note searchNoteByTime(int t) + { + if(note == null) + { + if(noteBeg != null) + note = noteBeg; + else + return null; + } + if(t <= note.t) + { + for(noteTmp = note; + noteTmp.prev != null && t <= noteTmp.t; + noteTmp = noteTmp.prev) + ; + if(noteTmp.t= tSrcBeg + || srcNote.v != 0 && srcNote.t + srcNote.len <= tSrcEnd) + && (srcNote.v != 0 || onlyMarkSrc)) { + if (onlyMarkSrc) { + srcNote.mark = NOTE_MARKED; + } else { + t = tDestBeg + + ((srcNote.t - tSrcBeg) * destTicksPer4) / srcTicksPer4; + n = srcNote.n; + len = (srcNote.len * destTicksPer4) / srcTicksPer4; + dest.add(new Note(t, chDest, n, srcNote.v, len)); + + if (len > 0) { + dest.add(new Note(t + len, chDest, n, (byte) 0, len)); + } + if (undo != null) { + undo.log2AddNoteList(t, chDest, n, srcNote.v, len); + } + } + } + } + } + + /** + * + * @param list + * @param tBeg + * @param shiftLen + * @param undo + */ + public static void shift(NoteList list, int tBeg, int shiftLen, UndoableAction undo) { + Note note = list.searchNoteByTime(0x7fffffff); + for (; note != null && note.t >= tBeg; note = note.prev) { + if (note.v == 0 && note.t - note.len < tBeg) { + Note noteTmp; + for (noteTmp = note.prev; + noteTmp != null && (noteTmp.c != note.c || noteTmp.n != note.n); + noteTmp = noteTmp.prev) + ; + + if (noteTmp != null && noteTmp.c == note.c && noteTmp.n == note.n) { + if (undo != null) { + undo.log2DelNoteList(noteTmp.t, noteTmp.c, noteTmp.n, noteTmp.v, noteTmp.len); + } + + noteTmp.len = note.t - noteTmp.t + shiftLen; + + if (noteTmp.t + noteTmp.len < tBeg) { + noteTmp.len = tBeg - noteTmp.t; + } + note.len = noteTmp.len; + + if (undo != null) { + undo.log2AddNoteList(noteTmp.t, noteTmp.c, noteTmp.n, noteTmp.v, noteTmp.len); + } + + } + } + note.t += shiftLen; + if (note.t < tBeg) { + if (undo != null && note.v != 0) { + undo.log2DelNoteList(note.t - shiftLen, note.c, note.n, note.v, note.len); + undo.log2AddNoteList(tBeg, note.c, note.n, note.v, note.len); + } + + note.t = tBeg; + } + } + if (undo != null) { + undo.logShift(tBeg, shiftLen, list.getFirst().c); + } + } + + /** + * + * @param composition + * @param channel + * @param timeBeg + * @param timeEnd + */ + public void delete(Composition composition, byte channel, int timeBeg, int timeEnd) { + NoteList list = composition.getNoteListByChannel(channel); + UndoableAction undo = composition.getUndoableAction(); + undo.prepare(); + undo.addAction(UndoableAction.DELETE_LIST); + + list.del(timeBeg, timeEnd, (byte) -1, (byte) -1, (byte) 127, undo); + undo.addAction(UndoableAction.SHIFT_LIST); + undo.addAction(UndoableAction.ADD_LIST); + shift(list, timeBeg, timeBeg - timeEnd, undo); + } + + /** + * + * @param composition + * @param channel + */ + public static void unMarkNotes(Composition composition, byte channel) { + NoteList list = composition.getNoteListByChannel(channel); + for (Note note = list.getFirst(); note != null; note = note.next) { + note.mark = NOTE_NOT_MARKED; + } + } + + /** + * + * @param composition + * @param channel + */ + public static void deleteSelected(Composition composition, byte channel) { + UndoableAction undo = composition.getUndoableAction(); + undo.prepare(); + undo.addAction(UndoableAction.DELETE_LIST); + NoteList list = composition.getNoteListByChannel(channel); + list.delSelected(undo); + + } + + /** + * + * @param composition + * @param channel + * @param shiftTime + * @param shiftNote + * @param shiftVol + */ + public static void doMove(Composition composition, byte channel, int shiftTime, int shiftNote, int shiftVol) { + UndoableAction undo = composition.getUndoableAction(); + undo.addAction(UndoableAction.ADD_LIST); + NoteList dest = composition.getNoteListByChannel(channel); + int newTime; + byte newVol; + int tmp; + byte newN; + for (Note note = undo.getDeletedList().getFirst(); + note != null; note = note.next) { + if (note.c == channel && note.v != 0) { + newTime = note.t + shiftTime; + if (newTime < 0) { + newTime = 0; + } + newN = (byte) (note.n + shiftNote); + + tmp = note.v + shiftVol; + if (tmp < 1) { + tmp = 1; + } else if (tmp > 127) { + tmp = 127; + } + newVol = (byte) tmp; + + dest.add(new Note(newTime, channel, newN, newVol, note.len)); + + if (note.len > 0) { + dest.add(new Note(newTime + note.len, channel, newN, (byte) 0, note.len)); + } + if (undo != null && note.v != 0) { + undo.log2AddNoteList(newTime, channel, newN, newVol, note.len); + } + + } + } + } +} diff --git a/src/midedit/NoteLong.java b/src/midedit/NoteLong.java new file mode 100644 index 0000000..53730db --- /dev/null +++ b/src/midedit/NoteLong.java @@ -0,0 +1,26 @@ +package midedit; + + + + +/** + * + * @author user + */ +public class NoteLong extends Note +{ + /** + * + * @param t + * @param d + */ + public NoteLong(int t,byte[] d) + { + super(t,(byte)NoteList.CHANNEL_LONG_NOTE,(byte)0,(byte)0,0); + dat = d; + } + /** + * + */ + public byte[] dat; +} diff --git a/src/midedit/NotesCanvas.java b/src/midedit/NotesCanvas.java new file mode 100644 index 0000000..d836fe9 --- /dev/null +++ b/src/midedit/NotesCanvas.java @@ -0,0 +1,128 @@ +package midedit; + + + +import midedit.media.Composition; +import javax.microedition.lcdui.*; + +/** + * + * @author user + */ +public class NotesCanvas extends MixerCanvas +{ + /** + * + * @param ctrl + * @param c + * @param ch + */ + public NotesCanvas(MixerMain ctrl, Composition c, int ch) + { + super(ctrl, c, ch); + hMax = 127; + hBase = 60; + curY = 11; + } + + /** + * + * @param ch + */ + public void setChannel(int ch) + { + channel = ch; + } + /** + * + * @return + */ + public int getChannel() + { + return channel; + } + + /** + * + * @return + */ + protected boolean doKEY_NUM5() + { + if(super.doKEY_NUM5() == false) + { + int dt; + dt = super.getCurLen(); + byte n = (byte)getNoteFromLine(curY); + int curT = getCurTime(); + composition.addNoteOn(curT, (byte) channel, n, super.getCurVol(), dt,true); + composition.addNoteOffWithoutSearch(curT + dt, (byte) channel, n, dt); + } + return true; + } + + + /** + * + * @return + */ + protected String getCurTuneString() + { + return "none"; + } + + /** + * + * @param g + * @param note + * @param shiftTime + * @param shiftNote + */ + protected void paintNote(Graphics g, Note note,int shiftTime,int shiftNote) + { + int x,h; + int dx, t=1; + x = getXInPixel(note.t +shiftTime); + h = getLineFromNote(note.n +shiftNote); + dx = (note.len*wOne)/Constants.timeConst; + if(dx==0) + dx=2; + if(x+dx>=0 && x=0 && h0 && nt/denom[dot] >= nMax[dot]) + { + dot--; + nt /= 10; + } + + if(dot>0) + { + for (i = 0; i < dot; ++i, nt /= 10, xLen += digLen) + { + dig = nt % 10; + g.drawImage(imgs[dig], x - xLen, y, Graphics.RIGHT | Graphics.BOTTOM); + } + + g.drawImage(imgs[10], x - xLen, y, Graphics.RIGHT | Graphics.BOTTOM); + xLen += digLen; + } + do{ + dig = nt % 10; + g.drawImage(imgs[dig], x - xLen, y, Graphics.RIGHT | Graphics.BOTTOM); + nt /= 10; + xLen += digLen; + }while(nt!=0); + + if(num<0) + { + dig = 11; + g.drawImage(imgs[dig], x - xLen, y, Graphics.RIGHT | Graphics.BOTTOM); + xLen += digLen; + } + + return xLen; + } + /** + * + * @param g + * @param n + * @param x + * @param y + * @param color + * @return + */ + public static int printNote(Graphics g,int n,int x, int y,int color) + { + g.drawImage(notesImages[color][n],x,y,Graphics.RIGHT|Graphics.BOTTOM); + + return noteLen; + } + + static int[] nMax = {100000,1000,100,10,1,0}; + static int[] denom = {1,10,100,1000,10000,100000}; + + static Image[][] digImages; + static Image[][] notesImages; + static private int digLen = 4; + static private int noteLen = 11; + /** + * + */ + static public int noteLenY=5; + /** + * + */ + static public final int NUM_CHAR=12; + /** + * + */ + static public final int NUM_COLOR=2; + /** + * + */ + static public final int NUM_NOTES=12; + /** + * + */ + static public final int NUM_NOTES_LINE=6; + + static{ + try { + Image numbers0 = Image.createImage("/img/nums0m.png"); + Image numbers1 = Image.createImage("/img/nums1m.png"); + Image notes0 = Image.createImage("/img/notes0.png"); + Image notes1 = Image.createImage("/img/notes1.png"); + digImages = new Image[NUM_COLOR][]; + digImages[0] = new Image[NUM_CHAR]; + digImages[1] = new Image[NUM_CHAR]; + + notesImages = new Image[NUM_COLOR][]; + notesImages[0] = new Image[NUM_NOTES]; + notesImages[1] = new Image[NUM_NOTES]; + + + int len = 0; + for(int i = 0; i=0) + delTemp(editNum); + editNum = -1; + + int tempMsPer4 = Composition.getMsPer4(Integer.parseInt(tempoField.getString(), + 10)); + int time = tick * Integer.parseInt(timeField.getString(), 10); + NoteLong noteTemp = composition.addTemp(time, tempMsPer4); + Note note; + int ind; + for (ind = 0; ind < tempNotes.size(); ++ind) { + note = (NoteLong) tempNotes.elementAt(ind); + if (note.t > time) + break; + } + tempNotes.insertElementAt(noteTemp, ind); + TempoList.this.insert(ind, getTempoString(noteTemp, tempMsPer4), null); + + } + model.display.setCurrent(TempoList.this); + } + }); + model.display.setCurrent(textBoxTemp); + + } + private void delTemp(int ind) + { + composition.delTemp( (NoteLong) tempNotes.elementAt(ind)); + tempNotes.removeElementAt(ind); + this.delete(ind); + } + + /** + * + * @param command + * @param displayable + */ + public void commandAction(Command command, Displayable displayable) + { + if(command == instempo) + { + editNum = -1; + viewInsertForm(0,120); + + } + else if(command == deltempo) + { + + if(tempNotes.size()>1) + { + delTemp(this.getSelectedIndex()); + } + } + else if(command == CompositionForm.back) + { + model.display.setCurrent(backForm); + } + else + { + int ind = this.getSelectedIndex(); + + NoteLong notelong = (NoteLong)tempNotes.elementAt(ind); + int tmp = 0; + for (int i = 3; i <= 5; ++i) { + tmp = (tmp << 8) | 0xff & notelong.dat[i]; + } + + int mod = (composition.getTicksPer4() << 2) >> (composition.getDenomE()); + int tempBPM =Composition.getTempBeatPerMin(tmp); + int time = notelong.t/tick; + + editNum = ind; + + viewInsertForm(time,tempBPM); + + } + } +} diff --git a/src/midedit/UndoableAction.java b/src/midedit/UndoableAction.java new file mode 100644 index 0000000..1624375 --- /dev/null +++ b/src/midedit/UndoableAction.java @@ -0,0 +1,257 @@ +package midedit; + +import midedit.media.Composition; + + + + +/** + * + * @author user + */ +public class UndoableAction +{ + private NoteList dellist = null; + private NoteList addlist = null; + /** + * + */ + public static final byte DELETE_LIST = 1; + /** + * + */ + public static final byte ADD_LIST = 2; + /** + * + */ + public static final byte SHIFT_LIST = 3; + /** + * + */ + public static final byte ADD_NOTE = 4; + /** + * + */ + public static final byte DEL_NOTE = 5; + private static final byte NUM_ACT = 3; + + private Note noteAddDel; + //private Note note; + private int indOrder=0; + private int shiftBeg; + private int shiftLen; + private byte[] order = new byte[NUM_ACT]; + private Composition composition; + private byte channel; + private boolean canUndo; + private boolean canRedo; + + /** + * + * @param c + */ + public UndoableAction(Composition c) + { + composition = c; + prepare(); + } + /** + * + * @param n + */ + public void addAction(byte n) + { + order[indOrder++] = n; + canUndo = true; + canRedo = false; + } + + /** + * + * @return + */ + public NoteList getDeletedList() + { + return dellist; + } + + /** + * + */ + public void clean() + { + dellist = null; + addlist = null; + indOrder = 0; + } + /** + * + */ + public void prepare() + { + order[0]=0; + indOrder = 0; + dellist = new NoteList(); + addlist = new NoteList(); + } + + /** + * + * @param singleNote + */ + public void logAddNote(Note singleNote) + { + channel = singleNote.c; + clean(); + addAction(ADD_NOTE); + noteAddDel = singleNote; + } + /** + * + * @param singleNote + */ + public void logDelNote(Note singleNote) + { + channel = singleNote.c; + clean(); + addAction(DEL_NOTE); + noteAddDel = singleNote; + } + + /** + * + * @param t + * @param ch + * @param n + * @param v + * @param len + */ + public void log2AddNoteList(int t, byte ch, byte n, byte v,int len) + { + addlist.add(new Note(t,ch,n,v,len)); + } + /** + * + * @param t + * @param ch + * @param n + * @param v + * @param len + */ + public void log2DelNoteList(int t, byte ch, byte n, byte v,int len) + { + dellist.add(new Note(t,ch,n,v,len)); + } + /** + * + * @param timeBeg + * @param len + * @param ch + */ + public void logShift(int timeBeg,int len,byte ch) + { + channel = ch; + shiftBeg = timeBeg; + shiftLen = len; + } + private void doAction() + { + NoteList list; + for(int i=indOrder-1; i>=0; --i) + switch(order[i]) + { + case ADD_NOTE: + composition.getNoteListByChannel(channel).delOne(noteAddDel.t, noteAddDel.c, + noteAddDel.n, noteAddDel.v); + if(noteAddDel.len != 0) + composition.getNoteListByChannel(channel).delOne(noteAddDel.t+noteAddDel.len, + noteAddDel.c,noteAddDel.n,(byte)0); + break; + case DEL_NOTE: + composition.getNoteListByChannel(channel).add(new Note(noteAddDel.t,noteAddDel.c, + noteAddDel.n,noteAddDel.v,noteAddDel.len)); + if(noteAddDel.len != 0) + composition.getNoteListByChannel(channel).add(new Note(noteAddDel.t+noteAddDel.len, + noteAddDel.c,noteAddDel.n, (byte)0,noteAddDel.len)); + break; + case DELETE_LIST: + Note noteLocal = dellist.getFirst(); + if(noteLocal!=null) + channel = noteLocal.c; + list = composition.getNoteListByChannel(channel); + for(noteLocal = dellist.getFirst(); noteLocal!=null; noteLocal = noteLocal.next) + { + list.add(new Note(noteLocal.t,noteLocal.c,noteLocal.n,noteLocal.v,noteLocal.len)); + if(noteLocal.len != 0) + list.add(new Note(noteLocal.t+noteLocal.len,noteLocal.c,noteLocal.n,(byte)0,noteLocal.len)); + } + break; + case ADD_LIST: + noteLocal = addlist.getFirst(); + if(noteLocal!=null) + channel = noteLocal.c; + + list = composition.getNoteListByChannel(channel); + for(noteLocal = addlist.getFirst(); noteLocal!=null; noteLocal = noteLocal.next) + { + list.delOne(noteLocal.t,noteLocal.c,noteLocal.n,noteLocal.v); + if(noteLocal.len != 0) + list.delOne(noteLocal.t+noteLocal.len,noteLocal.c,noteLocal.n,(byte)0); + } + break; + case SHIFT_LIST: + NoteListUtils.shift(composition.getNoteListByChannel(channel),shiftBeg,-shiftLen,null); + break; + } + reverseActOrder(); + canUndo = !canUndo; + canRedo = !canRedo; + } + + private void reverseActOrder() + { + byte[] newOrder = new byte[NUM_ACT]; + NoteList newAddlist=addlist, newDellist=dellist; + for(int i=0 ; iTitle:

+ *

Description:

+ *

Copyright: Copyright (c) 2004

+ *

Company:

+ * @author not attributable + * @version 1.0 + */ +public class RMSFile extends AbstractFile { + + private RecordStore curRecordStore = null; + private int recordID = 0; + + public String[] list(String pathName) throws IOException { + String[] fileList = RecordStore.listRecordStores(); + return fileList; + } + + public int write(int fileDescriptor, + byte[] buf, + int offset, + int numBytes) throws IOException { + if (curRecordStore != null) { + try { + curRecordStore.addRecord(buf, offset, numBytes); + } catch (RecordStoreException ex) { + throw new IOException(ex.getMessage()); + } + } else { + throw new IOException("not opened"); + } + return 0; + } + + public int read(int fileDescriptor, + byte[] buf, + int offset, + int numBytes) throws IOException { + + if (curRecordStore != null) { + //readBuf + is.read(buf, offset, numBytes); + //System.arraycopy(readBuf,readBufInd,buf,offset,numBytes); + //readBufInd += numBytes; + } else { + throw new IOException("not opened"); + } + + return numBytes; + } + + public int close(int fileDescriptor) throws IOException { + try { + if (curRecordStore != null) { + curRecordStore.closeRecordStore(); + curRecordStore = null; + //readBuf = null; + is = null; + //System.out.println ("Local file closed"); + } + } catch (RecordStoreException ex) { + throw new IOException(ex.getMessage()); + } + return 0; + } + + public int length(int fileDescriptor) throws IOException { + if (curRecordStore != null) { + int len = 0; + try { + len = curRecordStore.getRecordSize(recordID); + } catch (RecordStoreException ex) { + throw new IOException(ex.getMessage()); + } + return len; + } + return 0; + } + + public int exists(String fileName) throws IOException { + String name = getLastName(fileName); + RecordStore test = null; + try { + test = RecordStore.openRecordStore(name, false); + } catch (RecordStoreException ex) { + } + if (test != null) { + try { + test.closeRecordStore(); + } catch (RecordStoreException ex1) { + } + return 0; + } else { + return -1; + } + } + + public int open(String fileName, boolean isSave) throws IOException { + String name = getLastName(fileName); + lastPath = name; + try { + curRecordStore = RecordStore.openRecordStore(name, isSave); + if (curRecordStore == null) { + throw new IOException("not found in RMS"); + } + if (isSave == false) /// read + { + RecordEnumeration enumer = curRecordStore.enumerateRecords(null, null, false); + if (enumer.hasNextElement()) { + recordID = enumer.nextRecordId(); + + //recordID = curRecordStore.getNextRecordID(); + ByteArrayInputStream bais = new ByteArrayInputStream(curRecordStore.getRecord(recordID)); + is = bais; + } + } + //curRecordStore.closeRecordStore(); + } catch (RecordStoreException ex) { + //close(0); + curRecordStore = null; + throw new IOException(ex.toString() + " open"); + } + + return 0; + } + +// public int checkFileName(String fileName) throws IOException +// { +// return 0; +// } + public int delete(String fileName) throws IOException { + String name = getLastName(fileName); + try { + RecordStore.deleteRecordStore(name); + } catch (RecordStoreException ex) { + } + return 0; + } + /*protected String getPrefix() + { + return ""; + }*/ + + public String getURL() { + return lastPath; + } + + public String getAns() { + return "RMS save ok"; + } + + public static String getLastName(String fullName) { + int ind = fullName.lastIndexOf('/'); + String name; + name = (ind > 0) ? fullName.substring(ind + 1) : fullName; + return name; + } + + public InputStream getInputStreambyURL(String url) throws IOException { + String fileName = url; + InputStream isLocal = null; +////// copy from open(); + + String name = getLastName(fileName); + lastPath = name; + try { + boolean isSave = false; + curRecordStore = RecordStore.openRecordStore(name, isSave); + if (curRecordStore == null) { + throw new IOException("not found in RMS"); + } + if (isSave == false) /// read + { + RecordEnumeration enumer = curRecordStore.enumerateRecords(null, null, false); + if (enumer.hasNextElement()) { + recordID = enumer.nextRecordId(); + + //recordID = curRecordStore.getNextRecordID(); + ByteArrayInputStream bais = new ByteArrayInputStream(curRecordStore.getRecord(recordID)); + isLocal = bais; + } + } + } catch (RecordStoreException ex) { + curRecordStore = null; + throw new IOException(ex.toString() + " open"); + } + + return isLocal; + } + + public boolean isDirectory(String pathName) throws IOException { + return false; + } + + protected String getPrefix() { + return ""; + } +} diff --git a/src/midedit/media/AbstractPlayer.java b/src/midedit/media/AbstractPlayer.java new file mode 100644 index 0000000..d3c7608 --- /dev/null +++ b/src/midedit/media/AbstractPlayer.java @@ -0,0 +1,38 @@ +package midedit.media; + +import midedit.*; +import javax.microedition.lcdui.*; + +/** + * + * @author user + */ +public abstract class AbstractPlayer { + + private Displayable commandForm; + + public final void setCommandForm(Displayable d) { + commandForm = d; + } + + public abstract void play(String path) throws Exception; + + protected abstract void stop() throws Exception; + + public abstract void close(); + + /** + * + * @param is + */ + protected void setIsPlaying(boolean is) { + CompositionForm.isPlaying = is; + if (is) { + commandForm.addCommand(CompositionForm.stop); + } else { + commandForm.removeCommand(CompositionForm.stop); + } + } + + public abstract void playTest(byte[] writeTest); +} diff --git a/src/midedit/media/Composition.java b/src/midedit/media/Composition.java new file mode 100644 index 0000000..e96e325 --- /dev/null +++ b/src/midedit/media/Composition.java @@ -0,0 +1,537 @@ +package midedit.media; + +import midedit.*; + +/** + * + * @author user + */ +public class Composition { + + private String name; + public NoteList[] tracks; + /** + * + */ + public static final int DEFAULT_CHANNEL = 0; + private int timeNoteOff; + private int volume; + private int ticksPer4; + /** + * + */ + public final static int NOTHING = -127; + private int[] instruments; + private byte[] channelVolExp; + /** + * + */ + public final static byte channelVolExpMax = 64; + private boolean[] soloList; + private boolean isSoloMode; + private int nom = 4; + private int denomE = 2; + private NoteLong meterNote = null; + private UndoableAction undoableAction; + + /** + * + * @param s + */ + private Composition(String s) { + setName(s); + + tracks = new NoteList[Constants.NCHANNEL]; + for (int i = 0; i < Constants.NCHANNEL; ++i) { + tracks[i] = new NoteList(); + } + + + instruments = new int[Constants.NCHANNEL]; + channelVolExp = new byte[Constants.NCHANNEL]; + soloList = new boolean[Constants.NCHANNEL]; + for (int i = 0; i < Constants.NCHANNEL; ++i) { + instruments[i] = NOTHING; + channelVolExp[i] = (byte) (channelVolExpMax / 2); + soloList[i] = false; + } + instruments[Constants.DRUMS_CHANNEL] = -1; + + isSoloMode = false; + volume = 60; + setTicksPer4(240); + + undoableAction = new UndoableAction(this); + } + + /** + * + */ + public Composition() { + this("new"); + } + + /** + * + */ + public void deleteNoteList() { + tracks = null; + } + + /** + * + * @return + */ + public String[] getInstrumentsStrings() { + // String[] allInstrums = Constants.instruments; + int size = 0; + for (int i = 0; i < Constants.NCHANNEL; ++i) { + if (instruments[i] != NOTHING) { + size++; + } + } + String[] ss = new String[size]; + int j = 0; + for (int i = 0; i < Constants.NCHANNEL; ++i) { + if (instruments[i] != NOTHING) { + ss[j++] = Constants.getInstrName(instruments[i] + 1); + } + } + return ss; + } + + /** + * + * @param iNum + * @return + */ + public byte addInstrument(int iNum) { + if (iNum == -1) { + if (instruments[Constants.DRUMS_CHANNEL] == NOTHING) { + instruments[Constants.DRUMS_CHANNEL] = iNum; + return (byte) Constants.DRUMS_CHANNEL; + } + } else { + int i; + for (i = 0; i < Constants.NCHANNEL + && instruments[i] != NOTHING || i == Constants.DRUMS_CHANNEL; ++i); + if (i < Constants.NCHANNEL) { + instruments[i] = iNum; + return (byte) i; + } + } + return -1; + } + + /** + * + * @param ch + * @param iNum + */ + public void setInstrument(int ch, int iNum) { + if (ch >= 0) { + instruments[ch] = iNum; + + } + } + + /** + * + * @return + */ + public int[] getInstruments() { + int[] t = new int[instruments.length]; + for (int i = 0; i < instruments.length; ++i) { + t[i] = instruments[i]; + } + return t; + } + + /** + * + * @param ch + * @return + */ + public int getInstrument(int ch) { + return instruments[ch]; + } + + /** + * + * @param ch + * @param e + */ + public void setVolumeExp(int ch, byte e) { + channelVolExp[ch] = e; + } + +// /** +// * +// * @param ch +// * @return +// */ +// public byte getVolumeExp(int ch) { +// return channelVolExp[ch]; +// } + /** + * + * @return + */ + public byte[] getVolumeExpArr() { + byte[] t = new byte[channelVolExp.length]; + for (int i = 0; i < channelVolExp.length; ++i) { + t[i] = channelVolExp[i]; + } + return t; + } + + /** + * + * @return + */ + public boolean[] getSoloList() { + boolean[] dup = new boolean[soloList.length]; + System.arraycopy(soloList, 0, dup, 0, soloList.length); + return dup; + } + + /** + * + * @param channel + * @param solo + */ + public void setSolo(int channel, boolean solo) { + soloList[channel] = solo; + } + + /** + * + * @param solo + */ + public void setSoloMode(boolean solo) { + isSoloMode = solo; + } + + /** + * + */ + public void setSoloMode() { + boolean solo = false; + for (int ind = 0; ind < instruments.length; ++ind) { + if (soloList[ind]) { + solo = true; + } + } + + isSoloMode = solo; + } + + /** + * + * @param ch + * @return + */ + public boolean isPlayChan(int ch) { + return !isSoloMode || soloList[ch]; + } + +// /** +// * +// * @return +// */ +// public boolean isSoloMode() { +// return isSoloMode; +// } + /** + * + * @param tt + * @param ch + * @param nn + * @param vv + * @param ll + * @param log + */ + public void addNoteOn(int tt, byte ch, byte nn, byte vv, int ll, boolean log) { + tracks[ch].add(new Note(tt, ch, nn, vv, ll)); + if (log) { + undoableAction.logAddNote(new Note(tt, ch, nn, vv, ll)); + } + } + + /** + * + * @param tt + * @param ch + * @param nn + */ + public void addNoteOff(int tt, byte ch, byte nn) { + Note noteTmp = tracks[ch].searchBack(ch, nn); + if (noteTmp != null) { + noteTmp.len = tt - noteTmp.t; + tracks[ch].add(new Note(tt, ch, nn, (byte) 0, noteTmp.len)); + } else { + tracks[ch].add(new Note(tt, ch, nn, (byte) 0, 0)); + } + } + + /** + * + * @param tt + * @param ch + * @param nn + * @param backLen + */ + public void addNoteOffWithoutSearch(int tt, byte ch, byte nn, int backLen) { + tracks[ch].add(new Note(tt, ch, nn, (byte) 0, backLen)); + } + + /** + * + * @param tt + * @param ch + * @param nn + * @param vv + */ + public void delNote(int tt, byte ch, byte nn, byte vv) { + timeNoteOff = tracks[ch].del(tt, tt + Constants.timeConst - 1, ch, nn, vv, null); + if (timeNoteOff == -2) { + return; + } + int len; + if (timeNoteOff == -1) { + len = 0; + } else { + len = timeNoteOff - tt; + } + undoableAction.logDelNote(new Note(tt, ch, nn, vv, len)); + } + + /** + * + * @param tBeg + * @param tEnd + * @param ch + * @param nn + * @param vv + */ + public void delNotes(int tBeg, int tEnd, byte ch, byte nn, byte vv) { + if (ch == -1) { + for (int i = 0; i < Constants.NCHANNEL; ++i) { + tracks[i].del(tBeg, tEnd, ch, nn, vv, null); + } + } else { + tracks[ch].del(tBeg, tEnd, ch, nn, vv, null); + } + } + + /** + * + * @param t + * @param ch + * @return + */ + public Note getFirstNote(int t, int ch) { + return tracks[ch].searchNoteByTime(t); + } + + /** + * + * @param time + * @param newTemp + * @return + */ + public NoteLong addTemp(int time, int newTemp) { + byte[] dat = new byte[]{(byte) 0xff, (byte) 0x51, 0x03, 3, 4, 5}; + int tmp = newTemp; + for (int i = 5; i >= 3; --i) { + dat[i] = (byte) (tmp & 0xff); + tmp >>= 8; + } + NoteLong noteTemp = new NoteLong(time, dat); + tracks[DEFAULT_CHANNEL].add(noteTemp); + return noteTemp; + } + + /** + * + * @param delTemp + */ + public void delTemp(Note delTemp) { + tracks[DEFAULT_CHANNEL].delOne(delTemp); + } + + /** + * + * @param tempBPM + * @return + */ + public static int getMsPer4(int tempBPM) { + return 500000 * 120 / tempBPM; + } + + /** + * + * @param msPer4 + * @return + */ + public static int getTempBeatPerMin(int msPer4) { + return 120 * 500000 / msPer4; + } + + /** + * + * @param t + */ + public void setTicksPer4(int t) { + ticksPer4 = t; + Constants.setTimeConst(getTime2CanvasConst()); + } + + /** + * + * @return + */ + public short getTicksPer4() { + return (short) ticksPer4; + } + + /** + * + * @return + */ + public int getTime2CanvasConst() { + return ticksPer4 / 8; + } + + /** + * + * @param v + */ + public void setVolume(int v) { + volume = v; + } + + /** + * + * @return + */ + public int getVolume() { + return volume; + } + + /** + * + * @param ch + * @return + */ + public NoteList getNoteListByChannel(int ch) { + return tracks[ch]; + } + + /** + * + * @param s + */ + public void setName(String s) { + name = s; + } + + /** + * + * @return + */ + public String getName() { + return name; + } + + /** + * + * @param percent + * @param ch + */ + public void setCurW(int percent, byte ch) { + int timeNew; + if (percent == 0) { + timeNew = 0; + } else { + timeNew = this.getFirstNote(this.getLastTime() * percent / 100, ch).t; + MixerCanvas.curX = 0; + } + MixerCanvas.xBase = (short) (timeNew / Constants.timeConst); + } + + /** + * + * @return + */ + public int getCurWInPercent() { + int timeMax = this.getLastTime(); + return (MixerCanvas.xBase * Constants.timeConst * 100) / (timeMax > 0 ? timeMax : 1); + } + + /** + * + * @return + */ + public int getLastTime() { + int tCur, tMax = 0; + + for (int i = 0; i < Constants.NCHANNEL; ++i) { + Note noteTimeMax = this.getFirstNote(0x7fffffff, i); + if (noteTimeMax != null) { + tCur = noteTimeMax.t + noteTimeMax.len; + if (tCur > tMax) { + tMax = tCur; + } + } + } + + return tMax; + } + + /** + * + * @return + */ + public UndoableAction getUndoableAction() { + return undoableAction; + } + + /** + * + * @return + */ + public int getNom() { + return nom; + } + + /** + * + * @return + */ + public int getDenomE() { + return denomE; + } + + /** + * + * @param nomNew + * @param deNomNew + */ + public void setMeter(int nomNew, int deNomNew) { + nom = nomNew; + denomE = deNomNew; + + if (meterNote == null) { + byte[] dat = new byte[]{(byte) 0xff, (byte) 0x58, 0x04, 0x04, 0x02, 0x18, 0x08}; + dat[3] = (byte) nomNew; + dat[4] = (byte) deNomNew; + NoteLong newMeter = new NoteLong(0, dat); + tracks[DEFAULT_CHANNEL].add(newMeter); + meterNote = newMeter; + } else { + meterNote.dat[3] = (byte) nomNew; + meterNote.dat[4] = (byte) deNomNew; + } + } +} diff --git a/src/midedit/media/JSR135Player.java b/src/midedit/media/JSR135Player.java new file mode 100644 index 0000000..4087b99 --- /dev/null +++ b/src/midedit/media/JSR135Player.java @@ -0,0 +1,66 @@ +package midedit.media; + +import midedit.*; +import javax.microedition.media.*; +import java.io.*; + +/** + * + * @author user + */ +public class JSR135Player extends AbstractPlayer implements PlayerListener { + + private Player player; + + public void playerUpdate(Player player, java.lang.String event, java.lang.Object eventData) { + if (event.equals(STARTED)) { + setIsPlaying(true); + return; + } + if (event.equals(STOPPED) || event.equals(CLOSED) || event.equals(END_OF_MEDIA)) { + setIsPlaying(false); + } + return; + } + + public void play(String path) throws Exception { + if (player != null) { + player.close(); + } + InputStream is = MixerModel.getLocalFile().getInputStreambyURL(path); + player = Manager.createPlayer(is, "audio/midi"); + player.addPlayerListener(this); + player.start(); + } + + protected void stop() throws Exception { + if (player != null) { + player.stop(); + } + } + + public void close() { + if (player != null) { + player.close(); + } + player = null; + + } + + public void playTest(byte[] writeTest) { + ByteArrayInputStream is = new ByteArrayInputStream(writeTest); + if (player != null) { + player.close(); + } + + try { + player = Manager.createPlayer(is, "audio/midi"); + player.addPlayerListener(this); + player.start(); + } catch (IOException ex) { + //ex.printStackTrace(); + } catch (MediaException ex) { + //ex.printStackTrace(); + } + } +} diff --git a/src/text.txt b/src/text.txt new file mode 100644 index 0000000..6506a98 --- /dev/null +++ b/src/text.txt @@ -0,0 +1,11 @@ +MIDedit 2.1 / 3.0 + +По просьбе одного человека, на основе исходников MidEdit 2.0.5 (http://sunet.dl.sourceforge.net/project/midedit/MideditProject.tgz) начал делать модификацию. +Изменения: + - Сохранение в .mid, а не в .MID + - Исправления в локализации. Добавлен украинский язык. + + +****** +При первом запуске - настройки +player.realize \ No newline at end of file