diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index b2361d2bf..a24ee9a93 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -46,9 +46,9 @@ import processing.mode.java.JavaMode; public class Base { // Added accessors for 0218 because the UpdateCheck class was not properly // updating the values, due to javac inlining the static final values. - static private final int REVISION = 228; + static private final int REVISION = 229; /** This might be replaced by main() if there's a lib/version.txt file. */ - static private String VERSION_NAME = "0228"; //$NON-NLS-1$ + static private String VERSION_NAME = "0229"; //$NON-NLS-1$ /** Set true if this a proper release rather than a numbered revision. */ // static private boolean RELEASE = false; @@ -605,12 +605,6 @@ public class Base { protected void changeMode(Mode mode) { if (activeEditor.getMode() != mode) { Sketch sketch = activeEditor.getSketch(); - if (sketch.isModified()) { - Base.showWarning("Save", - "Please save the sketch before changing the mode.", - null); - return; - } nextMode = mode; // If the current editor contains file extensions that the new mode can handle, then diff --git a/app/src/processing/app/ColorChooser.java b/app/src/processing/app/ColorChooser.java index b4a6ccac8..b261096dd 100644 --- a/app/src/processing/app/ColorChooser.java +++ b/app/src/processing/app/ColorChooser.java @@ -442,6 +442,23 @@ public class ColorChooser { //extends JFrame implements DocumentListener { row.add(Box.createHorizontalGlue()); box.add(row); + row = Box.createHorizontalBox(); + if (Base.isMacOS()) { + row.add(Box.createHorizontalStrut(11)); + } else { + row.add(createFixedLabel("")); + } + button = new JButton("Cancel"); + button.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + ColorChooser.this.hide(); + } + }); + row.add(button); + row.add(Box.createHorizontalGlue()); + box.add(row); // box.add(Box.createVerticalGlue()); diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index ae90ba51f..806771478 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -389,7 +389,26 @@ public abstract class Editor extends JFrame implements RunnerListener { JRadioButtonMenuItem item = new JRadioButtonMenuItem(m.getTitle()); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - base.changeMode(m); + if (!sketch.isModified()) { + base.changeMode(m); + + } else { + Base.showWarning("Save", + "Please save the sketch before changing the mode.", + null); + + // Re-select the old checkbox, because it was automatically + // updated by Java, even though the Mode could not be changed. + // https://github.com/processing/processing/issues/2615 + for (Component c : modeMenu.getPopupMenu().getComponents()) { + if (c instanceof JRadioButtonMenuItem) { + if (((JRadioButtonMenuItem)c).getText() == mode.getTitle()) { + ((JRadioButtonMenuItem)c).setSelected(true); + break; + } + } + } + } } }); modeMenu.add(item); @@ -902,8 +921,6 @@ public abstract class Editor extends JFrame implements RunnerListener { // Menu Listener that populates the menu only when the menu is opened List menuList = new ArrayList(); - JMenu windowMenu = new JMenu("Window"); - @Override public void menuSelected(MenuEvent event) { JMenuItem item; @@ -928,19 +945,17 @@ public abstract class Editor extends JFrame implements RunnerListener { editor.toFront(); } }); - windowMenu.add(item); + sketchMenu.add(item); menuList.add(item); } - sketchMenu.add(windowMenu); } @Override public void menuDeselected(MenuEvent event) { for (JMenuItem item : menuList) { - windowMenu.remove(item); + sketchMenu.remove(item); } menuList.clear(); - sketchMenu.remove(windowMenu); } @Override diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index e3cd166d5..77343774e 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -28,6 +28,8 @@ import java.io.*; import java.util.*; import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; import processing.core.*; @@ -107,6 +109,8 @@ public class Preferences { int wide, high; JTextField sketchbookLocationField; + JTextField presentColor; + JTextField presentColorHex; JCheckBox editorAntialiasBox; JCheckBox deletePreviousBox; JCheckBox whinyBox; @@ -118,6 +122,8 @@ public class Preferences { JComboBox consoleSizeField; JCheckBox inputMethodBox; JCheckBox autoAssociateBox; + + ColorChooser selector; JCheckBox errorCheckerBox; JCheckBox warningsCheckerBox; @@ -375,6 +381,131 @@ public class Preferences { top += d.height + GUI_BETWEEN; + Container colorBox = Box.createHorizontalBox(); + + label = new JLabel("Background color when Presenting: "); + colorBox.add(label); + + final String colorTip = "" + + "Select the background color used when using Present.
" + + "Present is used to present a sketch in full-screen,
" + + "accessible from the Sketch menu."; + label.setToolTipText(colorTip); + + presentColor = new JTextField(" "); + presentColor.setOpaque(true); + presentColor.setEnabled(false); + presentColor.setBorder(new CompoundBorder(BorderFactory.createMatteBorder( + 1, 1, 0, 0, new Color(195, 195, 195)), BorderFactory.createMatteBorder( + 0, 0, 1, 1, new Color(54, 54, 54)))); + presentColor.setBackground(Preferences.getColor("run.present.bgcolor")); + + presentColorHex = new JTextField(6); + presentColorHex + .setText(Preferences.get("run.present.bgcolor").substring(1)); + presentColorHex.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + final String colorValue = presentColorHex.getText().toUpperCase(); + if (colorValue.length() == 7 && (colorValue.startsWith("#"))) + EventQueue.invokeLater(new Runnable() { + public void run() { + presentColorHex.setText(colorValue.substring(1)); + } + }); + if (colorValue.length() == 6 + && colorValue.matches("[0123456789ABCDEF]*")) { + presentColor.setBackground(new Color(Integer.parseInt( + colorValue.substring(0, 2), 16), Integer.parseInt( + colorValue.substring(2, 4), 16), Integer.parseInt( + colorValue.substring(4, 6), 16))); + if (!colorValue.equals(presentColorHex.getText())) + EventQueue.invokeLater(new Runnable() { + public void run() { + presentColorHex.setText(colorValue); + } + }); + } + } + + @Override + public void insertUpdate(DocumentEvent e) { + final String colorValue = presentColorHex.getText().toUpperCase(); + if (colorValue.length() == 7 && (colorValue.startsWith("#"))) + EventQueue.invokeLater(new Runnable() { + public void run() { + presentColorHex.setText(colorValue.substring(1)); + } + }); + if (colorValue.length() == 6 + && colorValue.matches("[0123456789ABCDEF]*")) { + presentColor.setBackground(new Color(Integer.parseInt( + colorValue.substring(0, 2), 16), Integer.parseInt( + colorValue.substring(2, 4), 16), Integer.parseInt( + colorValue.substring(4, 6), 16))); + if (!colorValue.equals(presentColorHex.getText())) + EventQueue.invokeLater(new Runnable() { + public void run() { + presentColorHex.setText(colorValue); + } + }); + } + } + + @Override public void changedUpdate(DocumentEvent e) {} + }); + + selector = new ColorChooser(dialog, false, + Preferences.getColor("run.present.bgcolor"), "OK", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String colorValue = selector.getHexColor(); + presentColorHex.setText(colorValue.substring(1)); + presentColor.setBackground(new Color(Integer.parseInt( + colorValue.substring(1, 3), 16), Integer.parseInt( + colorValue.substring(3, 5), 16), Integer.parseInt( + colorValue.substring(5, 7), 16))); + selector.hide(); + } + }); + + presentColor.addMouseListener(new MouseListener() { + @Override public void mouseReleased(MouseEvent e) {} + @Override public void mousePressed(MouseEvent e) {} + + @Override + public void mouseExited(MouseEvent e) { + dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + @Override + public void mouseEntered(MouseEvent e) { + dialog.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + + @Override + public void mouseClicked(MouseEvent e) { + selector.show(); + } + }); + + label = new JLabel("#"); + colorBox.add(label); + + colorBox.add(presentColorHex); + + colorBox.add(Box.createHorizontalStrut(GUI_SMALL + 2 / 3 * GUI_SMALL)); + + colorBox.add(presentColor); + + pain.add(colorBox); + d = colorBox.getPreferredSize(); + colorBox.setBounds(left, top, d.width, d.height); + + top += d.height + GUI_BETWEEN; + // [ ] Use smooth text in editor window editorAntialiasBox = new JCheckBox("Use smooth text in editor window"); @@ -830,6 +961,8 @@ public class Preferences { consoleSizeField.setSelectedItem(getInteger("console.font.size")); } + setColor("run.present.bgcolor", presentColor.getBackground()); + setBoolean("editor.input_method_support", inputMethodBox.isSelected()); //$NON-NLS-1$ if (autoAssociateBox != null) { @@ -896,6 +1029,9 @@ public class Preferences { fontSizeField.setSelectedItem(getInteger("editor.font.size")); consoleSizeField.setSelectedItem(getInteger("console.font.size")); + presentColor.setBackground(Preferences.getColor("run.present.bgcolor")); + presentColorHex.setText(Preferences.get("run.present.bgcolor").substring(1)); + memoryOverrideBox. setSelected(getBoolean("run.options.memory")); //$NON-NLS-1$ memoryField. diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java index fe98fab2b..c1a3cb4d5 100644 --- a/app/src/processing/app/UpdateCheck.java +++ b/app/src/processing/app/UpdateCheck.java @@ -58,7 +58,7 @@ public class UpdateCheck { new Thread(new Runnable() { public void run() { try { - Thread.sleep(30 * 1000); // give the PDE time to get rolling + Thread.sleep(20 * 1000); // give the PDE time to get rolling updateCheck(); } catch (Exception e) { // this can safely be ignored, too many instances where no net @@ -124,11 +124,11 @@ public class UpdateCheck { // (this should really be handled better). Thread.sleep(5 * 1000); if ((!base.libraryManagerFrame.hasAlreadyBeenOpened() && - base.libraryManagerFrame.hasUpdates()) || + base.libraryManagerFrame.hasUpdates(base)) || (!base.toolManagerFrame.hasAlreadyBeenOpened() && - base.toolManagerFrame.hasUpdates()) || + base.toolManagerFrame.hasUpdates(base)) || (!base.modeManagerFrame.hasAlreadyBeenOpened() && - base.modeManagerFrame.hasUpdates())) { + base.modeManagerFrame.hasUpdates(base))) { promptToOpenContributionManager(); } } diff --git a/app/src/processing/app/contrib/AvailableContribution.java b/app/src/processing/app/contrib/AvailableContribution.java index a815ab6da..44ed86888 100644 --- a/app/src/processing/app/contrib/AvailableContribution.java +++ b/app/src/processing/app/contrib/AvailableContribution.java @@ -1,4 +1,4 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* Part of the Processing project - http://processing.org @@ -23,6 +23,7 @@ package processing.app.contrib; import java.io.*; import java.util.HashMap; +import java.util.List; import processing.app.Base; import processing.app.Editor; @@ -53,6 +54,13 @@ class AvailableContribution extends Contribution { version = PApplet.parseInt(versionStr, 0); } prettyVersion = params.get("prettyVersion"); + String lastUpdatedStr = params.get("lastUpdated"); + if (lastUpdatedStr != null) + try { + lastUpdated = Long.parseLong(lastUpdatedStr); + } catch (NumberFormatException e) { + lastUpdated = 0; + } } @@ -179,26 +187,96 @@ class AvailableContribution extends Contribution { /** - * We overwrite the properties file with the curated version from the - * Processing site. This ensures that things have been cleaned up (for - * instance, that the "sentence" is really a sentence) and that bad data - * from the contrib's .properties file doesn't break the manager. + * We overwrite those fields that aren't proper in the properties file with + * the curated version from the Processing site. This ensures that things have + * been cleaned up (for instance, that the "sentence" is really a sentence) + * and that bad data from the contrib's .properties file doesn't break the + * manager. However, it also ensures that valid fields in the properties file + * aren't overwritten, since the properties file may be more recent than the + * contributions.txt file. + * * @param propFile * @return */ public boolean writePropertiesFile(File propFile) { try { + + HashMap properties = Base.readSettings(propFile); + + String name = properties.get("name"); + if (name == null || name.isEmpty()) + name = getName(); + + String category; + List categoryList = parseCategories(properties.get("category")); + if (categoryList.size() == 1 && categoryList.get(0).equals("Unknown")) + category = getCategoryStr(); + else { + StringBuilder sb = new StringBuilder(); + for (String cat : categories) { + sb.append(cat); + sb.append(','); + } + sb.deleteCharAt(sb.length() - 1); + category = sb.toString(); + } + + String authorList = properties.get("authorList"); + if (authorList == null || authorList.isEmpty()) + authorList = getAuthorList(); + + String url = properties.get("url"); + if (url == null || url.isEmpty()) + url = getUrl(); + + String sentence = properties.get("sentence"); + if (sentence == null || sentence.isEmpty()) + sentence = getSentence(); + + String paragraph = properties.get("paragraph"); + if (paragraph == null || paragraph.isEmpty()) + paragraph = getParagraph(); + + int version; + try { + version = Integer.parseInt(properties.get("version")); + } catch (NumberFormatException e) { + version = getVersion(); + System.err.println("The version number for the “" + name + + "” contribution is not set properly."); + System.err + .println("Please contact the author to fix it according to the guidelines."); + } + + String prettyVersion = properties.get("prettyVersion"); + if (prettyVersion == null || prettyVersion.isEmpty()) + prettyVersion = getPrettyVersion(); + + long lastUpdated; + try { + lastUpdated = Long.parseLong(properties.get("lastUpdated")); + } + catch (NumberFormatException nfe) { + lastUpdated = getLastUpdated(); + // Better comment these out till all contribs have a lastUpdated +// System.err.println("The last updated date for the “" + name +// + "” contribution is not set properly."); +// System.err +// .println("Please contact the author to fix it according to the guidelines."); + } + if (propFile.delete() && propFile.createNewFile() && propFile.setWritable(true)) { PrintWriter writer = PApplet.createWriter(propFile); - writer.println("name=" + getName()); - writer.println("category=" + getCategoryStr()); - writer.println("authorList=" + getAuthorList()); - writer.println("url=" + getUrl()); - writer.println("sentence=" + getSentence()); - writer.println("paragraph=" + getParagraph()); - writer.println("version=" + getVersion()); - writer.println("prettyVersion=" + getPrettyVersion()); + writer.println("name=" + name); + writer.println("category=" + category); + writer.println("authorList=" + authorList); + writer.println("url=" + url); + writer.println("sentence=" + sentence); + writer.println("paragraph=" + paragraph); + writer.println("version=" + version); + writer.println("prettyVersion=" + prettyVersion); + writer.println("lastUpdated=" + lastUpdated); writer.flush(); writer.close(); diff --git a/app/src/processing/app/contrib/Contribution.java b/app/src/processing/app/contrib/Contribution.java index 8367b98d3..9fc73c851 100644 --- a/app/src/processing/app/contrib/Contribution.java +++ b/app/src/processing/app/contrib/Contribution.java @@ -43,6 +43,7 @@ abstract public class Contribution { protected String paragraph; // protected int version; // 102 protected String prettyVersion; // "1.0.2" + protected long lastUpdated; // 1402805757 // "Sound" @@ -120,6 +121,11 @@ abstract public class Contribution { public String getPrettyVersion() { return prettyVersion; } + + // 1402805757 + public long getLastUpdated() { + return lastUpdated; + } abstract public ContributionType getType(); diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index 05531f63d..65c16048f 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -27,6 +27,7 @@ import java.util.*; import java.util.concurrent.locks.ReentrantLock; import processing.app.Base; +import processing.app.Library; import processing.core.PApplet; @@ -379,6 +380,19 @@ public class ContributionListing { } return false; } + + boolean hasUpdates(Base base) { + for (ModeContribution m : base.getModeContribs()) + if (hasUpdates(m)) + return true; + for (Library l : base.getActiveEditor().getMode().contribLibraries) + if (hasUpdates(l)) + return true; + for (ToolContribution t : base.getActiveEditor().contribTools) + if (hasUpdates(t)) + return true; + return false; + } boolean hasUpdates(Contribution contribution) { @@ -393,6 +407,24 @@ public class ContributionListing { } + String getLatestVersion(Contribution contribution) { + Contribution newestContrib = getAvailableContribution(contribution); + String latestVersion = newestContrib.getPrettyVersion(); + if (latestVersion != null && !latestVersion.isEmpty()) { + if (latestVersion.toLowerCase().startsWith("build")) // For Python mode + return ("v" + latestVersion.substring(5, latestVersion.indexOf(',')) + .trim()); + else if (latestVersion.toLowerCase().startsWith("v")) // For ketai library + return latestVersion; + else + return ("v" + latestVersion); + } + else + return null; + } + + + boolean hasDownloadedLatestList() { return hasDownloadedLatestList; } diff --git a/app/src/processing/app/contrib/ContributionManagerDialog.java b/app/src/processing/app/contrib/ContributionManagerDialog.java index 6cbe3b888..c0a23d79f 100644 --- a/app/src/processing/app/contrib/ContributionManagerDialog.java +++ b/app/src/processing/app/contrib/ContributionManagerDialog.java @@ -74,6 +74,10 @@ public class ContributionManagerDialog { } + public boolean hasUpdates(Base base) { + return contribListing.hasUpdates(base); + } + public void showFrame(Editor editor) { this.editor = editor; @@ -106,7 +110,7 @@ public class ContributionManagerDialog { status.setErrorMessage("Connection timed out while " + "downloading the contribution list."); } else { - status.setErrorMessage("Could not download the list" + + status.setErrorMessage("Could not download the list " + "of available contributions."); } exception.printStackTrace(); @@ -163,6 +167,7 @@ public class ContributionManagerDialog { category = null; } filterLibraries(category, filterField.filters); + contributionListPanel.updateColors(); } }); @@ -419,6 +424,8 @@ public class ContributionManagerDialog { filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a^\\x3a]", " "); filters = Arrays.asList(filter.split(" ")); filterLibraries(category, filters); + + contributionListPanel.updateColors(); } public String getFilterText() { diff --git a/app/src/processing/app/contrib/ContributionPanel.java b/app/src/processing/app/contrib/ContributionPanel.java index ca6f2da4e..37b4fb6b3 100644 --- a/app/src/processing/app/contrib/ContributionPanel.java +++ b/app/src/processing/app/contrib/ContributionPanel.java @@ -28,6 +28,8 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.Date; +import java.text.DateFormat; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -359,6 +361,29 @@ class ContributionPanel extends JPanel { } description.append(sentence); } + + String version = contrib.getPrettyVersion(); + + if (version != null && !version.isEmpty()) { + description.append("
"); + if (version.toLowerCase().startsWith("build")) // For Python mode + description.append("v" + + version.substring(5, version.indexOf(',')).trim()); + else if (version.toLowerCase().startsWith("v")) // For ketai library + description.append(version); + else + description.append("v" + version); + } + + long lastUpdatedUTC = contrib.getLastUpdated(); + if (lastUpdatedUTC != 0) { + DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.MEDIUM); + Date lastUpdatedDate = new Date(lastUpdatedUTC); + if (version != null && !version.isEmpty()) + description.append(", "); + description.append("Last Updated on " + dateFormatter.format(lastUpdatedDate)); + } + description.append(""); //descriptionText.setText(description.toString()); descriptionBlock.setText(description.toString()); @@ -371,7 +396,11 @@ class ContributionPanel extends JPanel { // Already marked for deletion, see requiresRestart() notes below. versionText.append("To finish an update, reinstall this contribution after restarting."); } else { - versionText.append("New version available!"); + String latestVersion = contribListing.getLatestVersion(contrib); + if (latestVersion != null) + versionText.append("New version (" + latestVersion + ") available!"); + else + versionText.append("New version available!"); if (contrib.getType().requiresRestart()) { // If a contribution can't be reinstalled in-place, the user may need // to remove the current version, restart Processing, then install. diff --git a/app/src/processing/app/contrib/LocalContribution.java b/app/src/processing/app/contrib/LocalContribution.java index 03a6e0f31..57ac2ffc9 100644 --- a/app/src/processing/app/contrib/LocalContribution.java +++ b/app/src/processing/app/contrib/LocalContribution.java @@ -1,4 +1,4 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* Part of the Processing project - http://processing.org @@ -74,6 +74,15 @@ public abstract class LocalContribution extends Contribution { System.err.println("Please contact the library author to fix it according to the guidelines."); } prettyVersion = properties.get("prettyVersion"); + try { + lastUpdated = Long.parseLong(properties.get("lastUpdated")); + } catch (NumberFormatException e) { + lastUpdated = 0; + + // Better comment these out till all contribs have a lastUpdated +// System.err.println("The last updated timestamp for the “" + name + "” library is not set properly."); +// System.err.println("Please contact the library author to fix it according to the guidelines."); + } } else { Base.log("No properties file at " + propertiesFile.getAbsolutePath()); diff --git a/app/src/processing/app/platform/LinuxPlatform.java b/app/src/processing/app/platform/LinuxPlatform.java index 8e9ee7c71..85d2b4e9a 100644 --- a/app/src/processing/app/platform/LinuxPlatform.java +++ b/app/src/processing/app/platform/LinuxPlatform.java @@ -23,6 +23,7 @@ package processing.app.platform; import java.io.File; +import java.awt.Toolkit; import processing.app.Base; import processing.app.Platform; @@ -47,6 +48,21 @@ public class LinuxPlatform extends Platform { "placement. For more background, please read the wiki:\n" + "http://wiki.processing.org/w/Supported_Platforms#Linux", null); } + + // Set x11 WM_CLASS property which is used as the application + // name by Gnome3 and other window managers. + // https://github.com/processing/processing/issues/2534 + try { + Toolkit xToolkit = Toolkit.getDefaultToolkit(); + java.lang.reflect.Field awtAppClassNameField = + xToolkit.getClass().getDeclaredField("awtAppClassName"); + awtAppClassNameField.setAccessible(true); + awtAppClassNameField.set(xToolkit, "Processing"); + + } catch(Exception e) { + // In case the implementation details change + e.printStackTrace(); + } } diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index de7eb16ce..221218d46 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -103,7 +103,7 @@ public class JEditTextArea extends JComponent } // Initialize some misc. stuff - painter = new TextAreaPainter(this, defaults); + painter = createPainter(defaults); documentHandler = new DocumentHandler(); eventListenerList = new EventListenerList(); caretEvent = new MutableCaretEvent(); @@ -176,6 +176,16 @@ public class JEditTextArea extends JComponent } + /** + * Override this to provide your own painter for this {@link JEditTextArea}. + * @param defaults + * @return a newly constructed {@link TextAreaPainter}. + */ + protected TextAreaPainter createPainter(final TextAreaDefaults defaults) { + return new TextAreaPainter(this, defaults); + } + + /** * Inline Input Method Support for Japanese. */ diff --git a/app/src/processing/mode/java/JavaBuild.java b/app/src/processing/mode/java/JavaBuild.java index 46c18816d..021f7ea5e 100644 --- a/app/src/processing/mode/java/JavaBuild.java +++ b/app/src/processing/mode/java/JavaBuild.java @@ -1446,7 +1446,11 @@ public class JavaBuild { } // https://github.com/processing/processing/issues/2239 runOptions.add("-Djna.nosys=true"); - + // https://github.com/processing/processing/issues/2559 + if (exportPlatform == PConstants.WINDOWS) { + runOptions.add("-Djava.library.path=\"%EXEDIR%\\lib;%PATH%\""); + } + /// macosx: write out Info.plist (template for classpath, etc) diff --git a/app/src/processing/mode/java/JavaMode.java b/app/src/processing/mode/java/JavaMode.java index 0753404b5..4515d46d7 100644 --- a/app/src/processing/mode/java/JavaMode.java +++ b/app/src/processing/mode/java/JavaMode.java @@ -46,7 +46,7 @@ public class JavaMode extends Mode { public String getTitle() { - return "Java"; + return "Java (2.0)"; } diff --git a/app/src/processing/mode/java/runner/Runner.java b/app/src/processing/mode/java/runner/Runner.java index 314e37f0d..8812627c9 100644 --- a/app/src/processing/mode/java/runner/Runner.java +++ b/app/src/processing/mode/java/runner/Runner.java @@ -639,9 +639,6 @@ public class Runner implements MessageConsumer { //vm.setDebugTraceMode(debugTraceMode); // vm.setDebugTraceMode(VirtualMachine.TRACE_ALL); // vm.setDebugTraceMode(VirtualMachine.TRACE_NONE); // formerly, seems to have no effect - - // For internal debugging - PrintWriter writer = null; // Calling this seems to set something internally to make the // Eclipse JDI wake up. Without it, an ObjectCollectedException @@ -735,7 +732,6 @@ public class Runner implements MessageConsumer { // we don't interrupt } //System.out.println("and leaving"); - if (writer != null) writer.close(); } diff --git a/build/build.xml b/build/build.xml index 045ab9027..9433bf858 100755 --- a/build/build.xml +++ b/build/build.xml @@ -14,7 +14,7 @@ - + @@ -151,21 +151,21 @@ - + + message="JDK 7u${jdk.update.macosx} required.${line.separator}To build on OS X, you must install Oracle's JDK 7u${jdk.update.macosx} from${line.separator}http://www.oracle.com/technetwork/java/javase/downloads${line.separator}Note that only 7u${jdk.update.macosx} (not a later or earlier version) will work. ${line.separator}And it must be the JDK, not the JRE. And do not try to defy me again." /> - + + value="macosx/work/Processing.app/Contents/Java"> @@ -201,10 +201,10 @@ + description="Build Processing for distribution."> + addproperty="version" + defaultvalue="${revision}" /> @@ -226,6 +226,7 @@ + @@ -237,6 +238,7 @@ + @@ -248,7 +250,7 @@ + message="Do not call assemble from the command line." /> @@ -257,19 +259,19 @@ - - + + - - + + - - + + @@ -278,18 +280,18 @@ + src="../java/reference.zip" + overwrite="false"> - - + + - - + + @@ -309,39 +311,39 @@ - - - - - - + + + + + + + property="revision.base"> - - - - - + + + + + + LF in revision.base. Please file a bug if you have a fix. --> + if $revision wasn't found... --> + message="Fix revision number in Base.java" /> @@ -375,25 +377,25 @@ + name="Processing" + displayName="Processing" + executableName="Processing" + identifier="org.processing.app" + signature="Pde2" + icon="macosx/processing.icns" + copyright="© The Processing Foundation" + getInfo="${version}, Copyright © The Processing Foundation" + shortVersion="${version}" + version="${revision}" + mainClassName="processing.app.Base"> + it's primarily copying over the JRE folder. --> + the .tgz on the Oracle site, though it's in a folder called + jre1.7.0_40.jre, so we'll need to strip that out. --> @@ -417,9 +419,9 @@ + icon="macosx/pde.icns" + name="Processing Source Code" + role="Editor"> @@ -449,20 +451,20 @@ the old options; most of these are probably no longer useful apple.laf.useScreenMenuBar true - apple.awt.showGrowBox - true - com.apple.smallTabs - true - apple.awt.Antialiasing - false - apple.awt.TextAntialiasing - true - com.apple.hwaccel - true - apple.awt.use-file-dialog-packages - false - apple.awt.graphics.UseQuartz - true + apple.awt.showGrowBox + true + com.apple.smallTabs + true + apple.awt.Antialiasing + false + apple.awt.TextAntialiasing + true + com.apple.hwaccel + true + apple.awt.use-file-dialog-packages + false + apple.awt.graphics.UseQuartz + true --> @@ -482,16 +484,16 @@ + value="macosx/work/Processing.app/Contents/Java" /> + tofile="${launch4j.dir}/bin/windres" /> + tofile="${launch4j.dir}/bin/ld" /> @@ -505,7 +507,7 @@ + description="Run Mac OS X version"> @@ -541,8 +543,8 @@ + depends="macosx-build" + description="Create a downloadable .zip for the Mac OS X version"> @@ -550,9 +552,9 @@ @@ -610,9 +612,9 @@ + tofile="${launch4j.dir}/bin/windres" /> + tofile="${launch4j.dir}/bin/ld" /> @@ -637,19 +639,19 @@ + dest="linux/jre.tgz" + usetimestamp="true" /> - + description="Clean windows version"> @@ -753,8 +755,8 @@ + depends="revision-check, windows-checkos, subprojects-build" + description="Build windows version"> @@ -781,9 +783,9 @@ + tofile="${launch4j.dir}/bin/windres.exe" /> + tofile="${launch4j.dir}/bin/ld.exe" /> @@ -792,11 +794,11 @@ + classname="net.sf.launch4j.ant.Launch4jTask" + classpath="${launch4j.dir}/launch4j.jar; ${launch4j.dir}/lib/xstream.jar" /> + file (i.e. the icon param doesn't work), so use a config file --> @@ -807,18 +809,18 @@ + dest="windows/jre.tgz" + usetimestamp="true" /> + since those shouldn't matter on Windows. --> + dest="windows/work" + src="windows/jre.tgz" + overwrite="false" /> @@ -834,36 +836,36 @@ + description="Run windows version"> + dir="windows/work" spawn="true"/> + description="Create .zip files of windows version"> + prefix="processing-${version}" /> @@ -906,23 +908,23 @@ remove the spaces for depth since it should be double dash, but screws up commen + also suppresses the java.lang prefix in the text. --> - + @@ -937,25 +939,25 @@ remove the spaces for depth since it should be double dash, but screws up commen - - + + - + - - + + @@ -995,7 +997,7 @@ remove the spaces for depth since it should be double dash, but screws up commen + depends="linux-clean, windows-clean, macosx-clean, subprojects-clean"> diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index 4b6516220..d4b60796b 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -1,3 +1,116 @@ +PROCESSING 3.0a1 (REV 0228) - 26 July 2014 + +Kicking off the 3.0 release process. The focus for Processing 3 is improving +the editor and the coding process, so we'll be integrating what was formerly +PDE X as the main editor. + +This release also includes a number of bug fixes and changes, based on +in-progress Google Summer of Code projects and a few helpful souls on Github. + +Please contribute to the Processing 3 release by testing and reporting bugs. +Or better yet, helping us fix them and submitting pull requests. + + +[ contributed fixes! ] + ++ Fix blendMode() problems in the default renderer (thanks Jakub Valtar!) + https://github.com/processing/processing/issues/2012 + https://github.com/processing/processing/issues/2275 + https://github.com/processing/processing/issues/2276 + https://github.com/processing/processing/issues/2483 + ++ Lighting issues with non-planar triangle strips or quad strips + https://github.com/processing/processing/issues/2014 + https://github.com/processing/processing/issues/2018 + https://github.com/processing/processing/pull/2644 + ++ Set the application name on Linux + https://github.com/processing/processing/issues/2534 + https://github.com/processing/processing/pull/2584 + ++ Serial library not working on export + https://github.com/processing/processing/issues/2559 + ++ Fix build problems on Windows + https://github.com/processing/processing/issues/2603 + https://github.com/processing/processing/pull/2610 + ++ filter() not applying to images produced by saveframe() consistently + https://github.com/processing/processing/issues/2619 + ++ drawLatch in PJOGL can be null after requesting frame rendering + https://github.com/processing/processing/issues/2630 + + +[ summer of code ] + ++ Line coloring incorrect for filtered contribution listings + https://github.com/processing/processing/issues/2583 + https://github.com/processing/processing/pull/2598 + ++ Added Present's background color as an option to the Preferences window + https://github.com/processing/processing/pull/2568 + ++ Check for updates on startup + https://github.com/processing/processing/pull/2636 + ++ Avoid problems with out-of-date contribution list + https://github.com/processing/processing/issues/2572 + ++ Integrate tweak mode into the new editor + https://github.com/processing/processing/pull/2624 + ++ Implementation of a list of open sketches in the Sketch menu + https://github.com/processing/processing/pull/2551 + ++ Add preference to set the present color + https://github.com/processing/processing/pull/2568 + ++ Fix a problem where mode menu selection would change even if + the change was canceled due to the sketch being modified + https://github.com/processing/processing/issues/2615 + ++ Add date and time stamps to the Contribution Manager + https://github.com/processing/processing/pull/2651 + + +[ more bug fixes ] + ++ Prevent the current Mode from being de-selected + https://github.com/processing/processing/issues/2545 + ++ Prevent ArrayIndexOutOfBoundsException when calling min/maxValue() + on a FloatDict that only contains NaN values + ++ Last row was being skipped on tables with the 'newlines' option set + ++ Debug table parsing with header rows + ++ Bug fix for setting Table data types + ++ Fixes for new Table(Iterable). Category data types were not importing + their dictionary, column titles weren't set, and performance improvements + were badly needed. + ++ When using setColumnType(), replace nulls with missingInt, missingFloat, etc + Formerly, this was throwing a NullPointerException. + + +[ changes ] + ++ A new sound library has been added, and Minim has been removed. Minim + will now available via the Contributions Manager. + ++ Add copy() method to PVector + ++ Major performance improvements to parsing w/ the 'newlines' option + ++ add getColumnTitle(int) and getColumnTitles() to TableRow interface + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + PROCESSING 2.2.1 (REV 0227) - 19 May 2014 A handful of bug fixes, the most prominent rolls back a change that broke diff --git a/build/windows/config-cmd.xml b/build/windows/config-cmd.xml index 7cd313d08..607d545c5 100755 --- a/build/windows/config-cmd.xml +++ b/build/windows/config-cmd.xml @@ -35,7 +35,7 @@ 1.7.0_40 - 256m + 256 An error occurred while starting the application. diff --git a/build/windows/config.xml b/build/windows/config.xml index 197e63680..1ff09ff00 100755 --- a/build/windows/config.xml +++ b/build/windows/config.xml @@ -35,7 +35,7 @@ 1.7.0_40 - 256m + 256 about.bmp diff --git a/core/done.txt b/core/done.txt index 694933b4b..007c32e8b 100644 --- a/core/done.txt +++ b/core/done.txt @@ -1,3 +1,41 @@ +0228 core (3.0a1) +X add copy() method to PVector +X modify PVector to include better methods for chaining operations +X http://code.google.com/p/processing/issues/detail?id=218 +X https://github.com/processing/processing/issues/257 +X PVector discussion with Dan +o Jer and Dan will look at their code, plus toxiclibs +X blendMode() broken with default renderer +X fix from Jakub Valtar +X https://github.com/processing/processing/issues/2012 +X may have been introduced between 2.0b7 and 2.0b8 +X https://github.com/processing/processing/issues/2275 +X https://github.com/processing/processing/issues/2276 +X https://github.com/processing/processing/issues/2483 +X if all data is NaN in a FloatDict, return NaN for maxValue() and minValue() +X formerly as AIOOBE -1 because -1 means "not found" +X but that was indexing directly into the data array + +pulls +X filter() not applying to images produced by saveframe() consistently +X https://github.com/processing/processing/issues/2619 +X drawLatch in PJOGL can be null after requesting frame rendering +X https://github.com/processing/processing/issues/2630 + +table +X major performance improvements to 'newlines' parsing +X last row was being skipped on tables with the 'newlines' option set +X debug table parsing with header rows +X bug fix for setting data types +X add getColumnTitle(int) and getColumnTitles() to TableRow interface +X fixes for new Table(Iterable) +X category data types were not importing their dictionary +X column titles weren't set on the new table +X drastic performance improvements for addRow() +X when using setColumnType(), replace nulls with missingInt, missingFloat, etc +X formerly, was throwing a NullPointerException + + 0227 core (2.2.1) X Permit mouse PRESS to set mouseX/mouseY X https://github.com/processing/processing/pull/2509 diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index ed29c0ee4..7d950eecc 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -2664,8 +2664,8 @@ public class PGraphics extends PImage implements PConstants { } if (stop - start > TWO_PI) { - start = 0; - stop = TWO_PI; + // don't change start, it is visible in PIE mode + stop = start + TWO_PI; } arcImpl(x, y, w, h, start, stop, mode); } diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java index 4b43c7e90..a2828d08a 100644 --- a/core/src/processing/core/PGraphicsJava2D.java +++ b/core/src/processing/core/PGraphicsJava2D.java @@ -743,11 +743,14 @@ public class PGraphicsJava2D extends PGraphics { int[] srcPixels = new int[width]; int[] dstPixels = new int[width]; + // Java won't set the high bits when RGB, returns 0 for alpha + int alphaFiller = (dstIn.getNumBands() == 3) ? (0xFF << 24) : 0x00; + for (int y = 0; y < height; y++) { src.getDataElements(0, y, width, 1, srcPixels); dstIn.getDataElements(0, y, width, 1, dstPixels); for (int x = 0; x < width; x++) { - dstPixels[x] = blendColor(srcPixels[x], dstPixels[x], mode); + dstPixels[x] = blendColor(srcPixels[x], alphaFiller | dstPixels[x], mode); } dstOut.setDataElements(0, y, width, 1, dstPixels); } @@ -1671,7 +1674,7 @@ public class PGraphicsJava2D extends PGraphics { if (textFont == null) { defaultFontOrDeath("textWidth"); } - + Font font = (Font) textFont.getNative(); //if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) { if (font != null) { diff --git a/core/src/processing/data/FloatDict.java b/core/src/processing/data/FloatDict.java index e9b902396..71ea99ffd 100644 --- a/core/src/processing/data/FloatDict.java +++ b/core/src/processing/data/FloatDict.java @@ -411,13 +411,21 @@ public class FloatDict { public String minKey() { checkMinMax("minKey"); - return keys[minIndex()]; + int index = minIndex(); + if (index == -1) { + return null; + } + return keys[index]; } public float minValue() { checkMinMax("minValue"); - return values[minIndex()]; + int index = minIndex(); + if (index == -1) { + return Float.NaN; + } + return values[index]; } @@ -452,17 +460,25 @@ public class FloatDict { } - /** The key for a max value. */ + /** The key for a max value, or null if everything is NaN (no max). */ public String maxKey() { checkMinMax("maxKey"); - return keys[maxIndex()]; + int index = maxIndex(); + if (index == -1) { + return null; + } + return keys[index]; } - /** The max value. */ + /** The max value. (Or NaN if they're all NaN.) */ public float maxValue() { checkMinMax("maxValue"); - return values[maxIndex()]; + int index = maxIndex(); + if (index == -1) { + return Float.NaN; + } + return values[index]; } diff --git a/core/src/processing/data/Table.java b/core/src/processing/data/Table.java index c270dd96e..a76ec9bfe 100644 --- a/core/src/processing/data/Table.java +++ b/core/src/processing/data/Table.java @@ -155,13 +155,30 @@ public class Table { public Table(Iterable rows) { init(); - boolean typed = false; - for (TableRow row : rows) { - if (!typed) { - setColumnTypes(row.getColumnTypes()); - typed = true; + + int row = 0; + int alloc = 10; + + for (TableRow incoming : rows) { + if (row == 0) { + setColumnTypes(incoming.getColumnTypes()); + setColumnTitles(incoming.getColumnTitles()); + // Do this after setting types, otherwise it'll attempt to parse the + // allocated but empty rows, and drive CATEGORY columns nutso. + setRowCount(alloc); + + } else if (row == alloc) { + // Far more efficient than re-allocating all columns and doing a copy + alloc *= 2; + setRowCount(alloc); } - addRow(row); + + //addRow(row); + setRow(row++, incoming); + } + // Shrink the table to only the rows that were used + if (row != alloc) { + setRowCount(row); } } @@ -505,6 +522,7 @@ public class Table { if (count > 0) { setString(row, col, new String(c, 0, count)); } + row++; // set row to row count (the current row index + 1) if (alloc != row) { setRowCount(row); // shrink to the actual size } @@ -1501,7 +1519,7 @@ public class Table { int[] intData = new int[rowCount]; for (int row = 0; row < rowCount; row++) { String s = getString(row, column); - intData[row] = PApplet.parseInt(s, missingInt); + intData[row] = (s == null) ? missingInt : PApplet.parseInt(s, missingInt); } columns[column] = intData; break; @@ -1511,7 +1529,7 @@ public class Table { for (int row = 0; row < rowCount; row++) { String s = getString(row, column); try { - longData[row] = Long.parseLong(s); + longData[row] = (s == null) ? missingLong : Long.parseLong(s); } catch (NumberFormatException nfe) { longData[row] = missingLong; } @@ -1523,7 +1541,7 @@ public class Table { float[] floatData = new float[rowCount]; for (int row = 0; row < rowCount; row++) { String s = getString(row, column); - floatData[row] = PApplet.parseFloat(s, missingFloat); + floatData[row] = (s == null) ? missingFloat : PApplet.parseFloat(s, missingFloat); } columns[column] = floatData; break; @@ -1533,7 +1551,7 @@ public class Table { for (int row = 0; row < rowCount; row++) { String s = getString(row, column); try { - doubleData[row] = Double.parseDouble(s); + doubleData[row] = (s == null) ? missingDouble : Double.parseDouble(s); } catch (NumberFormatException nfe) { doubleData[row] = missingDouble; } @@ -1835,13 +1853,16 @@ public class Table { * @param source a reference to the original row to be duplicated */ public TableRow addRow(TableRow source) { - int row = rowCount; + return setRow(rowCount, source); + } + + + public TableRow setRow(int row, TableRow source) { // Make sure there are enough columns to add this data ensureBounds(row, source.getColumnCount() - 1); for (int col = 0; col < columns.length; col++) { switch (columnTypes[col]) { - case CATEGORY: case INT: setInt(row, col, source.getInt(col)); break; @@ -1857,6 +1878,14 @@ public class Table { case STRING: setString(row, col, source.getString(col)); break; + case CATEGORY: + int index = source.getInt(col); + setInt(row, col, index); + if (!columnCategories[col].hasCategory(index)) { + columnCategories[col].setCategory(index, source.getString(col)); + } + break; + default: throw new RuntimeException("no types"); } @@ -2289,6 +2318,14 @@ public class Table { public int[] getColumnTypes() { return table.getColumnTypes(); } + + public String getColumnTitle(int column) { + return table.getColumnTitle(column); + } + + public String[] getColumnTitles() { + return table.getColumnTitles(); + } } @@ -3609,6 +3646,18 @@ public class Table { return indexToData.get(index); } + boolean hasCategory(int index) { + return index < size() && indexToData.get(index) != null; + } + + void setCategory(int index, String name) { + while (indexToData.size() <= index) { + indexToData.add(null); + } + indexToData.set(index, name); + dataToIndex.put(name, index); + } + int size() { return dataToIndex.size(); } @@ -3630,9 +3679,11 @@ public class Table { void read(DataInputStream input) throws IOException { int count = input.readInt(); + //System.out.println("found " + count + " entries in category map"); dataToIndex = new HashMap(count); for (int i = 0; i < count; i++) { String str = input.readUTF(); + //System.out.println(i + " " + str); dataToIndex.put(str, i); indexToData.add(str); } diff --git a/core/src/processing/data/TableRow.java b/core/src/processing/data/TableRow.java index 7107ee693..87e288825 100644 --- a/core/src/processing/data/TableRow.java +++ b/core/src/processing/data/TableRow.java @@ -109,4 +109,7 @@ public interface TableRow { public int getColumnType(int column); public int[] getColumnTypes(); + + public String getColumnTitle(int column); + public String[] getColumnTitles(); } diff --git a/core/src/processing/opengl/LightFrag.glsl b/core/src/processing/opengl/LightFrag.glsl new file mode 100644 index 000000000..b566c8e5b --- /dev/null +++ b/core/src/processing/opengl/LightFrag.glsl @@ -0,0 +1,31 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-13 Ben Fry and Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + */ + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +varying vec4 vertColor; +varying vec4 backVertColor; + +void main() { + gl_FragColor = gl_FrontFacing ? vertColor : backVertColor; +} \ No newline at end of file diff --git a/core/src/processing/opengl/LightVert.glsl b/core/src/processing/opengl/LightVert.glsl index bfbb6a8d3..8d75f970a 100644 --- a/core/src/processing/opengl/LightVert.glsl +++ b/core/src/processing/opengl/LightVert.glsl @@ -43,6 +43,7 @@ attribute vec4 emissive; attribute float shininess; varying vec4 vertColor; +varying vec4 backVertColor; const float zero_float = 0.0; const float one_float = 1.0; @@ -82,17 +83,17 @@ void main() { // Normal vector in eye coordinates vec3 ecNormal = normalize(normalMatrix * normal); - - if (dot(-one_float * ecVertex, ecNormal) < zero_float) { - // If normal is away from camera, choose its opposite. - // If we add backface culling, this will be backfacing - ecNormal *= -one_float; - } + vec3 ecNormalInv = ecNormal * -one_float; // Light calculations vec3 totalAmbient = vec3(0, 0, 0); - vec3 totalDiffuse = vec3(0, 0, 0); - vec3 totalSpecular = vec3(0, 0, 0); + + vec3 totalFrontDiffuse = vec3(0, 0, 0); + vec3 totalFrontSpecular = vec3(0, 0, 0); + + vec3 totalBackDiffuse = vec3(0, 0, 0); + vec3 totalBackSpecular = vec3(0, 0, 0); + for (int i = 0; i < 8; i++) { if (lightCount == i) break; @@ -118,24 +119,33 @@ void main() { : one_float; if (any(greaterThan(lightAmbient[i], zero_vec3))) { - totalAmbient += lightAmbient[i] * falloff; + totalAmbient += lightAmbient[i] * falloff; } if (any(greaterThan(lightDiffuse[i], zero_vec3))) { - totalDiffuse += lightDiffuse[i] * falloff * spotf * - lambertFactor(lightDir, ecNormal); + totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormal); + totalBackDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormalInv); } if (any(greaterThan(lightSpecular[i], zero_vec3))) { - totalSpecular += lightSpecular[i] * falloff * spotf * - blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalFrontSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalBackSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); } } // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - vertColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalFrontDiffuse, 1) * color + + vec4(totalFrontSpecular, 0) * specular + + vec4(emissive.rgb, 0); + + backVertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalBackDiffuse, 1) * color + + vec4(totalBackSpecular, 0) * specular + + vec4(emissive.rgb, 0); } \ No newline at end of file diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index f177bfa67..c2bf327e9 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -160,6 +160,11 @@ public class PGraphicsOpenGL extends PGraphics { PGraphicsOpenGL.class.getResource("ColorFrag.glsl"); static protected URL defTextureShaderFragURL = PGraphicsOpenGL.class.getResource("TextureFrag.glsl"); + static protected URL defLightShaderFragURL = + PGraphicsOpenGL.class.getResource("LightFrag.glsl"); + static protected URL defTexlightShaderFragURL = + PGraphicsOpenGL.class.getResource("TexlightFrag.glsl"); + static protected URL defLineShaderVertURL = PGraphicsOpenGL.class.getResource("LineVert.glsl"); static protected URL defLineShaderFragURL = @@ -379,9 +384,9 @@ public class PGraphicsOpenGL extends PGraphics { /** PImage that wraps filterTexture. */ protected PImage filterImage; - /** Flag to indicate if the user is manipulating the - * pixels array through the set()/get() methods */ - protected boolean setgetPixels; + /** Flag to indicate that pixels array is up-to-date and + * ready to be manipulated through the set()/get() methods */ + protected boolean arePixelsUpToDate; // ........................................................ @@ -2151,6 +2156,9 @@ public class PGraphicsOpenGL extends PGraphics { if ((flushMode == FLUSH_CONTINUOUSLY) || (flushMode == FLUSH_WHEN_FULL && tessGeo.isFull())) { flush(); + } else { + // pixels array is not up-to-date anymore + arePixelsUpToDate = false; } } @@ -2166,6 +2174,9 @@ public class PGraphicsOpenGL extends PGraphics { if (flushMode == FLUSH_CONTINUOUSLY || (flushMode == FLUSH_WHEN_FULL && tessGeo.isFull())) { flush(); + } else { + // pixels array is not up-to-date anymore + arePixelsUpToDate = false; } } @@ -2443,7 +2454,7 @@ public class PGraphicsOpenGL extends PGraphics { tessGeo.clear(); texCache.clear(); - setgetPixels = false; + arePixelsUpToDate = false; } @@ -3237,6 +3248,7 @@ public class PGraphicsOpenGL extends PGraphics { normalMode = NORMAL_MODE_SHAPE; inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); + inGeo.setNormal(normalX, normalY, normalZ); inGeo.addArc(x, y, w, h, start, stop, fill, stroke, mode); endShape(); @@ -5435,7 +5447,7 @@ public class PGraphicsOpenGL extends PGraphics { needEndDraw = true; } - if (!setgetPixels) { + if (!arePixelsUpToDate) { // Draws any remaining geometry in case the user is still not // setting/getting new pixels. flush(); @@ -5443,10 +5455,13 @@ public class PGraphicsOpenGL extends PGraphics { allocatePixels(); - if (!setgetPixels) { + if (!arePixelsUpToDate) { readPixels(); } + // Pixels are now up-to-date, set the flag. + arePixelsUpToDate = true; + if (needEndDraw) { endDraw(); } @@ -5566,7 +5581,6 @@ public class PGraphicsOpenGL extends PGraphics { @Override public int get(int x, int y) { loadPixels(); - setgetPixels = true; return super.get(x, y); } @@ -5576,7 +5590,6 @@ public class PGraphicsOpenGL extends PGraphics { int sourceWidth, int sourceHeight, PImage target, int targetX, int targetY) { loadPixels(); - setgetPixels = true; super.getImpl(sourceX, sourceY, sourceWidth, sourceHeight, target, targetX, targetY); } @@ -5585,7 +5598,6 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void set(int x, int y, int argb) { loadPixels(); - setgetPixels = true; super.set(x, y, argb); } @@ -5596,7 +5608,6 @@ public class PGraphicsOpenGL extends PGraphics { int sourceWidth, int sourceHeight, int targetX, int targetY) { loadPixels(); - setgetPixels = true; super.setImpl(sourceImage, sourceX, sourceY, sourceWidth, sourceHeight, targetX, targetY); // do we need this? @@ -6531,8 +6542,12 @@ public class PGraphicsOpenGL extends PGraphics { lightSpecular(0, 0, 0); } - // Because y is flipped, the vertices that should be specified by - // the user in CCW order to define a front-facing facet, end up being CW. + // Vertices should be specified by user in CW order (left-handed) + // That is CCW order (right-handed). Vertex shader inverts + // Y-axis and outputs vertices in CW order (right-handed). + // Culling occurs after the vertex shader, so FRONT FACE + // has to be set to CW (right-handed) for OpenGL to correctly + // recognize FRONT and BACK faces. pgl.frontFace(PGL.CW); pgl.disable(PGL.CULL_FACE); @@ -6540,7 +6555,8 @@ public class PGraphicsOpenGL extends PGraphics { pgl.activeTexture(PGL.TEXTURE0); // The current normal vector is set to be parallel to the Z axis. - normalX = normalY = normalZ = 0; + normalX = normalY = 0; + normalZ = 1; // Clear depth and stencil buffers. pgl.depthMask(true); @@ -6569,7 +6585,7 @@ public class PGraphicsOpenGL extends PGraphics { clearColorBuffer = false; modified = false; - setgetPixels = false; + arePixelsUpToDate = false; } @@ -6740,7 +6756,7 @@ public class PGraphicsOpenGL extends PGraphics { if (useDefault || !polyShader.checkPolyType(PShader.TEXLIGHT)) { if (ppg.defTexlightShader == null) { String[] vertSource = pgl.loadVertexShader(defTexlightShaderVertURL, 120); - String[] fragSource = pgl.loadFragmentShader(defTextureShaderFragURL, 120); + String[] fragSource = pgl.loadFragmentShader(defTexlightShaderFragURL, 120); ppg.defTexlightShader = new PShader(parent, vertSource, fragSource); } shader = ppg.defTexlightShader; @@ -6751,7 +6767,7 @@ public class PGraphicsOpenGL extends PGraphics { if (useDefault || !polyShader.checkPolyType(PShader.LIGHT)) { if (ppg.defLightShader == null) { String[] vertSource = pgl.loadVertexShader(defLightShaderVertURL, 120); - String[] fragSource = pgl.loadFragmentShader(defColorShaderFragURL, 120); + String[] fragSource = pgl.loadFragmentShader(defLightShaderFragURL, 120); ppg.defLightShader = new PShader(parent, vertSource, fragSource); } shader = ppg.defLightShader; @@ -7798,6 +7814,7 @@ public class PGraphicsOpenGL extends PGraphics { // // Normal calculation + // Expects vertices in CW (left-handed) order. void calcTriangleNormal(int i0, int i1, int i2) { int index; @@ -7825,9 +7842,9 @@ public class PGraphicsOpenGL extends PGraphics { float v10z = z0 - z1; // The automatic normal calculation in Processing assumes - // that vertices as given in CCW order so: + // that vertices as given in CCW order (right-handed) so: // n = v12 x v10 - // so that the normal outwards. + // so that the normal extends from the front face. float nx = v12y * v10z - v10y * v12z; float ny = v12z * v10x - v10z * v12x; float nz = v12x * v10y - v10x * v12y; @@ -7876,14 +7893,18 @@ public class PGraphicsOpenGL extends PGraphics { for (int i = 1; i < vertexCount - 1; i++) { int i1 = i; int i0, i2; - if (i % 2 == 0) { - // The even triangles (0, 2, 4...) should be CW - i0 = i + 1; - i2 = i - 1; - } else { - // The even triangles (1, 3, 5...) should be CCW + // Vertices are specified by user as: + // 1-3 ... + // |\|\ ... + // 0-2-4 ... + if (i % 2 == 1) { + // The odd triangles (1, 3, 5...) should be CW (left-handed) i0 = i - 1; i2 = i + 1; + } else { + // The even triangles (2, 4, 6...) should be CCW (left-handed) + i0 = i + 1; + i2 = i - 1; } calcTriangleNormal(i0, i1, i2); } @@ -7908,8 +7929,14 @@ public class PGraphicsOpenGL extends PGraphics { int i2 = 2 * qd; int i3 = 2 * qd + 1; - calcTriangleNormal(i0, i3, i1); - calcTriangleNormal(i0, i2, i3); + // Vertices are specified by user as: + // 1-3-5 ... + // |\|\| ... + // 0-2-4 ... + // thus (0, 1, 2) and (2, 1, 3) are triangles + // in CW order (left-handed). + calcTriangleNormal(i0, i1, i2); + calcTriangleNormal(i2, i1, i3); } } @@ -8081,56 +8108,108 @@ public class PGraphicsOpenGL extends PGraphics { int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH); int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH); - int idx0 = addVertex(centerX, centerY, VERTEX, true); + // get length before wrapping indexes so (startLUT <= stopLUT); + int length = PApplet.constrain(stopLUT - startLUT, 0, SINCOS_LENGTH); - int increment = 1; // what's a good algorithm? stopLUT - startLUT; - int pidx = 0, idx = 0; - for (int i = startLUT; i < stopLUT; i += increment) { - int ii = i % SINCOS_LENGTH; - // modulo won't make the value positive - if (ii < 0) ii += SINCOS_LENGTH; + boolean fullCircle = length == SINCOS_LENGTH; + + if (fullCircle && arcMode == CHORD) { + // get rid of overlapping vertices, + // solves problem with closing edge in P3D + length -= 1; + stopLUT -= 1; + } + + { // wrap indexes so they are safe to use in LUT + startLUT %= SINCOS_LENGTH; + if (startLUT < 0) startLUT += SINCOS_LENGTH; + + stopLUT %= SINCOS_LENGTH; + if (stopLUT < 0) stopLUT += SINCOS_LENGTH; + } + + int idx0; + if (arcMode == CHORD || arcMode == OPEN) { + // move center to the middle of flat side + // to properly display arcs smaller than PI + float relX = (cosLUT[startLUT] + cosLUT[stopLUT]) * 0.5f * hr; + float relY = (sinLUT[startLUT] + sinLUT[stopLUT]) * 0.5f * vr; + idx0 = addVertex(centerX + relX, centerY + relY, VERTEX, true); + } else { + idx0 = addVertex(centerX, centerY, VERTEX, true); + } + + int inc; + { // initializes inc the same way ellipse does + float sx1 = pg.screenX(x, y); + float sy1 = pg.screenY(x, y); + float sx2 = pg.screenX(x + w, y + h); + float sy2 = pg.screenY(x + w, y + h); + + int accuracy = + PApplet.min(MAX_POINT_ACCURACY, PApplet.max(MIN_POINT_ACCURACY, + (int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) / + POINT_ACCURACY_FACTOR))); + inc = PApplet.max(1, SINCOS_LENGTH / accuracy); + } + + int idx = idx0; + int pidx; + + int i = -inc; + int ii; + + // i: (0 -> length) inclusive + // ii: (startLUT -> stopLUT) inclusive, going CW (left-handed), + // wrapping around end of LUT + do { + i += inc; + i = PApplet.min(i, length); // clamp so last vertex won't go over + + ii = startLUT + i; // ii from 0 to (2 * SINCOS_LENGTH - 1) + if (ii >= SINCOS_LENGTH) ii -= SINCOS_LENGTH; + + pidx = idx; idx = addVertex(centerX + cosLUT[ii] * hr, centerY + sinLUT[ii] * vr, - VERTEX, i == startLUT && !fill); + VERTEX, i == 0 && !fill); if (stroke) { - if (arcMode == PIE) { - addEdge(pidx, idx, i == startLUT, false); - } else if (startLUT < i) { - addEdge(pidx, idx, i == startLUT + 1, arcMode == 0 && - i == stopLUT - 1); + if (arcMode == CHORD || arcMode == PIE) { + addEdge(pidx, idx, i == 0, false); + } else if (0 < i) { + // when drawing full circle, the edge is closed later + addEdge(pidx, idx, i == inc, i == length && !fullCircle); } } + } while (i < length); + + // keeping last vertex as idx and second last vertex as pidx - pidx = idx; - } - // draw last point explicitly for accuracy - idx = addVertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr, - centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr, - VERTEX, false); if (stroke) { - if (arcMode == PIE) { + if (arcMode == CHORD || arcMode == PIE) { addEdge(idx, idx0, false, false); closeEdge(idx, idx0); - } - } - if (arcMode == CHORD || arcMode == OPEN) { - // Add a last vertex coincident with the first along the perimeter - pidx = idx; - int i = startLUT; - int ii = i % SINCOS_LENGTH; - if (ii < 0) ii += SINCOS_LENGTH; - idx = addVertex(centerX + cosLUT[ii] * hr, - centerY + sinLUT[ii] * vr, - VERTEX, false); - if (stroke && arcMode == CHORD) { - addEdge(pidx, idx, false, true); + } else if (fullCircle) { + closeEdge(pidx, idx); } } } void addBox(float w, float h, float d, boolean fill, boolean stroke) { + + // Correct normals if some dimensions are negative so they always + // extend from front face. We could just take absolute value + // of dimensions, but that would affect texturing. + boolean invertNormX = (h > 0) != (d > 0); + boolean invertNormY = (w > 0) != (d > 0); + boolean invertNormZ = (w > 0) != (h > 0); + + int normX = invertNormX ? -1 : 1; + int normY = invertNormY ? -1 : 1; + int normZ = invertNormZ ? -1 : 1; + float x1 = -w/2f; float x2 = w/2f; float y1 = -h/2f; float y2 = h/2f; float z1 = -d/2f; float z2 = d/2f; @@ -8138,11 +8217,11 @@ public class PGraphicsOpenGL extends PGraphics { int idx1 = 0, idx2 = 0, idx3 = 0, idx4 = 0; if (fill || stroke) { // back face - setNormal(0, 0, -1); + setNormal(0, 0, -normZ); idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX, true); - idx2 = addVertex(x2, y1, z1, 1, 0, VERTEX, false); + idx2 = addVertex(x1, y2, z1, 0, 1, VERTEX, false); idx3 = addVertex(x2, y2, z1, 1, 1, VERTEX, false); - idx4 = addVertex(x1, y2, z1, 0, 1, VERTEX, false); + idx4 = addVertex(x2, y1, z1, 1, 0, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8152,10 +8231,10 @@ public class PGraphicsOpenGL extends PGraphics { } // front face - setNormal(0, 0, 1); - idx1 = addVertex(x2, y1, z2, 0, 0, VERTEX, false); + setNormal(0, 0, normZ); + idx1 = addVertex(x1, y2, z2, 1, 1, VERTEX, false); idx2 = addVertex(x1, y1, z2, 1, 0, VERTEX, false); - idx3 = addVertex(x1, y2, z2, 1, 1, VERTEX, false); + idx3 = addVertex(x2, y1, z2, 0, 0, VERTEX, false); idx4 = addVertex(x2, y2, z2, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); @@ -8166,11 +8245,11 @@ public class PGraphicsOpenGL extends PGraphics { } // right face - setNormal(1, 0, 0); + setNormal(normX, 0, 0); idx1 = addVertex(x2, y1, z1, 0, 0, VERTEX, false); - idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); + idx2 = addVertex(x2, y2, z1, 0, 1, VERTEX, false); idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false); - idx4 = addVertex(x2, y2, z1, 0, 1, VERTEX, false); + idx4 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8180,10 +8259,10 @@ public class PGraphicsOpenGL extends PGraphics { } // left face - setNormal(-1, 0, 0); - idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); + setNormal(-normX, 0, 0); + idx1 = addVertex(x1, y2, z1, 1, 1, VERTEX, false); idx2 = addVertex(x1, y1, z1, 1, 0, VERTEX, false); - idx3 = addVertex(x1, y2, z1, 1, 1, VERTEX, false); + idx3 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); @@ -8193,26 +8272,26 @@ public class PGraphicsOpenGL extends PGraphics { closeEdge(idx4, idx1); } - // bottom face - setNormal(0, -1, 0); - idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); - idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); - idx3 = addVertex(x2, y1, z1, 1, 1, VERTEX, false); - idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX, false); - if (stroke) { - addEdge(idx1, idx2, true, false); - addEdge(idx2, idx3, false, false); - addEdge(idx3, idx4, false, false); - addEdge(idx4, idx1, false, false); - closeEdge(idx4, idx1); - } - // top face - setNormal(0, 1, 0); + setNormal(0, -normY, 0); + idx1 = addVertex(x2, y1, z1, 1, 1, VERTEX, false); + idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); + idx3 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); + idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX, false); + if (stroke) { + addEdge(idx1, idx2, true, false); + addEdge(idx2, idx3, false, false); + addEdge(idx3, idx4, false, false); + addEdge(idx4, idx1, false, false); + closeEdge(idx4, idx1); + } + + // bottom face + setNormal(0, normY, 0); idx1 = addVertex(x1, y2, z1, 0, 0, VERTEX, false); - idx2 = addVertex(x2, y2, z1, 1, 0, VERTEX, false); + idx2 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false); - idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); + idx4 = addVertex(x2, y2, z1, 1, 0, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8342,8 +8421,8 @@ public class PGraphicsOpenGL extends PGraphics { int i0 = vert0 + i; int i1 = vert0 + i + detailU + 1; - indices[indCount + 3 * i + 0] = i0; - indices[indCount + 3 * i + 1] = i1; + indices[indCount + 3 * i + 0] = i1; + indices[indCount + 3 * i + 1] = i0; indices[indCount + 3 * i + 2] = i0 + 1; addEdge(i0, i0 + 1, true, true); @@ -9169,6 +9248,7 @@ public class PGraphicsOpenGL extends PGraphics { // // Normal calculation + // Expects vertices in CW (left-handed) order. void calcPolyNormal(int i0, int i1, int i2) { int index; diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 9957204c8..9aa70d2d1 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -167,7 +167,7 @@ public class PJOGL extends PGL { /** This countdown latch is used to maintain the synchronization between * Processing's drawing thread and JOGL's rendering thread */ - protected CountDownLatch drawLatch; + protected CountDownLatch drawLatch = new CountDownLatch(0); /** Flag used to do request final display() call to make sure that the * buffers are properly swapped. diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 6db7fddca..a771ff053 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -58,6 +58,13 @@ import java.util.Stack; * DXF: http://en.wikipedia.org/wiki/AutoCAD_DXF */ public class PShapeOpenGL extends PShape { + // Testing these constants, not use as they might go away... + static public final int POSITION = 0; + static public final int NORMAL = 1; + static public final int TEXCOORD = 2; + static public final int DIRECTION = 3; + static public final int OFFSET = 4; + static protected final int TRANSLATE = 0; static protected final int ROTATE = 1; static protected final int SCALE = 2; @@ -108,6 +115,9 @@ public class PShapeOpenGL extends PShape { public int glPointAttrib; public int glPointIndex; + // Testing this field, not use as it might go away... + public int glUsage = PGL.STATIC_DRAW; + // ........................................................ // Offsets for geometry aggregation and update. @@ -2493,6 +2503,73 @@ public class PShapeOpenGL extends PShape { return tess; } + // Testing this method, not use as it might go away... + public float[] getTessellation(int kind, int data) { + updateTessellation(); + + if (kind == TRIANGLES) { + if (data == POSITION) { + if (is3D()) { + root.setModifiedPolyVertices(firstPolyVertex, lastPolyVertex); + } else if (is2D()) { + int last1 = lastPolyVertex + 1; + if (-1 < firstLineVertex) last1 = firstLineVertex; + if (-1 < firstPointVertex) last1 = firstPointVertex; + root.setModifiedPolyVertices(firstPolyVertex, last1 - 1); + } + return tessGeo.polyVertices; + } else if (data == NORMAL) { + if (is3D()) { + root.setModifiedPolyNormals(firstPolyVertex, lastPolyVertex); + } else if (is2D()) { + int last1 = lastPolyVertex + 1; + if (-1 < firstLineVertex) last1 = firstLineVertex; + if (-1 < firstPointVertex) last1 = firstPointVertex; + root.setModifiedPolyNormals(firstPolyVertex, last1 - 1); + } + return tessGeo.polyNormals; + } else if (data == TEXCOORD) { + if (is3D()) { + root.setModifiedPolyTexCoords(firstPolyVertex, lastPolyVertex); + } else if (is2D()) { + int last1 = lastPolyVertex + 1; + if (-1 < firstLineVertex) last1 = firstLineVertex; + if (-1 < firstPointVertex) last1 = firstPointVertex; + root.setModifiedPolyTexCoords(firstPolyVertex, last1 - 1); + } + return tessGeo.polyTexCoords; + } + } else if (kind == LINES) { + if (data == POSITION) { + if (is3D()) { + root.setModifiedLineVertices(firstLineVertex, lastLineVertex); + } else if (is2D()) { + root.setModifiedPolyVertices(firstLineVertex, lastLineVertex); + } + return tessGeo.lineVertices; + } else if (data == DIRECTION) { + if (is2D()) { + root.setModifiedLineAttributes(firstLineVertex, lastLineVertex); + } + return tessGeo.lineDirections; + } + } else if (kind == POINTS) { + if (data == POSITION) { + if (is3D()) { + root.setModifiedPointVertices(firstPointVertex, lastPointVertex); + } else if (is2D()) { + root.setModifiedPolyVertices(firstPointVertex, lastPointVertex); + } + return tessGeo.pointVertices; + } else if (data == OFFSET) { + if (is2D()) { + root.setModifiedPointAttributes(firstPointVertex, lastPointVertex); + } + return tessGeo.pointOffsets; + } + } + return null; + } /////////////////////////////////////////////////////////// @@ -3652,56 +3729,56 @@ public class PShapeOpenGL extends PShape { glPolyVertex = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyVertex); pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef, - tessGeo.polyVerticesBuffer, PGL.STATIC_DRAW); + tessGeo.polyVerticesBuffer, glUsage); tessGeo.updatePolyColorsBuffer(); if (glPolyColor == 0) glPolyColor = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyColor); pgl.bufferData(PGL.ARRAY_BUFFER, sizei, - tessGeo.polyColorsBuffer, PGL.STATIC_DRAW); + tessGeo.polyColorsBuffer, glUsage); tessGeo.updatePolyNormalsBuffer(); if (glPolyNormal == 0) glPolyNormal = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyNormal); pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef, - tessGeo.polyNormalsBuffer, PGL.STATIC_DRAW); + tessGeo.polyNormalsBuffer, glUsage); tessGeo.updatePolyTexCoordsBuffer(); if (glPolyTexcoord == 0) glPolyTexcoord = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyTexcoord); pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef, - tessGeo.polyTexCoordsBuffer, PGL.STATIC_DRAW); + tessGeo.polyTexCoordsBuffer, glUsage); tessGeo.updatePolyAmbientBuffer(); if (glPolyAmbient == 0) glPolyAmbient = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyAmbient); pgl.bufferData(PGL.ARRAY_BUFFER, sizei, - tessGeo.polyAmbientBuffer, PGL.STATIC_DRAW); + tessGeo.polyAmbientBuffer, glUsage); tessGeo.updatePolySpecularBuffer(); if (glPolySpecular == 0) glPolySpecular = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolySpecular); pgl.bufferData(PGL.ARRAY_BUFFER, sizei, - tessGeo.polySpecularBuffer, PGL.STATIC_DRAW); + tessGeo.polySpecularBuffer, glUsage); tessGeo.updatePolyEmissiveBuffer(); if (glPolyEmissive == 0) glPolyEmissive = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyEmissive); pgl.bufferData(PGL.ARRAY_BUFFER, sizei, - tessGeo.polyEmissiveBuffer, PGL.STATIC_DRAW); + tessGeo.polyEmissiveBuffer, glUsage); tessGeo.updatePolyShininessBuffer(); if (glPolyShininess == 0) glPolyShininess = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyShininess); pgl.bufferData(PGL.ARRAY_BUFFER, sizef, - tessGeo.polyShininessBuffer, PGL.STATIC_DRAW); + tessGeo.polyShininessBuffer, glUsage); pgl.bindBuffer(PGL.ARRAY_BUFFER, 0); @@ -3711,7 +3788,7 @@ public class PShapeOpenGL extends PShape { pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex); pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER, tessGeo.polyIndexCount * PGL.SIZEOF_INDEX, - tessGeo.polyIndicesBuffer, PGL.STATIC_DRAW); + tessGeo.polyIndicesBuffer, glUsage); pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0); } @@ -3727,21 +3804,21 @@ public class PShapeOpenGL extends PShape { glLineVertex = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineVertex); pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef, - tessGeo.lineVerticesBuffer, PGL.STATIC_DRAW); + tessGeo.lineVerticesBuffer, glUsage); tessGeo.updateLineColorsBuffer(); if (glLineColor == 0) glLineColor = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineColor); pgl.bufferData(PGL.ARRAY_BUFFER, sizei, - tessGeo.lineColorsBuffer, PGL.STATIC_DRAW); + tessGeo.lineColorsBuffer, glUsage); tessGeo.updateLineDirectionsBuffer(); if (glLineAttrib == 0) glLineAttrib = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineAttrib); pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef, - tessGeo.lineDirectionsBuffer, PGL.STATIC_DRAW); + tessGeo.lineDirectionsBuffer, glUsage); pgl.bindBuffer(PGL.ARRAY_BUFFER, 0); @@ -3751,7 +3828,7 @@ public class PShapeOpenGL extends PShape { pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glLineIndex); pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER, tessGeo.lineIndexCount * PGL.SIZEOF_INDEX, - tessGeo.lineIndicesBuffer, PGL.STATIC_DRAW); + tessGeo.lineIndicesBuffer, glUsage); pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0); } @@ -3767,21 +3844,21 @@ public class PShapeOpenGL extends PShape { glPointVertex = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointVertex); pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef, - tessGeo.pointVerticesBuffer, PGL.STATIC_DRAW); + tessGeo.pointVerticesBuffer, glUsage); tessGeo.updatePointColorsBuffer(); if (glPointColor == 0) glPointColor = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointColor); pgl.bufferData(PGL.ARRAY_BUFFER, sizei, - tessGeo.pointColorsBuffer, PGL.STATIC_DRAW); + tessGeo.pointColorsBuffer, glUsage); tessGeo.updatePointOffsetsBuffer(); if (glPointAttrib == 0) glPointAttrib = PGraphicsOpenGL.createVertexBufferObject(context, pgl); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointAttrib); pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef, - tessGeo.pointOffsetsBuffer, PGL.STATIC_DRAW); + tessGeo.pointOffsetsBuffer, glUsage); pgl.bindBuffer(PGL.ARRAY_BUFFER, 0); @@ -3791,7 +3868,7 @@ public class PShapeOpenGL extends PShape { pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPointIndex); pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER, tessGeo.pointIndexCount * PGL.SIZEOF_INDEX, - tessGeo.pointIndicesBuffer, PGL.STATIC_DRAW); + tessGeo.pointIndicesBuffer, glUsage); pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0); } diff --git a/core/src/processing/opengl/TexlightFrag.glsl b/core/src/processing/opengl/TexlightFrag.glsl new file mode 100644 index 000000000..f423e49d3 --- /dev/null +++ b/core/src/processing/opengl/TexlightFrag.glsl @@ -0,0 +1,36 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-13 Ben Fry and Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + */ + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +uniform sampler2D texture; + +uniform vec2 texOffset; + +varying vec4 vertColor; +varying vec4 backVertColor; +varying vec4 vertTexCoord; + +void main() { + gl_FragColor = texture2D(texture, vertTexCoord.st) * (gl_FrontFacing ? vertColor : backVertColor); +} \ No newline at end of file diff --git a/core/src/processing/opengl/TexlightVert.glsl b/core/src/processing/opengl/TexlightVert.glsl index 6542bf8fb..d9f2cde3a 100644 --- a/core/src/processing/opengl/TexlightVert.glsl +++ b/core/src/processing/opengl/TexlightVert.glsl @@ -45,6 +45,7 @@ attribute vec4 emissive; attribute float shininess; varying vec4 vertColor; +varying vec4 backVertColor; varying vec4 vertTexCoord; const float zero_float = 0.0; @@ -85,17 +86,17 @@ void main() { // Normal vector in eye coordinates vec3 ecNormal = normalize(normalMatrix * normal); - - if (dot(-one_float * ecVertex, ecNormal) < zero_float) { - // If normal is away from camera, choose its opposite. - // If we add backface culling, this will be backfacing - ecNormal *= -one_float; - } + vec3 ecNormalInv = ecNormal * -one_float; // Light calculations vec3 totalAmbient = vec3(0, 0, 0); - vec3 totalDiffuse = vec3(0, 0, 0); - vec3 totalSpecular = vec3(0, 0, 0); + + vec3 totalFrontDiffuse = vec3(0, 0, 0); + vec3 totalFrontSpecular = vec3(0, 0, 0); + + vec3 totalBackDiffuse = vec3(0, 0, 0); + vec3 totalBackSpecular = vec3(0, 0, 0); + for (int i = 0; i < 8; i++) { if (lightCount == i) break; @@ -121,27 +122,36 @@ void main() { : one_float; if (any(greaterThan(lightAmbient[i], zero_vec3))) { - totalAmbient += lightAmbient[i] * falloff; + totalAmbient += lightAmbient[i] * falloff; } if (any(greaterThan(lightDiffuse[i], zero_vec3))) { - totalDiffuse += lightDiffuse[i] * falloff * spotf * - lambertFactor(lightDir, ecNormal); + totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormal); + totalBackDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormalInv); } if (any(greaterThan(lightSpecular[i], zero_vec3))) { - totalSpecular += lightSpecular[i] * falloff * spotf * - blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); - } + totalFrontSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalBackSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); + } } // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - vertColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalFrontDiffuse, 1) * color + + vec4(totalFrontSpecular, 0) * specular + + vec4(emissive.rgb, 0); + backVertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalBackDiffuse, 1) * color + + vec4(totalBackSpecular, 0) * specular + + vec4(emissive.rgb, 0); + // Calculating texture coordinates, with r and q set both to one vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); } diff --git a/core/todo.txt b/core/todo.txt index 224efcd5a..a3ff01848 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,15 +1,4 @@ -0228 core -X add copy() method to PVector -X modify PVector to include better methods for chaining operations -X http://code.google.com/p/processing/issues/detail?id=218 -X https://github.com/processing/processing/issues/257 -X PVector discussion with Dan -o Jer and Dan will look at their code, plus toxiclibs - -table -X major performance improvements to 'newlines' parsing -X debugging table parsing with header rows -X bug fix for setting data type +0229 core (3.0a2) applet removal @@ -17,7 +6,18 @@ _ remove Applet as base class _ performance issues on OS X (might be threading due to Applet) _ https://github.com/processing/processing/issues/2423 +_ fix for maxValue() and minValue() when all entries are bad +_ on FloatDict it was NaN, check across the lists and other dict types +_ StringDict should always put NaN values at the end on sort +_ same for the other list and dict classes +_ (this is part of the point of having these easier versions) + +_ better full screen mode for OS X +_ https://github.com/processing/processing/issues/2641 +_ http://stackoverflow.com/questions/6873568/fullscreen-feature-for-java-apps-on-osx-lion + _ bring back chaining in JSON (and add to XML) +_ maybe once we make the PVector change high @@ -53,12 +53,6 @@ _ image = gc.createCompatibleVolatileImage(source.width, source.height, Transp _ https://github.com/processing/processing/issues/1844 _ 'collector' class.. Dict that points to a list _ String as a key, int/float/string list as values -_ blendMode(ADD) is broken with default renderer -_ https://github.com/processing/processing/issues/2012 -_ may have been introduced between 2.0b7 and 2.0b8 -_ https://github.com/processing/processing/issues/2275 -_ https://github.com/processing/processing/issues/2276 -_ https://github.com/processing/processing/issues/2483 _ add option to have full screen span across screens _ display=all in cmd line _ sketchDisplay() -> 0 for all, or 1, 2, 3... diff --git a/done.txt b/done.txt index 225f3aa3a..6273246fd 100644 --- a/done.txt +++ b/done.txt @@ -1,3 +1,49 @@ +0228 pde (3.0a1) +X increase heap size to 256m (-Xmx256) per Manindra request +X use a ButtonGroup so that the current Mode cannot be de-selected +X https://github.com/processing/processing/issues/2545 + +earlier +X cpu usage when nothing happening (unmarked duplicate) +X https://github.com/processing/processing/issues/1074 + +gsoc +X Line coloring incorrect for filtered contribution listings +X https://github.com/processing/processing/issues/2583 +X https://github.com/processing/processing/pull/2598 +X Added Present's background color as an option to the Preferences window +X https://github.com/processing/processing/pull/2568 +X check for updates with contribs +X https://github.com/processing/processing/pull/2636 +X shows update manager on startup +X contrib properties files ignored in favor of contributions.txt from p5.org +X https://github.com/processing/processing/issues/2572 +X tweak mode integrated +X https://github.com/processing/processing/pull/2624 +X wrong mode selected if sketch is modified (checkbox changes) +X https://github.com/processing/processing/issues/2615 +X Add date and time stamps to the Contribution Manager +X https://github.com/processing/processing/pull/2651 + +pulls +X Implementation of a list of open sketches in the Sketch menu +X https://github.com/processing/processing/pull/2551 +X color selector for the pref (not reading it properly) +X https://github.com/processing/processing/pull/2568 +X lighting issues with non-planar triangle strips or quad strips +X https://github.com/processing/processing/issues/2014 +X https://github.com/processing/processing/issues/2018 +X https://github.com/processing/processing/pull/2644 +X set application name on Linux +X https://github.com/processing/processing/issues/2534 +X https://github.com/processing/processing/pull/2584 +X serial not working on export +X https://github.com/processing/processing/issues/2559 +X build error on Windows +X https://github.com/processing/processing/issues/2603 +X https://github.com/processing/processing/pull/2610 + + 0227 pde (2.2.1) X use mouseReleased() instead of mousePressed() in color selector X otherwise it registers the release as a click in the color window diff --git a/java/libraries/minim/examples/AnalyzeSound/AnalyzeSound.pde b/java/libraries/minim/examples/AnalyzeSound/AnalyzeSound.pde deleted file mode 100644 index 46bdec13a..000000000 --- a/java/libraries/minim/examples/AnalyzeSound/AnalyzeSound.pde +++ /dev/null @@ -1,58 +0,0 @@ -/** - * This sketch demonstrates how to use an FFT to analyze - * the audio being generated by an AudioPlayer. - *

- * FFT stands for Fast Fourier Transform, which is a - * method of analyzing audio that allows you to visualize - * the frequency content of a signal. You've seen - * visualizations like this before in music players - * and car stereos. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.analysis.*; -import ddf.minim.*; - -Minim minim; -AudioPlayer jingle; -FFT fft; - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - // specify that we want the audio buffers of the AudioPlayer - // to be 1024 samples long because our FFT needs to have - // a power-of-two buffer size and this is a good size. - jingle = minim.loadFile("jingle.mp3", 1024); - - // loop the file indefinitely - jingle.loop(); - - // create an FFT object that has a time-domain buffer - // the same size as jingle's sample buffer - // note that this needs to be a power of two - // and that it means the size of the spectrum will be half as large. - fft = new FFT( jingle.bufferSize(), jingle.sampleRate() ); - -} - -void draw() -{ - background(0); - stroke(255); - - // perform a forward FFT on the samples in jingle's mix buffer, - // which contains the mix of both the left and right channels of the file - fft.forward( jingle.mix ); - - for(int i = 0; i < fft.specSize(); i++) - { - // draw the line for frequency band i, scaling it up a bit so we can see it - line( i, height, i, height - fft.getBand(i)*8 ); - } -} diff --git a/java/libraries/minim/examples/AnalyzeSound/data/jingle.mp3 b/java/libraries/minim/examples/AnalyzeSound/data/jingle.mp3 deleted file mode 100644 index 8774a7632..000000000 Binary files a/java/libraries/minim/examples/AnalyzeSound/data/jingle.mp3 and /dev/null differ diff --git a/java/libraries/minim/examples/CreateAnInstrument/CreateAnInstrument.pde b/java/libraries/minim/examples/CreateAnInstrument/CreateAnInstrument.pde deleted file mode 100644 index e43c3f339..000000000 --- a/java/libraries/minim/examples/CreateAnInstrument/CreateAnInstrument.pde +++ /dev/null @@ -1,85 +0,0 @@ -/** - * This sketch demonstrates how to create synthesized sound with Minim using an AudioOutput and - * an Instrument we define. By using the playNote method you can schedule notes to played - * at some point in the future, essentially allowing to you create musical scores with code. - * Because they are constructed with code, they can be either deterministic or different every time. - * This sketch creates a deterministic score, meaning it is the same every time you run the sketch. - *

- * For more complex examples of using playNote check out algorithmicCompExample and compositionExample - * in the Synthesis folder. - *

- * For more information about Minim and additional features, visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; -import ddf.minim.ugens.*; - -Minim minim; -AudioOutput out; - -// to make an Instrument we must define a class -// that implements the Instrument interface. -class SineInstrument implements Instrument -{ - Oscil wave; - Line ampEnv; - - SineInstrument( float frequency ) - { - // make a sine wave oscillator - // the amplitude is zero because - // we are going to patch a Line to it anyway - wave = new Oscil( frequency, 0, Waves.SINE ); - ampEnv = new Line(); - ampEnv.patch( wave.amplitude ); - } - - // this is called by the sequencer when this instrument - // should start making sound. the duration is expressed in seconds. - void noteOn( float duration ) - { - // start the amplitude envelope - ampEnv.activate( duration, 0.5f, 0 ); - // attach the oscil to the output so it makes sound - wave.patch( out ); - } - - // this is called by the sequencer when the instrument should - // stop making sound - void noteOff() - { - wave.unpatch( out ); - } -} - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - // use the getLineOut method of the Minim object to get an AudioOutput object - out = minim.getLineOut(); - - // when providing an Instrument, we always specify start time and duration - out.playNote( 0.0, 0.9, new SineInstrument( 97.99 ) ); - out.playNote( 1.0, 0.9, new SineInstrument( 123.47 ) ); - - // we can use the Frequency class to create frequencies from pitch names - out.playNote( 2.0, 2.9, new SineInstrument( Frequency.ofPitch( "C3" ).asHz() ) ); - out.playNote( 3.0, 1.9, new SineInstrument( Frequency.ofPitch( "E3" ).asHz() ) ); - out.playNote( 4.0, 0.9, new SineInstrument( Frequency.ofPitch( "G3" ).asHz() ) ); -} - -void draw() -{ - background(0); - stroke(255); - - // draw the waveforms - for(int i = 0; i < out.bufferSize() - 1; i++) - { - line( i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50 ); - line( i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50 ); - } -} diff --git a/java/libraries/minim/examples/GetMetaData/GetMetaData.pde b/java/libraries/minim/examples/GetMetaData/GetMetaData.pde deleted file mode 100644 index 717152ba2..000000000 --- a/java/libraries/minim/examples/GetMetaData/GetMetaData.pde +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Get Meta Data - * by Damien Di Fede. - * - * This sketch demonstrates how to use the getMetaData - * method of AudioPlayer. This method is also available - * for AudioSnippet and AudioSample. - * You should use this method when you want to retrieve metadata - * about a file that you have loaded, like ID3 tags from an mp3 file. - * If you load WAV file or other non-tagged file, most of the metadata - * will be empty, but you will still have information like the filename - * and the length. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; - -Minim minim; -AudioPlayer groove; -AudioMetaData meta; - -void setup() -{ - size(512, 256, P2D); - - minim = new Minim(this); - groove = minim.loadFile("groove.mp3"); - meta = groove.getMetaData(); - - textFont(createFont("Serif", 12)); -} - -int ys = 25; -int yi = 15; - -void draw() -{ - background(0); - int y = ys; - text("File Name: " + meta.fileName(), 5, y); - text("Length (in milliseconds): " + meta.length(), 5, y+=yi); - text("Title: " + meta.title(), 5, y+=yi); - text("Author: " + meta.author(), 5, y+=yi); - text("Album: " + meta.album(), 5, y+=yi); - text("Date: " + meta.date(), 5, y+=yi); - text("Comment: " + meta.comment(), 5, y+=yi); - text("Track: " + meta.track(), 5, y+=yi); - text("Genre: " + meta.genre(), 5, y+=yi); - text("Copyright: " + meta.copyright(), 5, y+=yi); - text("Disc: " + meta.disc(), 5, y+=yi); - text("Composer: " + meta.composer(), 5, y+=yi); - text("Orchestra: " + meta.orchestra(), 5, y+=yi); - text("Publisher: " + meta.publisher(), 5, y+=yi); - text("Encoded: " + meta.encoded(), 5, y+=yi); -} diff --git a/java/libraries/minim/examples/GetMetaData/data/groove.mp3 b/java/libraries/minim/examples/GetMetaData/data/groove.mp3 deleted file mode 100644 index 22fd64fd4..000000000 Binary files a/java/libraries/minim/examples/GetMetaData/data/groove.mp3 and /dev/null differ diff --git a/java/libraries/minim/examples/GetMetaData/data/serif.vlw b/java/libraries/minim/examples/GetMetaData/data/serif.vlw deleted file mode 100644 index dbb25086b..000000000 Binary files a/java/libraries/minim/examples/GetMetaData/data/serif.vlw and /dev/null differ diff --git a/java/libraries/minim/examples/MonitorInput/MonitorInput.pde b/java/libraries/minim/examples/MonitorInput/MonitorInput.pde deleted file mode 100644 index 86679683b..000000000 --- a/java/libraries/minim/examples/MonitorInput/MonitorInput.pde +++ /dev/null @@ -1,61 +0,0 @@ -/** - * This sketch demonstrates how to monitor the currently active audio input - * of the computer using an AudioInput. What you will actually - * be monitoring depends on the current settings of the machine the sketch is running on. - * Typically, you will be monitoring the built-in microphone, but if running on a desktop - * it's feasible that the user may have the actual audio output of the computer - * as the active audio input, or something else entirely. - *

- * Press 'm' to toggle monitoring on and off. - *

- * When you run your sketch as an applet you will need to sign it in order to get an input. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; - -Minim minim; -AudioInput in; - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - // use the getLineIn method of the Minim object to get an AudioInput - in = minim.getLineIn(); -} - -void draw() -{ - background(0); - stroke(255); - - // draw the waveforms so we can see what we are monitoring - for(int i = 0; i < in.bufferSize() - 1; i++) - { - line( i, 50 + in.left.get(i)*50, i+1, 50 + in.left.get(i+1)*50 ); - line( i, 150 + in.right.get(i)*50, i+1, 150 + in.right.get(i+1)*50 ); - } - - String monitoringState = in.isMonitoring() ? "enabled" : "disabled"; - text( "Input monitoring is currently " + monitoringState + ".", 5, 15 ); -} - -void keyPressed() -{ - if ( key == 'm' || key == 'M' ) - { - if ( in.isMonitoring() ) - { - in.disableMonitoring(); - } - else - { - in.enableMonitoring(); - } - } -} diff --git a/java/libraries/minim/examples/PatchingAnInput/PatchingAnInput.pde b/java/libraries/minim/examples/PatchingAnInput/PatchingAnInput.pde deleted file mode 100644 index e756a6d17..000000000 --- a/java/libraries/minim/examples/PatchingAnInput/PatchingAnInput.pde +++ /dev/null @@ -1,56 +0,0 @@ -/** - * This sketch demonstrates how to create a simple synthesis chain that - * involves controlling the value of a UGenInput with the output of - * a UGen. In this case, we patch an Oscil generating a sine wave into - * the amplitude input of an Oscil generating a square wave. The result - * is known as amplitude modulation. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; -import ddf.minim.ugens.*; - -Minim minim; -AudioOutput out; -Oscil wave; -Oscil mod; - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - // use the getLineOut method of the Minim object to get an AudioOutput object - out = minim.getLineOut(); - - // create a triangle wave Oscil, set to 440 Hz, at 1.0 amplitude - // in this case, the amplitude we construct the Oscil with - // doesn't matter because we will be patching something to - // its amplitude input. - wave = new Oscil( 440, 1.0f, Waves.TRIANGLE ); - - // create a sine wave Oscil for modulating the amplitude of wave - mod = new Oscil( 2, 0.4f, Waves.SINE ); - - // connect up the modulator - mod.patch( wave.amplitude ); - - // patch wave to the output - wave.patch( out ); -} - -void draw() -{ - background(0); - stroke(255); - - // draw the waveforms - for(int i = 0; i < out.bufferSize() - 1; i++) - { - line( i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50 ); - line( i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50 ); - } -} diff --git a/java/libraries/minim/examples/PlayAFile/PlayAFile.pde b/java/libraries/minim/examples/PlayAFile/PlayAFile.pde deleted file mode 100644 index c95eb3956..000000000 --- a/java/libraries/minim/examples/PlayAFile/PlayAFile.pde +++ /dev/null @@ -1,48 +0,0 @@ -/** - * This sketch demonstrates how to play a file with Minim using an AudioPlayer.
- * It's also a good example of how to draw the waveform of the audio. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; - -Minim minim; -AudioPlayer player; - -void setup() -{ - size(512, 200, P3D); - - // we pass this to Minim so that it can load files from the data directory - minim = new Minim(this); - - // loadFile will look in all the same places as loadImage does. - // this means you can find files that are in the data folder and the - // sketch folder. you can also pass an absolute path, or a URL. - player = minim.loadFile("marcus_kellis_theme.mp3"); - - // play the file from start to finish. - // if you want to play the file again, - // you need to call rewind() first. - player.play(); -} - -void draw() -{ - background(0); - stroke(255); - - // draw the waveforms - // the values returned by left.get() and right.get() will be between -1 and 1, - // so we need to scale them up to see the waveform - // note that if the file is MONO, left.get() and right.get() will return the same value - for(int i = 0; i < player.bufferSize() - 1; i++) - { - float x1 = map( i, 0, player.bufferSize(), 0, width ); - float x2 = map( i+1, 0, player.bufferSize(), 0, width ); - line( x1, 50 + player.left.get(i)*50, x2, 50 + player.left.get(i+1)*50 ); - line( x1, 150 + player.right.get(i)*50, x2, 150 + player.right.get(i+1)*50 ); - } -} diff --git a/java/libraries/minim/examples/PlayAFile/data/marcus_kellis_theme.mp3 b/java/libraries/minim/examples/PlayAFile/data/marcus_kellis_theme.mp3 deleted file mode 100644 index ba57c5aac..000000000 Binary files a/java/libraries/minim/examples/PlayAFile/data/marcus_kellis_theme.mp3 and /dev/null differ diff --git a/java/libraries/minim/examples/RecordAudioInput/RecordAudioInput.pde b/java/libraries/minim/examples/RecordAudioInput/RecordAudioInput.pde deleted file mode 100644 index b5983fde7..000000000 --- a/java/libraries/minim/examples/RecordAudioInput/RecordAudioInput.pde +++ /dev/null @@ -1,87 +0,0 @@ -/** - * This sketch demonstrates how to an AudioRecorder to record audio to disk. - * To use this sketch you need to have something plugged into the line-in on your computer, - * or else be working on a laptop with an active built-in microphone. - *

- * Press 'r' to toggle recording on and off and the press 's' to save to disk. - * The recorded file will be placed in the sketch folder of the sketch. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; - -Minim minim; -AudioInput in; -AudioRecorder recorder; - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - in = minim.getLineIn(); - // create a recorder that will record from the input to the filename specified - // the file will be located in the sketch's root folder. - recorder = minim.createRecorder(in, "myrecording.wav"); - - textFont(createFont("Arial", 12)); -} - -void draw() -{ - background(0); - stroke(255); - // draw the waveforms - // the values returned by left.get() and right.get() will be between -1 and 1, - // so we need to scale them up to see the waveform - for(int i = 0; i < in.bufferSize() - 1; i++) - { - line(i, 50 + in.left.get(i)*50, i+1, 50 + in.left.get(i+1)*50); - line(i, 150 + in.right.get(i)*50, i+1, 150 + in.right.get(i+1)*50); - } - - if ( recorder.isRecording() ) - { - text("Currently recording...", 5, 15); - } - else - { - text("Not recording.", 5, 15); - } -} - -void keyReleased() -{ - if ( key == 'r' ) - { - // to indicate that you want to start or stop capturing audio data, you must call - // beginRecord() and endRecord() on the AudioRecorder object. You can start and stop - // as many times as you like, the audio data will be appended to the end of the buffer - // (in the case of buffered recording) or to the end of the file (in the case of streamed recording). - if ( recorder.isRecording() ) - { - recorder.endRecord(); - } - else - { - recorder.beginRecord(); - } - } - if ( key == 's' ) - { - // we've filled the file out buffer, - // now write it to the file we specified in createRecorder - // in the case of buffered recording, if the buffer is large, - // this will appear to freeze the sketch for sometime - // in the case of streamed recording, - // it will not freeze as the data is already in the file and all that is being done - // is closing the file. - // the method returns the recorded audio as an AudioRecording, - // see the example AudioRecorder >> RecordAndPlayback for more about that - recorder.save(); - println("Done saving."); - } -} diff --git a/java/libraries/minim/examples/RecordAudioOutput/RecordAudioOutput.pde b/java/libraries/minim/examples/RecordAudioOutput/RecordAudioOutput.pde deleted file mode 100644 index c34d03f1e..000000000 --- a/java/libraries/minim/examples/RecordAudioOutput/RecordAudioOutput.pde +++ /dev/null @@ -1,93 +0,0 @@ -/** - * This sketch demonstrates how to use an AudioRecorder to record audio to disk. - * Press 'r' to toggle recording on and off and the press 's' to save to disk. - * The recorded file will be placed in the sketch folder of the sketch. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; -import ddf.minim.ugens.*; - -Minim minim; -AudioOutput out; -AudioRecorder recorder; - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - out = minim.getLineOut(); - - // create a recorder that will record from the output to the filename specified - // the file will be located in the sketch's root folder. - recorder = minim.createRecorder(out, "myrecording.wav"); - - // patch some sound into the output so we have something to record - Oscil wave = new Oscil( 440.f, 1.0f ); - Oscil mod = new Oscil( 4.0f, 0.25f, Waves.SAW ); - mod.offset.setLastValue( 0.5f ); - mod.patch( wave.amplitude ); - wave.patch( out ); - - textFont(createFont("Arial", 12)); -} - -void draw() -{ - background(0); - stroke(255); - // draw the waveforms - // the values returned by left.get() and right.get() will be between -1 and 1, - // so we need to scale them up to see the waveform - for(int i = 0; i < out.bufferSize() - 1; i++) - { - line(i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50); - line(i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50); - } - - if ( recorder.isRecording() ) - { - text("Currently recording...", 5, 15); - } - else - { - text("Not recording.", 5, 15); - } -} - -void keyReleased() -{ - if ( key == 'r' ) - { - // to indicate that you want to start or stop capturing audio data, you must call - // beginRecord() and endRecord() on the AudioRecorder object. You can start and stop - // as many times as you like, the audio data will be appended to the end of the buffer - // (in the case of buffered recording) or to the end of the file (in the case of streamed recording). - if ( recorder.isRecording() ) - { - recorder.endRecord(); - } - else - { - recorder.beginRecord(); - } - } - if ( key == 's' ) - { - // we've filled the file out buffer, - // now write it to the file we specified in createRecorder - // in the case of buffered recording, if the buffer is large, - // this will appear to freeze the sketch for sometime - // in the case of streamed recording, - // it will not freeze as the data is already in the file and all that is being done - // is closing the file. - // the method returns the recorded audio as an AudioRecording, - // see the example AudioRecorder >> RecordAndPlayback for more about that - recorder.save(); - println("Done saving."); - } -} diff --git a/java/libraries/minim/examples/Scrubbing/Scrubbing.pde b/java/libraries/minim/examples/Scrubbing/Scrubbing.pde deleted file mode 100644 index 23f24bdb1..000000000 --- a/java/libraries/minim/examples/Scrubbing/Scrubbing.pde +++ /dev/null @@ -1,71 +0,0 @@ -/** - * This is a relatively simple file player that lets you scrub forward and backward in an audio file.
- * It should be noted that it's not *exactly* scrubbing because the playback speed is not changed, - * it's simply that the position in the song is changed by very small increments when fast-forwarding or rewinding. - * But the end result is convincing enough. - *

- * The positioning code is inside of the Play, Rewind, and Forward classes, which are in button.pde. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; - -Minim minim; -AudioPlayer song; -Play play; -Rewind rewind; -Forward ffwd; - -void setup() -{ - size(512, 200, P3D); - minim = new Minim(this); - // load a file from the data folder, use a sample buffer of 1024 samples - song = minim.loadFile("fair1939.wav", 512); - // buttons for control - play = new Play(width/2 - 50, 130, 20, 10); - rewind = new Rewind(width/2, 130, 20, 10); - ffwd = new Forward(width/2 + 50, 130, 20, 10); -} - -void draw() -{ - background(0); - // draw the wave form - // this wav is MONO, so we only need the left channel, - // though we could have used the right channel and gotten the same values - stroke(255); - for (int i = 0; i < song.bufferSize() - 1; i++) - { - line(i, 50 - song.left.get(i)*50, i+1, 50 - song.left.get(i+1)*10); - } - // draw the position in the song - // the position is in milliseconds, - // to get a meaningful graphic, we need to map the value to the range [0, width] - float x = map(song.position(), 0, song.length(), 0, width); - stroke(255, 0, 0); - line(x, 50 - 20, x, 50 + 20); - // do the controls - play.update(); - play.draw(); - rewind.update(); - rewind.draw(); - ffwd.update(); - ffwd.draw(); -} - -void mousePressed() -{ - play.mousePressed(); - rewind.mousePressed(); - ffwd.mousePressed(); -} - -void mouseReleased() -{ - play.mouseReleased(); - rewind.mouseReleased(); - ffwd.mouseReleased(); -} diff --git a/java/libraries/minim/examples/Scrubbing/button.pde b/java/libraries/minim/examples/Scrubbing/button.pde deleted file mode 100755 index 90cc1b15b..000000000 --- a/java/libraries/minim/examples/Scrubbing/button.pde +++ /dev/null @@ -1,255 +0,0 @@ -abstract class Button -{ - int x, y, hw, hh; - - Button(int x, int y, int hw, int hh) - { - this.x = x; - this.y = y; - this.hw = hw; - this.hh = hh; - } - - boolean pressed() - { - return mouseX > x - hw && mouseX < x + hw && mouseY > y - hh && mouseY < y + hh; - } - - abstract void mousePressed(); - abstract void mouseReleased(); - abstract void update(); - abstract void draw(); -} - -class Play extends Button -{ - boolean play; - boolean invert; - - Play(int x, int y, int hw, int hh) - { - super(x, y, hw, hh); - play = true; - } - - // code to handle playing and pausing the file - void mousePressed() - { - if ( pressed() ) - { - invert = true; - if ( song.isPlaying() ) - { - song.pause(); - play = true; - } - else - { - song.loop(); - play = false; - } - } - } - - void mouseReleased() - { - invert = false; - } - - // play is a boolean value used to determine what to draw on the button - void update() - { - if ( song.isPlaying() ) play = false; - else play = true; - } - - void draw() - { - if ( invert ) - { - fill(255); - stroke(0); - } - else - { - noFill(); - stroke(255); - } - rect(x - hw, y - hh, hw*2, hh*2); - if ( invert ) - { - fill(0); - stroke(255); - } - else - { - fill(255); - noStroke(); - } - if ( play ) - { - triangle(x - hw/3, y - hh/2, x - hw/3, y + hh/2, x + hw/2, y); - } - else - { - rect(x - hw/3, y - hh/2, hw/4, hh); - rect(x + hw/8, y - hh/2, hw/4, hh); - } - } -} - -class Rewind extends Button -{ - boolean invert; - boolean pressed; - - Rewind(int x, int y, int hw, int hh) - { - super(x, y, hw, hh); - invert = false; - } - - // code used to scrub backward in the file - void update() - { - // if the rewind button is currently being pressed - if (pressed) - { - // get the current song position - int pos = song.position(); - // if it greater than 200 milliseconds - if ( pos > 200 ) - { - // rewind the song by 200 milliseconds - song.skip(-200); - } - else - { - // if the song hasn't played more than 100 milliseconds - // just rewind to the beginning - song.rewind(); - } - } - } - - void mousePressed() - { - pressed = pressed(); - if ( pressed ) - { - invert = true; - // if the song isn't currently playing, rewind it to the beginning - if ( !song.isPlaying() ) song.rewind(); - } - } - - void mouseReleased() - { - pressed = false; - invert = false; - } - - void draw() - { - if ( invert ) - { - fill(255); - stroke(0); - } - else - { - noFill(); - stroke(255); - } - rect(x - hw, y - hh, hw*2, hh*2); - if ( invert ) - { - fill(0); - stroke(255); - } - else - { - fill(255); - noStroke(); - } - triangle(x - hw/2, y, x, y - hh/2, x, y + hh/2); - triangle(x, y, x + hw/2, y - hh/2, x + hw/2, y + hh/2); - } -} - -class Forward extends Button -{ - boolean invert; - boolean pressed; - - Forward(int x, int y, int hw, int hh) - { - super(x, y, hw, hh); - invert = false; - } - - void update() - { - // if the forward button is currently being pressed - if (pressed) - { - // get the current position of the song - int pos = song.position(); - // if the song's position is more than 40 milliseconds from the end of the song - if ( pos < song.length() - 40 ) - { - // forward the song by 40 milliseconds - song.skip(40); - } - else - { - // otherwise, cue the song at the end of the song - song.cue( song.length() ); - } - // start the song playing - song.play(); - } - } - - void mousePressed() - { - pressed = pressed(); - if ( pressed ) - { - invert = true; - } - } - - void mouseReleased() - { - pressed = false; - invert = false; - } - - void draw() - { - if ( invert ) - { - fill(255); - stroke(0); - } - else - { - noFill(); - stroke(255); - } - rect(x - hw, y - hh, hw*2, hh*2); - if ( invert ) - { - fill(0); - stroke(255); - } - else - { - fill(255); - noStroke(); - } - triangle(x, y, x - hw/2, y - hh/2, x - hw/2, y + hh/2); - triangle(x, y - hh/2, x, y + hh/2, x + hw/2, y); - } -} diff --git a/java/libraries/minim/examples/Scrubbing/data/fair1939.wav b/java/libraries/minim/examples/Scrubbing/data/fair1939.wav deleted file mode 100755 index 815a691e6..000000000 Binary files a/java/libraries/minim/examples/Scrubbing/data/fair1939.wav and /dev/null differ diff --git a/java/libraries/minim/examples/SequenceSound/SequenceSound.pde b/java/libraries/minim/examples/SequenceSound/SequenceSound.pde deleted file mode 100644 index c23c8fa36..000000000 --- a/java/libraries/minim/examples/SequenceSound/SequenceSound.pde +++ /dev/null @@ -1,85 +0,0 @@ -/** - * This sketch demonstrates how to create synthesized sound with Minim using an AudioOutput and the - * default instrument built into an AudioOutput. By using the playNote method you can - * schedule notes to played at some point in the future, essentially allowing to you create musical scores with - * code. Because they are constructed with code, they can be either deterministic or different every time. This - * sketch creates a deterministic score, meaning it is the same every time you run the sketch. It also demonstrates - * a couple different versions of the playNote method. - *

- * For more complex examples of using playNote check out - * algorithmicCompExample and compositionExample in the Synthesis folder. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; -import ddf.minim.ugens.*; - -Minim minim; -AudioOutput out; - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - // use the getLineOut method of the Minim object to get an AudioOutput object - out = minim.getLineOut(); - - // set the tempo of the sequencer - // this makes the first argument of playNote - // specify the start time in quarter notes - // and the duration becomes relative to the length of a quarter note - // by default the tempo is 60 BPM (beats per minute). - // at 60 BPM both start time and duration can be interpreted as seconds. - // to retrieve the current tempo, use getTempo(). - out.setTempo( 80 ); - - // pause the sequencer so our note play back will be rock solid - // if you don't do this, then tiny bits of error can occur since - // the sequencer is running in parallel with you note queueing. - out.pauseNotes(); - - // given start time, duration, and frequency - out.playNote( 0.0, 0.9, 97.99 ); - out.playNote( 1.0, 0.9, 123.47 ); - - // given start time, duration, and note name - out.playNote( 2.0, 2.9, "C3" ); - out.playNote( 3.0, 1.9, "E3" ); - out.playNote( 4.0, 0.9, "G3" ); - - // given start time and note name or frequency - // (duration defaults to 1.0) - out.playNote( 5.0, "" ); - out.playNote( 6.0, 329.63); - out.playNote( 7.0, "G4" ); - - // the note offset is simply added into the start time of - // every subsequenct call to playNote. It's expressed in beats. - // to get the current note offset, use getNoteOffset(). - out.setNoteOffset( 8.1 ); - - // because only given a note name or frequency - // starttime defaults to 0.0 and duration defaults to 1.0 - out.playNote( "G5" ); - out.playNote( 987.77 ); - - // now we can start the sequencer again to hear our sequence - out.resumeNotes(); -} - -void draw() -{ - background(0); - stroke(255); - - // draw the waveforms - for(int i = 0; i < out.bufferSize() - 1; i++) - { - line( i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50 ); - line( i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50 ); - } -} diff --git a/java/libraries/minim/examples/SoundSpectrum/SoundSpectrum.pde b/java/libraries/minim/examples/SoundSpectrum/SoundSpectrum.pde deleted file mode 100644 index 73de17a0c..000000000 --- a/java/libraries/minim/examples/SoundSpectrum/SoundSpectrum.pde +++ /dev/null @@ -1,180 +0,0 @@ -/** - * An FFT object is used to convert an audio signal into its frequency domain representation. This representation - * lets you see how much of each frequency is contained in an audio signal. Sometimes you might not want to - * work with the entire spectrum, so it's possible to have the FFT object calculate average frequency bands by - * simply averaging the values of adjacent frequency bands in the full spectrum. There are two different ways - * these can be calculated: Linearly, by grouping equal numbers of adjacent frequency bands, or - * Logarithmically, by grouping frequency bands by octave, which is more akin to how humans hear sound. - *
- * This sketch illustrates the difference between viewing the full spectrum, - * linearly spaced averaged bands, and logarithmically spaced averaged bands. - *

- * From top to bottom: - *

    - *
  • The full spectrum.
  • - *
  • The spectrum grouped into 30 linearly spaced averages.
  • - *
  • The spectrum grouped logarithmically into 10 octaves, each split into 3 bands.
  • - *
- * - * Moving the mouse across the sketch will highlight a band in each spectrum and display what the center - * frequency of that band is. The averaged bands are drawn so that they line up with full spectrum bands they - * are averages of. In this way, you can clearly see how logarithmic averages differ from linear averages. - *

- * For more information about Minim and additional features, visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.analysis.*; -import ddf.minim.*; - -Minim minim; -AudioPlayer jingle; -FFT fftLin; -FFT fftLog; - -float height3; -float height23; -float spectrumScale = 4; - -PFont font; - -void setup() -{ - size(512, 480); - height3 = height/3; - height23 = 2*height/3; - - minim = new Minim(this); - jingle = minim.loadFile("jingle.mp3", 1024); - - // loop the file - jingle.loop(); - - // create an FFT object that has a time-domain buffer the same size as jingle's sample buffer - // note that this needs to be a power of two - // and that it means the size of the spectrum will be 1024. - // see the online tutorial for more info. - fftLin = new FFT( jingle.bufferSize(), jingle.sampleRate() ); - - // calculate the averages by grouping frequency bands linearly. use 30 averages. - fftLin.linAverages( 30 ); - - // create an FFT object for calculating logarithmically spaced averages - fftLog = new FFT( jingle.bufferSize(), jingle.sampleRate() ); - - // calculate averages based on a miminum octave width of 22 Hz - // split each octave into three bands - // this should result in 30 averages - fftLog.logAverages( 22, 3 ); - - rectMode(CORNERS); - font = loadFont("ArialMT-12.vlw"); -} - -void draw() -{ - background(0); - - textFont(font); - textSize( 18 ); - - float centerFrequency = 0; - - // perform a forward FFT on the samples in jingle's mix buffer - // note that if jingle were a MONO file, this would be the same as using jingle.left or jingle.right - fftLin.forward( jingle.mix ); - fftLog.forward( jingle.mix ); - - // draw the full spectrum - { - noFill(); - for(int i = 0; i < fftLin.specSize(); i++) - { - // if the mouse is over the spectrum value we're about to draw - // set the stroke color to red - if ( i == mouseX ) - { - centerFrequency = fftLin.indexToFreq(i); - stroke(255, 0, 0); - } - else - { - stroke(255); - } - line(i, height3, i, height3 - fftLin.getBand(i)*spectrumScale); - } - - fill(255, 128); - text("Spectrum Center Frequency: " + centerFrequency, 5, height3 - 25); - } - - // no more outline, we'll be doing filled rectangles from now - noStroke(); - - // draw the linear averages - { - // since linear averages group equal numbers of adjacent frequency bands - // we can simply precalculate how many pixel wide each average's - // rectangle should be. - int w = int( width/fftLin.avgSize() ); - for(int i = 0; i < fftLin.avgSize(); i++) - { - // if the mouse is inside the bounds of this average, - // print the center frequency and fill in the rectangle with red - if ( mouseX >= i*w && mouseX < i*w + w ) - { - centerFrequency = fftLin.getAverageCenterFrequency(i); - - fill(255, 128); - text("Linear Average Center Frequency: " + centerFrequency, 5, height23 - 25); - - fill(255, 0, 0); - } - else - { - fill(255); - } - // draw a rectangle for each average, multiply the value by spectrumScale so we can see it better - rect(i*w, height23, i*w + w, height23 - fftLin.getAvg(i)*spectrumScale); - } - } - - // draw the logarithmic averages - { - // since logarithmically spaced averages are not equally spaced - // we can't precompute the width for all averages - for(int i = 0; i < fftLog.avgSize(); i++) - { - centerFrequency = fftLog.getAverageCenterFrequency(i); - // how wide is this average in Hz? - float averageWidth = fftLog.getAverageBandWidth(i); - - // we calculate the lowest and highest frequencies - // contained in this average using the center frequency - // and bandwidth of this average. - float lowFreq = centerFrequency - averageWidth/2; - float highFreq = centerFrequency + averageWidth/2; - - // freqToIndex converts a frequency in Hz to a spectrum band index - // that can be passed to getBand. in this case, we simply use the - // index as coordinates for the rectangle we draw to represent - // the average. - int xl = (int)fftLog.freqToIndex(lowFreq); - int xr = (int)fftLog.freqToIndex(highFreq); - - // if the mouse is inside of this average's rectangle - // print the center frequency and set the fill color to red - if ( mouseX >= xl && mouseX < xr ) - { - fill(255, 128); - text("Logarithmic Average Center Frequency: " + centerFrequency, 5, height - 25); - fill(255, 0, 0); - } - else - { - fill(255); - } - // draw a rectangle for each average, multiply the value by spectrumScale so we can see it better - rect( xl, height, xr, height - fftLog.getAvg(i)*spectrumScale ); - } - } -} diff --git a/java/libraries/minim/examples/SoundSpectrum/data/ArialMT-12.vlw b/java/libraries/minim/examples/SoundSpectrum/data/ArialMT-12.vlw deleted file mode 100644 index 45150ecac..000000000 Binary files a/java/libraries/minim/examples/SoundSpectrum/data/ArialMT-12.vlw and /dev/null differ diff --git a/java/libraries/minim/examples/SoundSpectrum/data/jingle.mp3 b/java/libraries/minim/examples/SoundSpectrum/data/jingle.mp3 deleted file mode 100644 index 8774a7632..000000000 Binary files a/java/libraries/minim/examples/SoundSpectrum/data/jingle.mp3 and /dev/null differ diff --git a/java/libraries/minim/examples/SynthesizeSound/SynthesizeSound.pde b/java/libraries/minim/examples/SynthesizeSound/SynthesizeSound.pde deleted file mode 100644 index 64b8d915d..000000000 --- a/java/libraries/minim/examples/SynthesizeSound/SynthesizeSound.pde +++ /dev/null @@ -1,100 +0,0 @@ -/** - * This sketch demonstrates how to create synthesized sound with Minim - * using an AudioOutput and an Oscil. An Oscil is a UGen object, - * one of many different types included with Minim. By using - * the numbers 1 thru 5, you can change the waveform being used - * by the Oscil to make sound. These basic waveforms are the - * basis of much audio synthesis. - * - * For many more examples of UGens included with Minim, - * have a look in the Synthesis folder of the Minim examples. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; -import ddf.minim.ugens.*; - -Minim minim; -AudioOutput out; -Oscil wave; - -void setup() -{ - size(512, 200, P3D); - - minim = new Minim(this); - - // use the getLineOut method of the Minim object to get an AudioOutput object - out = minim.getLineOut(); - - // create a sine wave Oscil, set to 440 Hz, at 0.5 amplitude - wave = new Oscil( 440, 0.5f, Waves.SINE ); - // patch the Oscil to the output - wave.patch( out ); -} - -void draw() -{ - background(0); - stroke(255); - strokeWeight(1); - - // draw the waveform of the output - for(int i = 0; i < out.bufferSize() - 1; i++) - { - line( i, 50 - out.left.get(i)*50, i+1, 50 - out.left.get(i+1)*50 ); - line( i, 150 - out.right.get(i)*50, i+1, 150 - out.right.get(i+1)*50 ); - } - - // draw the waveform we are using in the oscillator - stroke( 128, 0, 0 ); - strokeWeight(4); - for( int i = 0; i < width-1; ++i ) - { - point( i, height/2 - (height*0.49) * wave.getWaveform().value( (float)i / width ) ); - } -} - -void mouseMoved() -{ - // usually when setting the amplitude and frequency of an Oscil - // you will want to patch something to the amplitude and frequency inputs - // but this is a quick and easy way to turn the screen into - // an x-y control for them. - - float amp = map( mouseY, 0, height, 1, 0 ); - wave.setAmplitude( amp ); - - float freq = map( mouseX, 0, width, 110, 880 ); - wave.setFrequency( freq ); -} - -void keyPressed() -{ - switch( key ) - { - case '1': - wave.setWaveform( Waves.SINE ); - break; - - case '2': - wave.setWaveform( Waves.TRIANGLE ); - break; - - case '3': - wave.setWaveform( Waves.SAW ); - break; - - case '4': - wave.setWaveform( Waves.SQUARE ); - break; - - case '5': - wave.setWaveform( Waves.QUARTERPULSE ); - break; - - default: break; - } -} diff --git a/java/libraries/minim/examples/TriggerASample/TriggerASample.pde b/java/libraries/minim/examples/TriggerASample/TriggerASample.pde deleted file mode 100644 index dc39a4091..000000000 --- a/java/libraries/minim/examples/TriggerASample/TriggerASample.pde +++ /dev/null @@ -1,84 +0,0 @@ -/** - * This sketch demonstrates how to use the loadSample method of Minim. - * The loadSample method allows you to specify the sample you want to load - * with a String and optionally specify what you want the buffer size of the - * returned AudioSample to be. Minim is able to load wav files, au files, aif - * files, snd files, and mp3 files. When you call loadSample, if you just - * specify the filename it will try to load the sample from the data folder of your sketch. - * However, you can also specify an absolute path (such as "C:\foo\bar\thing.wav") and the - * file will be loaded from that location (keep in mind that won't work from an applet). - * You can also specify a URL (such as "http://www.mysite.com/mp3/song.mp3") but keep in mind - * that if you run the sketch as an applet you may run in to security restrictions - * if the applet is not on the same domain as the file you want to load. You can get around - * the restriction by signing all of the jars in the applet. - *

- * An AudioSample is a special kind of file playback that allows - * you to repeatedly trigger an audio file. It does this by keeping the - * entire file in an internal buffer and then keeping a list of trigger points. - * AudioSample supports up to 20 overlapping triggers, which - * should be plenty for short sounds. It is not advised that you use this class - * for long sounds (like entire songs, for example) because the entire file is - * kept in memory. - *

- * Use 'k' and 's' to trigger a kick drum sample and a snare sample, respectively. - * You will see their waveforms drawn when they are played back. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; - -Minim minim; -AudioSample kick; -AudioSample snare; - -void setup() -{ - size(512, 200, P3D); - minim = new Minim(this); - - // load BD.wav from the data folder - kick = minim.loadSample( "BD.mp3", // filename - 512 // buffer size - ); - - // An AudioSample will spawn its own audio processing Thread, - // and since audio processing works by generating one buffer - // of samples at a time, we can specify how big we want that - // buffer to be in the call to loadSample. - // above, we requested a buffer size of 512 because - // this will make the triggering of the samples sound more responsive. - // on some systems, this might be too small and the audio - // will sound corrupted, in that case, you can just increase - // the buffer size. - - // if a file doesn't exist, loadSample will return null - if ( kick == null ) println("Didn't get kick!"); - - // load SD.wav from the data folder - snare = minim.loadSample("SD.wav", 512); - if ( snare == null ) println("Didn't get snare!"); -} - -void draw() -{ - background(0); - stroke(255); - - // use the mix buffer to draw the waveforms. - for (int i = 0; i < kick.bufferSize() - 1; i++) - { - float x1 = map(i, 0, kick.bufferSize(), 0, width); - float x2 = map(i+1, 0, kick.bufferSize(), 0, width); - line(x1, 50 - kick.mix.get(i)*50, x2, 50 - kick.mix.get(i+1)*50); - line(x1, 150 - snare.mix.get(i)*50, x2, 150 - snare.mix.get(i+1)*50); - } -} - -void keyPressed() -{ - if ( key == 's' ) snare.trigger(); - if ( key == 'k' ) kick.trigger(); -} - diff --git a/java/libraries/minim/examples/TriggerASample/data/BD.mp3 b/java/libraries/minim/examples/TriggerASample/data/BD.mp3 deleted file mode 100644 index 9d1aa49fe..000000000 Binary files a/java/libraries/minim/examples/TriggerASample/data/BD.mp3 and /dev/null differ diff --git a/java/libraries/minim/examples/TriggerASample/data/SD.wav b/java/libraries/minim/examples/TriggerASample/data/SD.wav deleted file mode 100644 index 5020ce899..000000000 Binary files a/java/libraries/minim/examples/TriggerASample/data/SD.wav and /dev/null differ diff --git a/java/libraries/minim/examples/delayExample/delayExample.pde b/java/libraries/minim/examples/delayExample/delayExample.pde deleted file mode 100644 index 6c2b7941b..000000000 --- a/java/libraries/minim/examples/delayExample/delayExample.pde +++ /dev/null @@ -1,90 +0,0 @@ -/* delayExample
- * is an example of using the Delay UGen in a continuous sound example. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - *

- * author: Anderson Mills
- * Anderson Mills's work was supported by numediart (www.numediart.org) - */ - -// import everything necessary to make sound. -import ddf.minim.*; -import ddf.minim.ugens.*; - -// create all of the variables that will need to be accessed in -// more than one methods (setup(), draw(), stop()). -Minim minim; -AudioOutput out; -Delay myDelay; - -// setup is run once at the beginning -void setup() -{ - // initialize the drawing window - size( 512, 200 ); - - // initialize the minim and out objects - minim = new Minim(this); - out = minim.getLineOut(); - - // initialize myDelay with continual feedback and audio passthrough - myDelay = new Delay( 0.4, 0.5, true, true ); - - // sawh will create a Sawtooth wave with the requested number of harmonics. - // like with Waves.randomNHarms for sine waves, - // you can create a richer sounding sawtooth this way. - Waveform saw = Waves.sawh( 15 ); - // create the Blip that will be used - Oscil myBlip = new Oscil( 245.0, 0.3, saw ); - - // Waves.square will create a square wave with an uneven duty-cycle, - // also known as a pulse wave. a square wave has only two values, - // either -1 or 1 and the duty cycle indicates how much of the wave - // should -1 and how much 1. in this case, we are asking for a square - // wave that is -1 90% of the time, and 1 10% of the time. - Waveform square = Waves.square( 0.9 ); - // create an LFO to be used for an amplitude envelope - Oscil myLFO = new Oscil( 1, 0.3, square ); - // offset the center value of the LFO so that it outputs 0 - // for the long portion of the duty cycle - myLFO.offset.setLastValue( 0.3 ); - - myLFO.patch( myBlip.amplitude ); - - // and the Blip is patched through the delay into the output - myBlip.patch( myDelay ).patch( out ); -} - -// draw is run many times -void draw() -{ - // erase the window to dark grey - background( 64 ); - // draw using a light gray stroke - stroke( 192 ); - // draw the waveforms - for( int i = 0; i < out.bufferSize() - 1; i++ ) - { - // find the x position of each buffer value - float x1 = map( i, 0, out.bufferSize(), 0, width ); - float x2 = map( i+1, 0, out.bufferSize(), 0, width ); - // draw a line from one buffer position to the next for both channels - line( x1, 50 + out.left.get(i)*50, x2, 50 + out.left.get(i+1)*50); - line( x1, 150 + out.right.get(i)*50, x2, 150 + out.right.get(i+1)*50); - } - - text( "Delay time is " + myDelay.delTime.getLastValue(), 5, 15 ); - text( "Delay amplitude (feedback) is " + myDelay.delAmp.getLastValue(), 5, 30 ); -} - -// when the mouse is moved, change the delay parameters -void mouseMoved() -{ - // set the delay time by the horizontal location - float delayTime = map( mouseX, 0, width, 0.0001, 0.5 ); - myDelay.setDelTime( delayTime ); - // set the feedback factor by the vertical location - float feedbackFactor = map( mouseY, 0, height, 0.99, 0.0 ); - myDelay.setDelAmp( feedbackFactor ); -} diff --git a/java/libraries/minim/examples/filterExample/filterExample.pde b/java/libraries/minim/examples/filterExample/filterExample.pde deleted file mode 100644 index 2b82c52ba..000000000 --- a/java/libraries/minim/examples/filterExample/filterExample.pde +++ /dev/null @@ -1,84 +0,0 @@ -/* filterExample
- * is an example of using the different filters - * in continuous sound. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - *

- * author: Damien Di Fede, Anderson Mills
- * Anderson Mills's work was supported by numediart (www.numediart.org) - */ - -// import everything necessary to make sound. -import ddf.minim.*; -import ddf.minim.ugens.*; -// the effects package is needed because the filters are there for now. -import ddf.minim.effects.*; - -// create all of the variables that will need to be accessed in -// more than one methods (setup(), draw(), stop()). -Minim minim; -AudioOutput out; - -// setup is run once at the beginning -void setup() -{ -// initialize the drawing window - size(300, 200, P2D); - - // initialize the minim and out objects - minim = new Minim(this); - out = minim.getLineOut(); - - // create all of the variables - IIRFilter filt; - Oscil osc; - Oscil cutOsc; - Constant cutoff; - - // initialize the oscillator - // (a sawtooth wave has energy across the spectrum) - osc = new Oscil(500, 0.2, Waves.SAW); - - // uncoment one of the filters to hear it's effect - //filt = new LowPassSP(400, out.sampleRate()); - //filt = new LowPassFS(400, out.sampleRate()); - filt = new BandPass(400, 100, out.sampleRate()); - //filt = new HighPassSP(400, out.sampleRate()); - //filt = new NotchFilter(400, 100, out.sampleRate()); - - // create an Oscil we will use to modulate - // the cutoff frequency of the filter. - // by using an amplitude of 800 and an - // offset of 1000, the cutoff frequency - // will sweep between 200 and 1800 Hertz. - cutOsc = new Oscil(1, 800, Waves.SINE); - // offset the center value of the Oscil by 1000 - cutOsc.offset.setLastValue( 1000 ); - - // patch the oscil to the cutoff frequency of the filter - cutOsc.patch(filt.cutoff); - - // patch the sawtooth oscil through the filter and then to the output - osc.patch(filt).patch(out); -} - - -// draw is run many times -void draw() -{ - // erase the window to black - background( 0 ); - // draw using a white stroke - stroke( 255 ); - // draw the waveforms - for( int i = 0; i < out.bufferSize() - 1; i++ ) - { - // find the x position of each buffer value - float x1 = map( i, 0, out.bufferSize(), 0, width ); - float x2 = map( i+1, 0, out.bufferSize(), 0, width ); - // draw a line from one buffer position to the next for both channels - line( x1, 50 + out.left.get(i)*50, x2, 50 + out.left.get(i+1)*50); - line( x1, 150 + out.right.get(i)*50, x2, 150 + out.right.get(i+1)*50); - } -} diff --git a/java/libraries/minim/examples/frequencyModulation/frequencyModulation.pde b/java/libraries/minim/examples/frequencyModulation/frequencyModulation.pde deleted file mode 100644 index 7fcb7645a..000000000 --- a/java/libraries/minim/examples/frequencyModulation/frequencyModulation.pde +++ /dev/null @@ -1,81 +0,0 @@ -/* frequencyModulation -

- A simple example for doing FM (frequency modulation) using two Oscils. -

- For more information about Minim and additional features, - visit http://code.compartmental.net/minim/ -

- Author: Damien Di Fede - */ - -// import everything necessary to make sound. -import ddf.minim.*; -import ddf.minim.ugens.*; - -// create all of the variables that will need to be accessed in -// more than one methods (setup(), draw(), stop()). -Minim minim; -AudioOutput out; - -// the Oscil we use for modulating frequency. -Oscil fm; - -// setup is run once at the beginning -void setup() -{ - // initialize the drawing window - size( 512, 200, P3D ); - - // initialize the minim and out objects - minim = new Minim( this ); - out = minim.getLineOut(); - - // make the Oscil we will hear. - // arguments are frequency, amplitude, and waveform - Oscil wave = new Oscil( 200, 0.8, Waves.TRIANGLE ); - // make the Oscil we will use to modulate the frequency of wave. - // the frequency of this Oscil will determine how quickly the - // frequency of wave changes and the amplitude determines how much. - // since we are using the output of fm directly to set the frequency - // of wave, you can think of the amplitude as being expressed in Hz. - fm = new Oscil( 10, 2, Waves.SINE ); - // set the offset of fm so that it generates values centered around 200 Hz - fm.offset.setLastValue( 200 ); - // patch it to the frequency of wave so it controls it - fm.patch( wave.frequency ); - // and patch wave to the output - wave.patch( out ); -} - -// draw is run many times -void draw() -{ - // erase the window to black - background( 0 ); - // draw using a white stroke - stroke( 255 ); - // draw the waveforms - for( int i = 0; i < out.bufferSize() - 1; i++ ) - { - // find the x position of each buffer value - float x1 = map( i, 0, out.bufferSize(), 0, width ); - float x2 = map( i+1, 0, out.bufferSize(), 0, width ); - // draw a line from one buffer position to the next for both channels - line( x1, 50 + out.left.get(i)*50, x2, 50 + out.left.get(i+1)*50); - line( x1, 150 + out.right.get(i)*50, x2, 150 + out.right.get(i+1)*50); - } - - text( "Modulation frequency: " + fm.frequency.getLastValue(), 5, 15 ); - text( "Modulation amplitude: " + fm.amplitude.getLastValue(), 5, 30 ); -} - -// we can change the parameters of the frequency modulation Oscil -// in real-time using the mouse. -void mouseMoved() -{ - float modulateAmount = map( mouseY, 0, height, 220, 1 ); - float modulateFrequency = map( mouseX, 0, width, 0.1, 100 ); - - fm.setFrequency( modulateFrequency ); - fm.setAmplitude( modulateAmount ); -} diff --git a/java/libraries/minim/examples/loadFileIntoBuffer/data/SD.wav b/java/libraries/minim/examples/loadFileIntoBuffer/data/SD.wav deleted file mode 100644 index 5020ce899..000000000 Binary files a/java/libraries/minim/examples/loadFileIntoBuffer/data/SD.wav and /dev/null differ diff --git a/java/libraries/minim/examples/loadFileIntoBuffer/loadFileIntoBuffer.pde b/java/libraries/minim/examples/loadFileIntoBuffer/loadFileIntoBuffer.pde deleted file mode 100644 index 32db474e4..000000000 --- a/java/libraries/minim/examples/loadFileIntoBuffer/loadFileIntoBuffer.pde +++ /dev/null @@ -1,93 +0,0 @@ -/** - * This sketch demonstrates how to use the loadFileIntoBuffer method of the Minim class and is also a good - * reference for some of the methods of the MultiChannelBuffer class. When the sketch begins it loads - * a file from the data folder into a MultiChannelBuffer and then modifies that sample data before - * using it to create a Sampler UGen. You can hear the result of this modification by hitting - * the space bar. - *

- * For more information about Minim and additional features, - * visit http://code.compartmental.net/minim/ - */ - -import ddf.minim.*; -import ddf.minim.ugens.*; - -Minim minim; -MultiChannelBuffer sampleBuffer; - -AudioOutput output; -Sampler sampler; - -void setup() -{ - size(512, 200, P3D); - - // create Minim and an AudioOutput - minim = new Minim(this); - output = minim.getLineOut(); - - // construct a new MultiChannelBuffer with 2 channels and 1024 sample frames. - // in our particular case, it doesn't really matter what we choose for these - // two values because loadFileIntoBuffer will reconfigure the buffer - // to match the channel count and length of the file. - sampleBuffer = new MultiChannelBuffer( 1, 1024 ); - - // we pass the buffer to the method and Minim will reconfigure it to match - // the file. if the file doesn't exist, or there is some other problen with - // loading it, the function will return 0 as the sample rate. - float sampleRate = minim.loadFileIntoBuffer( "SD.wav", sampleBuffer ); - - // make sure the file load worked - if ( sampleRate > 0 ) - { - // double the size of the buffer to give ourselves some silence to play with - int originalBufferSize = sampleBuffer.getBufferSize(); - sampleBuffer.setBufferSize( originalBufferSize * 2 ); - - // go through first half of the buffer, which contains the original sample, - // and add a delayed version of each sample at some random position. - // we happen to know that the source file is only one channel - // but in general you'd want to iterate over all channels when doing something like this - for( int s = 0; s < originalBufferSize; ++s ) - { - int delayIndex = s + int( random( 0, originalBufferSize ) ); - float sampleValue = sampleBuffer.getSample( 0, s ); - float destValue = sampleBuffer.getSample( 0, delayIndex ); - sampleBuffer.setSample( 0, // channel - delayIndex, // sample frame to set - sampleValue + destValue // the value to set - ); - } - - // create a sampler that will use our buffer to generate audio. - // we must provide the sample rate of the audio and the number of voices. - sampler = new Sampler( sampleBuffer, sampleRate, 1 ); - - // and finally, connect to the output so we can hear it - sampler.patch( output ); - } -} - -void draw() -{ - background(0); - stroke(255); - - // use the mix buffer to draw the waveforms. - for (int i = 0; i < output.bufferSize() - 1; i++) - { - float x1 = map(i, 0, output.bufferSize(), 0, width); - float x2 = map(i+1, 0, output.bufferSize(), 0, width); - line(x1, 50 - output.left.get(i)*50, x2, 50 - output.left.get(i+1)*50); - line(x1, 150 - output.right.get(i)*50, x2, 150 - output.right.get(i+1)*50); - } -} - -void keyPressed() -{ - if ( key == ' ' && sampler != null ) - { - sampler.trigger(); - } -} - diff --git a/java/libraries/minim/library/export.txt b/java/libraries/minim/library/export.txt deleted file mode 100644 index f2681acab..000000000 --- a/java/libraries/minim/library/export.txt +++ /dev/null @@ -1 +0,0 @@ -name = Minim Audio diff --git a/java/libraries/minim/license.txt b/java/libraries/minim/license.txt deleted file mode 100644 index fc8a5de7e..000000000 --- a/java/libraries/minim/license.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/java/libraries/minim/version.txt b/java/libraries/minim/version.txt deleted file mode 100644 index bab1033cc..000000000 --- a/java/libraries/minim/version.txt +++ /dev/null @@ -1 +0,0 @@ -3.0 BETA \ No newline at end of file diff --git a/java/libraries/sound/README.txt b/java/libraries/sound/README.md similarity index 100% rename from java/libraries/sound/README.txt rename to java/libraries/sound/README.md diff --git a/java/libraries/sound/build.xml b/java/libraries/sound/build.xml index 7f403f259..463f18c57 100755 --- a/java/libraries/sound/build.xml +++ b/java/libraries/sound/build.xml @@ -1,5 +1,5 @@ - + diff --git a/java/libraries/sound/examples/Effects/Filter/BPF/BPF.pde b/java/libraries/sound/examples/Effects/Filter/BPF/BPF.pde index cac2334ec..30a1f0746 100644 --- a/java/libraries/sound/examples/Effects/Filter/BPF/BPF.pde +++ b/java/libraries/sound/examples/Effects/Filter/BPF/BPF.pde @@ -6,7 +6,7 @@ In this example it is started and stopped by clicking into the renderer window. import processing.sound.*; WhiteNoise noise; -BandPass bPass; +BandPass bandPass; float amp=0.0; @@ -16,14 +16,15 @@ void setup() { // Create the noise generator + Filter noise = new WhiteNoise(this); - bPass = new BandPass(this); + bandPass = new BandPass(this); + noise.play(0.5); - bPass.process(noise, 100); + bandPass.process(noise, 100); } void draw() { - bPass.freq(map(mouseX, 0, 350, 20, 10000)); + bandPass.freq(map(mouseX, 0, width, 20, 10000)); - bPass.res(map(mouseY, 0, 350, 0.05, 1.0)); + bandPass.bw(map(mouseY, 0, height, 100, 1000)); } diff --git a/java/libraries/sound/examples/Effects/Filter/HPF/HPF.pde b/java/libraries/sound/examples/Effects/Filter/HPF/HPF.pde index 0ea52b2ae..d4a82cac9 100644 --- a/java/libraries/sound/examples/Effects/Filter/HPF/HPF.pde +++ b/java/libraries/sound/examples/Effects/Filter/HPF/HPF.pde @@ -17,10 +17,11 @@ void setup() { // Create the noise generator + filter noise = new WhiteNoise(this); highPass = new HighPass(this); + noise.play(0.5); highPass.process(noise, 100); } void draw() { - highPass.freq(map(mouseX, 0, 350, 20, 10000)); + highPass.freq(map(mouseX, 0, width, 80, 10000)); } diff --git a/java/libraries/sound/examples/Effects/Filter/LPF/LPF.pde b/java/libraries/sound/examples/Effects/Filter/LPF/LPF.pde index ab866be0c..070b280ed 100644 --- a/java/libraries/sound/examples/Effects/Filter/LPF/LPF.pde +++ b/java/libraries/sound/examples/Effects/Filter/LPF/LPF.pde @@ -6,7 +6,7 @@ In this example it is started and stopped by clicking into the renderer window. import processing.sound.*; WhiteNoise noise; -LowPass lPass; +LowPass lowPass; float amp=0.0; @@ -16,11 +16,11 @@ void setup() { // Create the noise generator + filter noise = new WhiteNoise(this); - lPass = new LowPass(this); + lowPass = new LowPass(this); noise.play(0.2); - lPass.process(noise, 800); + lowPass.process(noise, 800); } void draw() { - lPass.freq(map(mouseX, 0, 350, 800, 10000)); + lowPass.freq(map(mouseX, 0, width, 80, 10000)); } diff --git a/java/libraries/sound/examples/IO/AudioInput/AudioInput.pde b/java/libraries/sound/examples/IO/AudioInput/AudioInput.pde new file mode 100644 index 000000000..59afab706 --- /dev/null +++ b/java/libraries/sound/examples/IO/AudioInput/AudioInput.pde @@ -0,0 +1,46 @@ +/* +Be Careful with your speaker volume, you might produce a painful +feedback. We recommend to wear headphones for this example. + +*/ + +import processing.sound.*; + +AudioIn input; +Amplitude rms; + +int scale=1; + +void setup() { + size(640,360); + background(255); + + //Create an Audio input and grab the 1st channel + input = new AudioIn(this, 0); + + // start the Audio Input + input.play(); + + // create a new Amplitude analyzer + rms = new Amplitude(this); + + // Patch the input to an volume analyzer + rms.input(input); +} + + +void draw() { + background(125,255,125); + + // adjust the volume of the audio input + input.amp(map(mouseY, 0, height, 0.0, 1.0)); + + // rms.analyze() return a value between 0 and 1. To adjust + // the scaling and mapping of an ellipse we scale from 0 to 0.5 + scale=int(map(rms.analyze(), 0, 0.5, 1, 350)); + noStroke(); + + fill(255,0,150); + // We draw an ellispe coupled to the audio analysis + ellipse(width/2, height/2, 1*scale, 1*scale); +} diff --git a/java/libraries/sound/library/.gitignore b/java/libraries/sound/library/.gitignore new file mode 100644 index 000000000..4a611631b --- /dev/null +++ b/java/libraries/sound/library/.gitignore @@ -0,0 +1,2 @@ +sound.jar + diff --git a/java/libraries/sound/src/cpp/Makefile b/java/libraries/sound/src/cpp/Makefile index 7ac3036da..7e866267d 100644 --- a/java/libraries/sound/src/cpp/Makefile +++ b/java/libraries/sound/src/cpp/Makefile @@ -8,3 +8,4 @@ clean: install: cp libMethClaInterface.jnilib ../../library/macosx + cp libMethClaInterface.jnilib /Users/wirsing/Documents/Processing/libraries/sound/library/macosx/ diff --git a/java/libraries/sound/src/cpp/include/methcla/plugins/bpf.h b/java/libraries/sound/src/cpp/include/methcla/plugins/bpf.h new file mode 100644 index 000000000..c58b8931c --- /dev/null +++ b/java/libraries/sound/src/cpp/include/methcla/plugins/bpf.h @@ -0,0 +1,25 @@ +/* + Copyright 2012-2013 Samplecount S.L. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef METHCLA_PLUGINS_BPF_H_INCLUDED +#define METHCLA_PLUGINS_BPF_H_INCLUDED + +#include + +METHCLA_EXPORT const Methcla_Library* methcla_plugins_bpf(const Methcla_Host*, const char*); +#define METHCLA_PLUGINS_BPF_URI METHCLA_PLUGINS_URI "/bpf" + +#endif /* METHCLA_PLUGINS_BPF_H_INCLUDED */ diff --git a/java/libraries/sound/src/cpp/include/processing_sound_MethClaInterface.h b/java/libraries/sound/src/cpp/include/processing_sound_MethClaInterface.h index 0b309e286..de571b3a0 100644 --- a/java/libraries/sound/src/cpp/include/processing_sound_MethClaInterface.h +++ b/java/libraries/sound/src/cpp/include/processing_sound_MethClaInterface.h @@ -47,6 +47,14 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_synthStop JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_oscSet (JNIEnv *, jobject, jfloat, jfloat, jfloat, jfloat, jintArray); +/* + * Class: processing_sound_MethClaInterface + * Method: oscAudioSet + * Signature: ([I[I[I[I[I)V + */ +JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_oscAudioSet + (JNIEnv *, jobject, jintArray, jintArray, jintArray, jintArray, jintArray); + /* * Class: processing_sound_MethClaInterface * Method: sinePlay @@ -106,10 +114,10 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_pulseSet /* * Class: processing_sound_MethClaInterface * Method: audioInPlay - * Signature: (FFFZ)[I + * Signature: (FFFI)[I */ JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_audioInPlay - (JNIEnv *, jobject, jfloat, jfloat, jfloat, jboolean); + (JNIEnv *, jobject, jfloat, jfloat, jfloat, jint); /* * Class: processing_sound_MethClaInterface @@ -210,9 +218,9 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_brownNoiseSet /* * Class: processing_sound_MethClaInterface * Method: envelopePlay - * Signature: ([IFFFF)I + * Signature: ([IFFFF)[I */ -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_envelopePlay +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_envelopePlay (JNIEnv *, jobject, jintArray, jfloat, jfloat, jfloat, jfloat); /* @@ -226,41 +234,49 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_doneAfter /* * Class: processing_sound_MethClaInterface * Method: highPassPlay - * Signature: ([IFF)I + * Signature: ([IF)[I */ -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_highPassPlay - (JNIEnv *, jobject, jintArray, jfloat, jfloat); +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_highPassPlay + (JNIEnv *, jobject, jintArray, jfloat); /* * Class: processing_sound_MethClaInterface * Method: lowPassPlay - * Signature: ([IFF)I + * Signature: ([IF)[I */ -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_lowPassPlay - (JNIEnv *, jobject, jintArray, jfloat, jfloat); +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_lowPassPlay + (JNIEnv *, jobject, jintArray, jfloat); /* * Class: processing_sound_MethClaInterface * Method: bandPassPlay - * Signature: ([IFF)I + * Signature: ([IFF)[I */ -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_bandPassPlay +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_bandPassPlay (JNIEnv *, jobject, jintArray, jfloat, jfloat); /* * Class: processing_sound_MethClaInterface * Method: filterSet - * Signature: (FFI)V + * Signature: (FI)V */ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_filterSet + (JNIEnv *, jobject, jfloat, jint); + +/* + * Class: processing_sound_MethClaInterface + * Method: filterBwSet + * Signature: (FFI)V + */ +JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_filterBwSet (JNIEnv *, jobject, jfloat, jfloat, jint); /* * Class: processing_sound_MethClaInterface * Method: delayPlay - * Signature: ([IFFF)I + * Signature: ([IFFF)[I */ -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_delayPlay +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_delayPlay (JNIEnv *, jobject, jintArray, jfloat, jfloat, jfloat); /* @@ -274,9 +290,9 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_delaySet /* * Class: processing_sound_MethClaInterface * Method: reverbPlay - * Signature: ([IFFF)I + * Signature: ([IFFF)[I */ -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_reverbPlay +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_reverbPlay (JNIEnv *, jobject, jintArray, jfloat, jfloat, jfloat); /* @@ -287,6 +303,14 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_reverbPlay JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_reverbSet (JNIEnv *, jobject, jfloat, jfloat, jfloat, jint); +/* + * Class: processing_sound_MethClaInterface + * Method: out + * Signature: (I[I)V + */ +JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_out + (JNIEnv *, jobject, jint, jintArray); + /* * Class: processing_sound_MethClaInterface * Method: amplitude diff --git a/java/libraries/sound/src/cpp/processing_sound_MethClaInterface.cpp b/java/libraries/sound/src/cpp/processing_sound_MethClaInterface.cpp index f603bd6ca..796bb8593 100644 --- a/java/libraries/sound/src/cpp/processing_sound_MethClaInterface.cpp +++ b/java/libraries/sound/src/cpp/processing_sound_MethClaInterface.cpp @@ -27,6 +27,7 @@ #include "methcla/plugins/fft.h" #include "methcla/plugins/hpf.h" #include "methcla/plugins/lpf.h" +#include "methcla/plugins/bpf.h" #include "methcla/plugins/delay.h" #include "methcla/plugins/reverb.h" #include "methcla/plugins/audio_in.h" @@ -38,21 +39,33 @@ Methcla::Engine* m_engine; Methcla::Engine& engine() { return *m_engine; } -std::mutex mutex; +std::mutex mutex_fft_in; +std::mutex mutex_fft_out; +std::mutex mutex_amp_in; +std::mutex mutex_amp_out; + static Methcla_Time kLatency = 0.1; -typedef struct data_v{ - int id; - std::atomic amp; -} ServerValue, *ServerValuePtr; - -typedef struct data_a{ - int id; - int fftSize=512; - std::vector fft; -} ServerArray, *ServerArrayPtr; +struct ServerValue{ + ServerValue() : + amp(0), + id(-1) + {} + float amp; + int id; +}; +struct ServerArray{ + ServerArray() : + fftSize(512), + fft(fftSize), + id(-1) + {} + int fftSize; + std::vector fft; + int id; +}; // Engine @@ -77,7 +90,8 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_engineNew (JNIEnv .addLibrary(methcla_plugins_pan2) .addLibrary(methcla_plugins_amplitude_follower) .addLibrary(methcla_plugins_hpf) - .addLibrary(methcla_plugins_lpf) + .addLibrary(methcla_plugins_lpf) + .addLibrary(methcla_plugins_bpf) .addLibrary(methcla_plugins_delay) .addLibrary(methcla_plugins_reverb) .addLibrary(methcla_plugins_fft) @@ -140,6 +154,72 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_oscSet (JNIEnv *en env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); }; +JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_oscAudioSet(JNIEnv *env, jobject object, jintArray freq, jintArray amp, jintArray add, jintArray pos, jintArray nodeId){ + + jint* m_freq = env->GetIntArrayElements(freq, 0); + jint* m_amp = env->GetIntArrayElements(amp, 0); + jint* m_add = env->GetIntArrayElements(add, 0); + jint* m_pos = env->GetIntArrayElements(pos, 0); + jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + + Methcla::Request request(engine()); + request.openBundle(Methcla::immediately); + + if (m_freq[0] != -1) + { + Methcla::AudioBusId freq_bus = m_engine->audioBusId().alloc(); + //request.set(m_nodeId[0], 0 , 0); + //request.free(m_freq[1]); + request.mapOutput(m_freq[0], 0, freq_bus); + request.mapInput(m_nodeId[0], 0, freq_bus); + + std::cout << "freq" << std::endl; + } + + if (m_amp[0] != -1) + { + + Methcla::AudioBusId amp_bus = m_engine->audioBusId().alloc(); + //request.set(m_nodeId[0], 1 , 0); + //request.free(m_amp[1]); + request.mapOutput(m_amp[0], 0, amp_bus); + request.mapInput(m_nodeId[0], 1, amp_bus); + + std::cout << "amp" << std::endl; + } + + if (m_add[0] != -1) + { + Methcla::AudioBusId add_bus = m_engine->audioBusId().alloc(); + request.set(m_nodeId[0], 2 , 0); + request.free(m_add[1]); + request.mapOutput(m_add[0], 0, add_bus); + request.mapInput(m_nodeId[0], 2, add_bus); + + std::cout << "add" << std::endl; + } + + if (m_pos[0] != -1) + { + Methcla::AudioBusId pos_bus = m_engine->audioBusId().alloc(); + request.set(m_nodeId[1], 0 , 0); + request.free(m_pos[1]); + request.mapOutput(m_pos[0], 0, pos_bus); + request.mapInput(m_nodeId[1], 0, pos_bus); + + std::cout << "pos" << std::endl; + } + + request.closeBundle(); + request.send(); + + env->ReleaseIntArrayElements(freq, m_freq, 0); + env->ReleaseIntArrayElements(amp, m_amp, 0); + env->ReleaseIntArrayElements(add, m_add, 0); + env->ReleaseIntArrayElements(pos, m_pos, 0); + env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); +}; + // SineOsc JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_sinePlay(JNIEnv *env, jobject object, jfloat freq, jfloat amp, jfloat add, jfloat pos){ @@ -187,7 +267,6 @@ JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_sinePlay(JNIE }; JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_sawPlay(JNIEnv *env, jobject object, jfloat freq, jfloat amp, jfloat add, jfloat pos){ - jintArray nodeId = env->NewIntArray(2); jint *m_nodeId = env->GetIntArrayElements(nodeId, NULL); @@ -208,6 +287,9 @@ JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_sawPlay(JNIEn {Methcla::Value(1.f)} ); + engine().addNotificationHandler(engine().freeNodeIdHandler(synth.id())); + engine().addNotificationHandler(engine().freeNodeIdHandler(pan.id())); + request.mapOutput(synth.id(), 0, bus); request.mapInput(pan.id(), 0, bus); request.mapOutput(pan.id(), 0, Methcla::AudioBusId(0), Methcla::kBusMappingExternal); @@ -316,6 +398,7 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_sqrSet(JNIEnv *env Methcla::Request request(engine()); request.openBundle(Methcla::immediately); request.set(m_nodeId[0], 0 , freq); + request.set(m_nodeId[0], 0 , 0.5f); request.set(m_nodeId[0], 2 , amp); request.set(m_nodeId[1], 0 , pos); request.closeBundle(); @@ -381,13 +464,12 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_pulseSet(JNIEnv *e env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); }; -JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_audioInPlay(JNIEnv *env, jobject object, jfloat amp, jfloat add, jfloat pos, jboolean out){ +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_audioInPlay(JNIEnv *env, jobject object, jfloat amp, jfloat add, jfloat pos, jint in){ jintArray nodeId = env->NewIntArray(2); jint *m_nodeId = env->GetIntArrayElements(nodeId, NULL); Methcla::AudioBusId bus = m_engine->audioBusId().alloc(); - Methcla::AudioBusId in = m_engine->audioBusId().alloc(); Methcla::Request request(engine()); request.openBundle(Methcla::immediately); @@ -401,11 +483,11 @@ JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_audioInPlay(J auto pan = request.synth( METHCLA_PLUGINS_PAN2_URI, engine().root(), - {pos, 0}, + {pos, 1.f}, {Methcla::Value(1.f)} ); - request.mapInput(synth.id(), 0, in, Methcla::kBusMappingExternal); + request.mapInput(synth.id(), 0, Methcla::AudioBusId(in), Methcla::kBusMappingExternal); request.mapOutput(synth.id(), 0, bus); request.mapInput(pan.id(), 0, bus); @@ -420,7 +502,7 @@ JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_audioInPlay(J request.send(); m_nodeId[0]=synth.id(); - m_nodeId[1]=pan.id(); + m_nodeId[1]= pan.id(); env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); @@ -780,9 +862,11 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_brownNoiseSet(JNIE }; -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_envelopePlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat attackTime, jfloat sustainTime, jfloat sustainLevel, jfloat releaseTime){ +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_envelopePlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat attackTime, jfloat sustainTime, jfloat sustainLevel, jfloat releaseTime){ jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + jintArray returnId = env->NewIntArray(2); + jint *m_returnId = env->GetIntArrayElements(returnId, NULL); Methcla::AudioBusId in_bus = m_engine->audioBusId().alloc(); Methcla::AudioBusId out_bus = m_engine->audioBusId().alloc(); @@ -813,15 +897,21 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_envelopePlay(JNIEn request.closeBundle(); request.send(); - + + m_returnId[0]=synth.id(); + m_returnId[1]=m_nodeId[1]; + + env->ReleaseIntArrayElements(returnId, m_returnId, 0); env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); - return synth.id(); + return returnId; }; -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_highPassPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat freq, jfloat res){ +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_highPassPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat freq){ jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + jintArray returnId = env->NewIntArray(2); + jint *m_returnId = env->GetIntArrayElements(returnId, NULL); Methcla::AudioBusId in_bus = m_engine->audioBusId().alloc(); Methcla::AudioBusId out_bus = m_engine->audioBusId().alloc(); @@ -831,7 +921,7 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_highPassPlay(JNIEn auto synth = request.synth( METHCLA_PLUGINS_HPF_URI, Methcla::NodePlacement::after(m_nodeId[0]), - {freq, res}, + {freq}, {} ); @@ -845,14 +935,20 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_highPassPlay(JNIEn request.closeBundle(); request.send(); - env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); + m_returnId[0]=synth.id(); + m_returnId[1]=m_nodeId[1]; - return synth.id(); + env->ReleaseIntArrayElements(returnId, m_returnId, 0); + env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); + + return returnId; }; -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_lowPassPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat freq, jfloat res){ +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_lowPassPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat freq){ jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + jintArray returnId = env->NewIntArray(2); + jint *m_returnId = env->GetIntArrayElements(returnId, NULL); Methcla::AudioBusId in_bus = m_engine->audioBusId().alloc(); Methcla::AudioBusId out_bus = m_engine->audioBusId().alloc(); @@ -862,7 +958,7 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_lowPassPlay(JNIEnv auto synth = request.synth( METHCLA_PLUGINS_LPF_URI, Methcla::NodePlacement::after(m_nodeId[0]), - {freq, res}, + {freq}, {} ); @@ -876,14 +972,20 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_lowPassPlay(JNIEnv request.closeBundle(); request.send(); - env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); + m_returnId[0]=synth.id(); + m_returnId[1]=m_nodeId[1]; - return synth.id(); + env->ReleaseIntArrayElements(returnId, m_returnId, 0); + env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); + + return returnId; }; -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_bandPassPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat freq, jfloat res){ +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_bandPassPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat freq, jfloat bw){ jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + jintArray returnId = env->NewIntArray(2); + jint *m_returnId = env->GetIntArrayElements(returnId, NULL); Methcla::AudioBusId in_bus = m_engine->audioBusId().alloc(); Methcla::AudioBusId out_bus = m_engine->audioBusId().alloc(); @@ -891,9 +993,9 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_bandPassPlay(JNIEn Methcla::Request request(engine()); request.openBundle(Methcla::immediately); auto synth = request.synth( - METHCLA_PLUGINS_HPF_URI, + METHCLA_PLUGINS_BPF_URI, Methcla::NodePlacement::after(m_nodeId[0]), - {freq, res}, + {freq, bw}, {} ); @@ -907,30 +1009,46 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_bandPassPlay(JNIEn request.closeBundle(); request.send(); + m_returnId[0]=synth.id(); + m_returnId[1]=m_nodeId[1]; + + env->ReleaseIntArrayElements(returnId, m_returnId, 0); env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); - return synth.id(); + return returnId; }; -JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_filterSet(JNIEnv *env, jobject object, jfloat freq, jfloat res, jint nodeId){ +JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_filterSet(JNIEnv *env, jobject object, jfloat freq, jint nodeId){ Methcla::Request request(engine()); request.openBundle(Methcla::immediately); request.set(nodeId, 0, freq); - request.set(nodeId, 1, res); request.closeBundle(); request.send(); }; -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_delayPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat maxDelayTime, jfloat delayTime, jfloat feedBack){ +JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_filterBwSet(JNIEnv *env, jobject object, jfloat freq, jfloat bw, jint nodeId){ + + Methcla::Request request(engine()); + request.openBundle(Methcla::immediately); + request.set(nodeId, 0, freq); + request.set(nodeId, 1, bw); + request.closeBundle(); + request.send(); +}; + +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_delayPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat maxDelayTime, jfloat delayTime, jfloat feedBack){ - jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + jintArray returnId = env->NewIntArray(2); + jint *m_returnId = env->GetIntArrayElements(returnId, NULL); Methcla::AudioBusId in_bus = m_engine->audioBusId().alloc(); Methcla::AudioBusId out_bus = m_engine->audioBusId().alloc(); Methcla::Request request(engine()); request.openBundle(Methcla::immediately); + auto synth = request.synth( METHCLA_PLUGINS_DELAY_URI, Methcla::NodePlacement::after(m_nodeId[0]), @@ -947,13 +1065,16 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_delayPlay(JNIEnv * request.closeBundle(); request.send(); - + + m_returnId[0]=synth.id(); + m_returnId[1]=m_nodeId[1]; + + env->ReleaseIntArrayElements(returnId, m_returnId, 0); env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); - return synth.id(); + return returnId; }; - JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_delaySet(JNIEnv *env, jobject object, jfloat delayTime, jfloat feedBack, jint nodeId){ Methcla::Request request(engine()); request.openBundle(Methcla::immediately); @@ -963,9 +1084,11 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_delaySet(JNIEnv *e request.send(); }; -JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_reverbPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat room, jfloat damp, jfloat wet){ +JNIEXPORT jintArray JNICALL Java_processing_sound_MethClaInterface_reverbPlay(JNIEnv *env, jobject object, jintArray nodeId, jfloat room, jfloat damp, jfloat wet){ jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + jintArray returnId = env->NewIntArray(2); + jint *m_returnId = env->GetIntArrayElements(returnId, NULL); Methcla::AudioBusId in_bus = m_engine->audioBusId().alloc(); Methcla::AudioBusId out_bus = m_engine->audioBusId().alloc(); @@ -991,9 +1114,13 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_reverbPlay(JNIEnv request.closeBundle(); request.send(); + m_returnId[0]=synth.id(); + m_returnId[1]=m_nodeId[1]; + + env->ReleaseIntArrayElements(returnId, m_returnId, 0); env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); - return synth.id(); + return returnId; }; JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_reverbSet(JNIEnv *env, jobject object, jfloat room, jfloat damp, jfloat wet, jint nodeId){ @@ -1021,7 +1148,7 @@ JNIEXPORT jlong JNICALL Java_processing_sound_MethClaInterface_amplitude(JNIEnv Methcla::Request request(engine()); - ServerValue *amp_ptr = (ServerValue *) malloc(sizeof(ServerValue)); + ServerValue * amp_ptr = new ServerValue; ptr = (jlong)amp_ptr; @@ -1046,8 +1173,8 @@ JNIEXPORT jlong JNICALL Java_processing_sound_MethClaInterface_amplitude(JNIEnv auto id = engine().addNotificationHandler([amp_ptr](const OSCPP::Server::Message& msg) { if (msg == "/amplitude") { OSCPP::Server::ArgStream args(msg.args()); - while (!args.atEnd()) { - + std::lock_guard guard(mutex_amp_in); + while (!args.atEnd()) { amp_ptr->amp = args.float32(); } return false; @@ -1062,9 +1189,8 @@ JNIEXPORT jlong JNICALL Java_processing_sound_MethClaInterface_amplitude(JNIEnv }; JNIEXPORT jfloat JNICALL Java_processing_sound_MethClaInterface_poll_1amplitude(JNIEnv * env, jobject object, jlong ptr){ - ServerValue *amp_ptr = (ServerValue*)ptr; - + std::lock_guard guard(mutex_amp_out); return amp_ptr->amp; }; @@ -1072,20 +1198,18 @@ JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_destroy_1amplitude ServerValue *amp_ptr = (ServerValue*)ptr; engine().removeNotificationHandler(amp_ptr->id); - free(amp_ptr); - + delete amp_ptr; }; JNIEXPORT jlong JNICALL Java_processing_sound_MethClaInterface_fft(JNIEnv *env, jobject object, jintArray nodeId, jint fftSize){ jlong ptr; jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); - ServerArray *fft_ptr = (ServerArray *) malloc(sizeof(ServerArray) + fftSize*(sizeof(std::vector))); - - std::cout << "1" << std::endl; + //ServerArray *fft_ptr = (ServerArray *) malloc(sizeof(ServerArray)); - fft_ptr->fft.resize(fftSize); - std::cout << "2" << std::endl; + ServerArray * fft_ptr = new ServerArray; + + fft_ptr->fft.resize(fftSize, 0); fft_ptr->fftSize=fftSize; ptr = (jlong)fft_ptr; @@ -1098,6 +1222,8 @@ JNIEXPORT jlong JNICALL Java_processing_sound_MethClaInterface_fft(JNIEnv *env, Methcla::Request request(engine()); request.openBundle(Methcla::immediately); + std::cout << fftSize << std::endl; + auto synth = request.synth( METHCLA_PLUGINS_FFT_URI, Methcla::NodePlacement::after(m_nodeId[0]), @@ -1118,12 +1244,14 @@ JNIEXPORT jlong JNICALL Java_processing_sound_MethClaInterface_fft(JNIEnv *env, if (msg == "/fft") { OSCPP::Server::ArgStream args(msg.args()); int i=0; - while (!args.atEnd()) { - fft_ptr->fft[i] = args.float32(); - std::lock_guard guard(mutex); - i++; - } - return false; + { + std::lock_guard guard(mutex_fft_in); + while (!args.atEnd()) { + fft_ptr->fft[i] = args.float32(); + i++; + } + } + return false; } return false; }); @@ -1138,12 +1266,10 @@ JNIEXPORT jlong JNICALL Java_processing_sound_MethClaInterface_fft(JNIEnv *env, JNIEXPORT jfloatArray JNICALL Java_processing_sound_MethClaInterface_poll_1fft(JNIEnv *env, jobject object, jlong ptr){ ServerArray *fft_ptr = (ServerArray*)ptr; - jfloatArray fft_mag = env->NewFloatArray(fft_ptr->fftSize); - - jfloat *m_fft_mag = env->GetFloatArrayElements(fft_mag, NULL); + std::lock_guard guard(mutex_fft_out); for (int i = 0; i < fft_ptr->fftSize; ++i) { m_fft_mag[i]=fft_ptr->fft[i]; @@ -1155,9 +1281,9 @@ JNIEXPORT jfloatArray JNICALL Java_processing_sound_MethClaInterface_poll_1fft(J }; JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_destroy_1fft(JNIEnv *env, jobject object, jlong ptr){ - ServerArray *fft_ptr = (ServerArray*)ptr; + ServerArray * fft_ptr = (ServerArray*)ptr; engine().removeNotificationHandler(fft_ptr->id); - free(fft_ptr); + delete fft_ptr; }; /* OLD VARIABLE IN OUT FUNCTION @@ -1187,3 +1313,18 @@ JNIEXPORT jint JNICALL Java_processing_sound_MethClaInterface_out(JNIEnv *env, j }; */ +JNIEXPORT void JNICALL Java_processing_sound_MethClaInterface_out(JNIEnv *env, jobject object, jint out, jintArray nodeId){ + + jint* m_nodeId = env->GetIntArrayElements(nodeId, 0); + + Methcla::Request request(engine()); + request.openBundle(Methcla::immediately); + + request.mapOutput(m_nodeId[0], 0, Methcla::AudioBusId(out), Methcla::kBusMappingExternal); + + request.closeBundle(); + request.send(); + + env->ReleaseIntArrayElements(nodeId, m_nodeId, 0); +}; + diff --git a/java/libraries/sound/src/processing/sound/AudioIn.java b/java/libraries/sound/src/processing/sound/AudioIn.java index 382d4de3d..42f572972 100644 --- a/java/libraries/sound/src/processing/sound/AudioIn.java +++ b/java/libraries/sound/src/processing/sound/AudioIn.java @@ -2,25 +2,26 @@ package processing.sound; import processing.core.PApplet; -public class AudioIn { +public class AudioIn implements SoundObject{ PApplet parent; private Engine m_engine; private int[] m_nodeId = {-1,-1}; private float m_amp = 1.f; private float m_add = 0; - private boolean m_out = true; + private int m_in = 0; private float m_pos = 0; - public AudioIn(PApplet theParent) { + public AudioIn (PApplet theParent, int in) { this.parent = theParent; parent.registerMethod("dispose", this); m_engine.setPreferences(theParent, 512, 44100); m_engine.start(); + m_in = in; } public void play(){ - m_nodeId = m_engine.audioInPlay(m_amp, m_add, m_pos, m_out); + m_nodeId = m_engine.audioInPlay(m_amp, m_add, m_pos, m_in); } public void play(float amp, float add, float pos){ diff --git a/java/libraries/sound/src/processing/sound/BandPass.java b/java/libraries/sound/src/processing/sound/BandPass.java index 61476d494..91d173f47 100644 --- a/java/libraries/sound/src/processing/sound/BandPass.java +++ b/java/libraries/sound/src/processing/sound/BandPass.java @@ -6,10 +6,9 @@ public class BandPass implements SoundObject{ PApplet parent; private Engine m_engine; - private int m_nodeId; - private int[] m_m = {0,0}; - private float m_freq = 100; - private float m_res = 1; + private int[] m_nodeId = {-1,-1}; + private float m_freq = 4000; + private float m_bw = 1000; public BandPass(PApplet theParent) { this.parent = theParent; @@ -18,22 +17,26 @@ public class BandPass implements SoundObject{ m_engine.start(); } - public void process(SoundObject input, float freq, float res){ - m_freq=freq; m_res=res; - m_nodeId = m_engine.bandPassPlay(input.returnId(), m_freq, m_res); + public void process(SoundObject input, float freq, float bw){ + m_freq=freq; m_bw=bw; + m_nodeId = m_engine.bandPassPlay(input.returnId(), m_freq, m_bw); } public void process(SoundObject input, float freq){ m_freq=freq; - m_nodeId = m_engine.bandPassPlay(input.returnId(), m_freq, m_res); + m_nodeId = m_engine.bandPassPlay(input.returnId(), m_freq, m_bw); } + public void process(SoundObject input){ + m_nodeId = m_engine.bandPassPlay(input.returnId(), m_freq, m_bw); + } + private void set(){ - m_engine.filterSet(m_freq, m_res, m_nodeId); + m_engine.filterBwSet(m_freq, m_bw, m_nodeId[0]); } - public void set(float freq, float res){ - m_freq=freq; m_res=res; + public void set(float freq, float bw){ + m_freq=freq; m_bw=bw; this.set(); } @@ -42,20 +45,20 @@ public class BandPass implements SoundObject{ this.set(); } - public void res(float res){ - m_res=res; + public void bw(float bw){ + m_bw=bw; this.set(); } public int[] returnId(){ - return m_m; + return m_nodeId; } public void stop(){ - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } public void dispose() { - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } } diff --git a/java/libraries/sound/src/processing/sound/BrownNoise.java b/java/libraries/sound/src/processing/sound/BrownNoise.java index 2dfdf6576..74bbd80df 100644 --- a/java/libraries/sound/src/processing/sound/BrownNoise.java +++ b/java/libraries/sound/src/processing/sound/BrownNoise.java @@ -1,7 +1,7 @@ package processing.sound; import processing.core.*; -public class BrownNoise implements SoundObject{ +public class BrownNoise implements Noise{ PApplet parent; private Engine m_engine; diff --git a/java/libraries/sound/src/processing/sound/Delay.java b/java/libraries/sound/src/processing/sound/Delay.java index f2540f9a6..262105a8f 100644 --- a/java/libraries/sound/src/processing/sound/Delay.java +++ b/java/libraries/sound/src/processing/sound/Delay.java @@ -6,8 +6,7 @@ public class Delay implements SoundObject{ PApplet parent; private Engine m_engine; - private int m_nodeId; - private int[] m_m = {0,0}; + private int m_nodeId[] = {-1,-1}; private float m_maxDelayTime = 2; private float m_delayTime = 0; private float m_feedBack = 0; @@ -35,7 +34,7 @@ public class Delay implements SoundObject{ } private void set(){ - m_engine.delaySet(m_delayTime, m_feedBack, m_nodeId); + m_engine.delaySet(m_delayTime, m_feedBack, m_nodeId[0]); } public void set(float delayTime, float feedBack){ @@ -54,14 +53,14 @@ public class Delay implements SoundObject{ } public int[] returnId(){ - return m_m; + return m_nodeId; } public void stop(){ - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } public void dispose() { - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } } diff --git a/java/libraries/sound/src/processing/sound/Engine.java b/java/libraries/sound/src/processing/sound/Engine.java index 1612d6b71..51a04a40f 100644 --- a/java/libraries/sound/src/processing/sound/Engine.java +++ b/java/libraries/sound/src/processing/sound/Engine.java @@ -62,6 +62,10 @@ public class Engine { public static void oscSet(float freq, float amp, float add, float pos, int[] nodeId){ methCla.oscSet(freq, amp, add, pos, nodeId); }; + + public static void oscAudioSet(int[] freqId, int[] ampId, int[] addId, int[] posId, int[] nodeId){ + methCla.oscAudioSet(freqId, ampId, addId, posId, nodeId); + }; // Sine Wave Oscillator @@ -101,8 +105,8 @@ public class Engine { // AudioIn - public static int[] audioInPlay(float amp, float add, float pos, boolean out){ - return methCla.audioInPlay(amp, add, pos, out); + public static int[] audioInPlay(float amp, float add, float pos, int in){ + return methCla.audioInPlay(amp, add, pos, in); }; public static void audioInSet(float amp, float add, float pos, int[] nodeId){ @@ -163,7 +167,7 @@ public class Engine { // Envelope - public static int envelopePlay(int[] input, float attackTime, float sustainTime, float sustainLevel, float releaseTime){ + public static int[] envelopePlay(int[] input, float attackTime, float sustainTime, float sustainLevel, float releaseTime){ return methCla.envelopePlay(input, attackTime, sustainTime, sustainLevel, releaseTime); }; @@ -173,25 +177,29 @@ public class Engine { // Filters - public static int highPassPlay(int[] input, float freq, float res){ - return methCla.highPassPlay(input, freq, res); + public static int[] highPassPlay(int[] input, float freq){ + return methCla.highPassPlay(input, freq); }; - public static int lowPassPlay(int[] input, float freq, float res){ - return methCla.lowPassPlay(input, freq, res); + public static int[] lowPassPlay(int[] input, float freq){ + return methCla.lowPassPlay(input, freq); }; - public static int bandPassPlay(int[] input, float freq, float res){ - return methCla.bandPassPlay(input, freq, res); + public static int[] bandPassPlay(int[] input, float freq, float bw){ + return methCla.bandPassPlay(input, freq, bw); }; - public static void filterSet(float freq, float res, int nodeId){ - methCla.filterSet(freq, res, nodeId); + public static void filterSet(float freq, int nodeId){ + methCla.filterSet(freq, nodeId); + }; + + public static void filterBwSet(float freq, float bw, int nodeId){ + methCla.filterBwSet(freq, bw, nodeId); }; // Delay - public static int delayPlay(int[] input, float maxDelayTime, float delayTime, float feedBack){ + public static int[] delayPlay(int[] input, float maxDelayTime, float delayTime, float feedBack){ return methCla.delayPlay(input, maxDelayTime, delayTime, feedBack); }; @@ -201,7 +209,7 @@ public class Engine { // Reverb - public static int reverbPlay(int[] input, float room, float damp, float wet){ + public static int[] reverbPlay(int[] input, float room, float damp, float wet){ return methCla.reverbPlay(input, room, damp, wet); }; @@ -237,6 +245,13 @@ public class Engine { methCla.destroy_fft(ptr); }; + // Out + + public static void out(int out, int[] nodeId){ + methCla.out(out, nodeId); + }; + + public static void engineStop() { methCla.engineStop(); } diff --git a/java/libraries/sound/src/processing/sound/Env.java b/java/libraries/sound/src/processing/sound/Env.java index 9ff122a5e..499f9ccdc 100644 --- a/java/libraries/sound/src/processing/sound/Env.java +++ b/java/libraries/sound/src/processing/sound/Env.java @@ -5,7 +5,7 @@ public class Env { PApplet parent; private Engine m_engine; - int m_nodeId; + int[] m_nodeId = {-1, -1}; public Env (PApplet theParent) { this.parent = theParent; @@ -18,11 +18,11 @@ public class Env { m_nodeId = m_engine.envelopePlay(input.returnId(), attackTime, sustainTime, sustainLevel, releaseTime); } - public int returnId(){ + public int[] returnId(){ return m_nodeId; } public void dispose(){ - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } }; diff --git a/java/libraries/sound/src/processing/sound/HighPass.java b/java/libraries/sound/src/processing/sound/HighPass.java index 4cf7c5550..01e23f120 100644 --- a/java/libraries/sound/src/processing/sound/HighPass.java +++ b/java/libraries/sound/src/processing/sound/HighPass.java @@ -6,10 +6,8 @@ public class HighPass implements SoundObject{ PApplet parent; private Engine m_engine; - private int m_nodeId; - private int[] m_m = {0,0}; + private int[] m_nodeId = {-1,-1}; private float m_freq = 100; - private float m_res = 1; public HighPass(PApplet theParent) { this.parent = theParent; @@ -18,22 +16,21 @@ public class HighPass implements SoundObject{ m_engine.start(); } - public void process(SoundObject input, float freq, float res){ - m_freq=freq; m_res=res; - m_nodeId = m_engine.highPassPlay(input.returnId(), m_freq, m_res); - } - public void process(SoundObject input, float freq){ m_freq=freq; - m_nodeId = m_engine.highPassPlay(input.returnId(), m_freq, m_res); + m_nodeId = m_engine.highPassPlay(input.returnId(), m_freq); } + public void process(SoundObject input){ + m_nodeId = m_engine.highPassPlay(input.returnId(), m_freq); + } + private void set(){ - m_engine.filterSet(m_freq, m_res, m_nodeId); + m_engine.filterSet(m_freq, m_nodeId[0]); } - public void set(float freq, float res){ - m_freq=freq; m_res=res; + public void set(float freq){ + m_freq=freq; this.set(); } @@ -41,21 +38,16 @@ public class HighPass implements SoundObject{ m_freq=freq; this.set(); } - - public void res(float res){ - m_res=res; - this.set(); - } public int[] returnId(){ - return m_m; + return m_nodeId; } public void stop(){ - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } public void dispose() { - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } } diff --git a/java/libraries/sound/src/processing/sound/LowPass.java b/java/libraries/sound/src/processing/sound/LowPass.java index e16d898f2..5f2a17a3d 100644 --- a/java/libraries/sound/src/processing/sound/LowPass.java +++ b/java/libraries/sound/src/processing/sound/LowPass.java @@ -6,10 +6,8 @@ public class LowPass implements SoundObject{ PApplet parent; private Engine m_engine; - private int m_nodeId; - private int[] m_m = {0,0}; + private int[] m_nodeId = {-1, -1}; private float m_freq = 100; - private float m_res = 1; public LowPass(PApplet theParent) { this.parent = theParent; @@ -18,22 +16,21 @@ public class LowPass implements SoundObject{ m_engine.start(); } - public void process(SoundObject input, float freq, float res){ - m_freq=freq; m_res=res; - m_nodeId = m_engine.lowPassPlay(input.returnId(), m_freq, m_res); - } - public void process(SoundObject input, float freq){ m_freq=freq; - m_nodeId = m_engine.lowPassPlay(input.returnId(), m_freq, m_res); + m_nodeId = m_engine.lowPassPlay(input.returnId(), m_freq); + } + + public void process(SoundObject input){ + m_nodeId = m_engine.lowPassPlay(input.returnId(), m_freq); } private void set(){ - m_engine.filterSet(m_freq, m_res, m_nodeId); + m_engine.filterSet(m_freq, m_nodeId[0]); } - public void set(float freq, float res){ - m_freq=freq; m_res=res; + public void set(float freq){ + m_freq=freq; this.set(); } @@ -42,20 +39,15 @@ public class LowPass implements SoundObject{ this.set(); } - public void res(float res){ - m_res=res; - this.set(); - } - public int[] returnId(){ - return m_m; + return m_nodeId; } public void stop(){ - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } public void dispose() { - //m_engine.synthStop(m_nodeId); + m_engine.synthStop(m_nodeId); } } diff --git a/java/libraries/sound/src/processing/sound/MethClaInterface.java b/java/libraries/sound/src/processing/sound/MethClaInterface.java index 35fafaf60..bb1a7d4c7 100644 --- a/java/libraries/sound/src/processing/sound/MethClaInterface.java +++ b/java/libraries/sound/src/processing/sound/MethClaInterface.java @@ -23,6 +23,8 @@ public class MethClaInterface // general Oscillator methods public native void oscSet(float freq, float amp, float add, float pos, int[] nodeId); + + public native void oscAudioSet(int[] freqId, int[] ampId, int[] addId, int[] posId, int[] nodeId); // Sine Wave Oscillator @@ -50,7 +52,7 @@ public class MethClaInterface // Audio In - public native int[] audioInPlay(float amp, float add, float pos, boolean out); + public native int[] audioInPlay(float amp, float add, float pos, int in); public native void audioInSet(float amp, float add, float pos, int[] nodeId); @@ -86,29 +88,32 @@ public class MethClaInterface // Envelope - public native int envelopePlay(int[] input, float attackTime, float sustainTime, float sustainLevel, float releaseTime); + public native int[] envelopePlay(int[] input, float attackTime, float sustainTime, float sustainLevel, float releaseTime); public native int doneAfter(float seconds); // Filters - public native int highPassPlay(int[] input, float freq, float res); + public native int[] highPassPlay(int[] input, float freq); - public native int lowPassPlay(int[] input, float freq, float res); + public native int[] lowPassPlay(int[] input, float freq); - public native int bandPassPlay(int[] input, float freq, float res); + public native int[] bandPassPlay(int[] input, float freq, float bw); + + public native void filterSet(float freq, int nodeId); + + public native void filterBwSet(float freq, float bw, int nodeId); - public native void filterSet(float freq, float res, int nodeId); // Delay - public native int delayPlay(int[] input, float maxDelayTime, float delayTime, float feedBack); + public native int[] delayPlay(int[] input, float maxDelayTime, float delayTime, float feedBack); public native void delaySet(float delayTime, float feedBack, int nodeId); // Reverb - public native int reverbPlay(int[] input, float room, float damp, float wet); + public native int[] reverbPlay(int[] input, float room, float damp, float wet); public native void reverbSet(float room, float damp, float wet, int nodeId); @@ -118,7 +123,7 @@ public class MethClaInterface // Pan + Out - // public native int out(float pos, int nodeId); + public native void out(int out, int[] nodeId); // connect diff --git a/java/libraries/sound/src/processing/sound/Mix.java b/java/libraries/sound/src/processing/sound/Mix.java new file mode 100644 index 000000000..1cc9e5a69 --- /dev/null +++ b/java/libraries/sound/src/processing/sound/Mix.java @@ -0,0 +1,42 @@ +package processing.sound; + +import processing.core.PApplet; + +public class Mix implements SoundObject{ + + PApplet parent; + private Engine m_engine; + private int m_nodeId[] = {-1,-1}; + private int[] m_nodeInIds; + private float[] m_amps; + + public Mix(PApplet theParent) { + this.parent = theParent; + parent.registerMethod("dispose", this); + m_engine.setPreferences(theParent, 512, 44100); + m_engine.start(); + } + + public void play(SoundObject[] input, float[] amps){ + m_amps=amps; + for (int i=0; i + diff --git a/pdex/build.xml b/pdex/build.xml index 21c545ebb..4cfc10aa0 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -1,149 +1,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + + + + + - - - - - - - - + + + + + - - - - + - - - - + + + + + - - - - - - - - + + + - - - - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pdex/src/com/illposed/osc/OSCBundle.java b/pdex/src/com/illposed/osc/OSCBundle.java index bce88824d..5ce38235e 100644 --- a/pdex/src/com/illposed/osc/OSCBundle.java +++ b/pdex/src/com/illposed/osc/OSCBundle.java @@ -155,13 +155,13 @@ public class OSCBundle extends OSCPacket { */ protected void computeTimeTagByteArray(OSCJavaToByteArrayConverter stream) { if ((null == timestamp) || (timestamp == TIMESTAMP_IMMEDIATE)) { - stream.write((int) 0); - stream.write((int) 1); + stream.write(0); + stream.write(1); return; } long millisecs = timestamp.getTime(); - long secsSince1970 = (long) (millisecs / 1000); + long secsSince1970 = millisecs / 1000; long secs = secsSince1970 + SECONDS_FROM_1900_TO_1970.longValue(); // this line was cribbed from jakarta commons-net's NTP TimeStamp code diff --git a/pdex/src/galsasson/mode/tweak/ColorSelector.java b/pdex/src/galsasson/mode/tweak/ColorSelector.java index ede620633..d2dbe82cb 100644 --- a/pdex/src/galsasson/mode/tweak/ColorSelector.java +++ b/pdex/src/galsasson/mode/tweak/ColorSelector.java @@ -2,14 +2,11 @@ package galsasson.mode.tweak; import java.awt.BorderLayout; import java.awt.Color; -import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; -import java.awt.FlowLayout; import javax.swing.Box; import javax.swing.JFrame; -import javax.swing.border.EmptyBorder; import processing.core.PApplet; import processing.core.PGraphics; diff --git a/pdex/src/galsasson/mode/tweak/HProgressBar.java b/pdex/src/galsasson/mode/tweak/HProgressBar.java index 9501163dc..f94e04974 100644 --- a/pdex/src/galsasson/mode/tweak/HProgressBar.java +++ b/pdex/src/galsasson/mode/tweak/HProgressBar.java @@ -1,6 +1,5 @@ package galsasson.mode.tweak; -import java.awt.Color; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.geom.AffineTransform; @@ -20,10 +19,10 @@ public class HProgressBar { setPos(0); - int xl[] = {0, 0, -(int)((float)size/1.5)}; + int xl[] = {0, 0, -(int)(size/1.5)}; int yl[] = {-(int)((float)size/3), (int)((float)size/3), 0}; leftPoly = new Polygon(xl, yl, 3); - int xr[] = {0, (int)((float)size/1.5), 0}; + int xr[] = {0, (int)(size/1.5), 0}; int yr[] = {-(int)((float)size/3), 0, (int)((float)size/3)}; rightPoly = new Polygon(xr, yr, 3); } diff --git a/pdex/src/galsasson/mode/tweak/Handle.java b/pdex/src/galsasson/mode/tweak/Handle.java index 73731a44d..3e9453a6c 100644 --- a/pdex/src/galsasson/mode/tweak/Handle.java +++ b/pdex/src/galsasson/mode/tweak/Handle.java @@ -1,11 +1,6 @@ package galsasson.mode.tweak; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.math.BigDecimal; import java.util.Comparator; @@ -176,7 +171,7 @@ public class Handle { private float getChange() { int pixels = xCurrent - xLast; - return (float)pixels*incValue; + return pixels*incValue; } public void setPos(int nx, int ny) diff --git a/pdex/src/galsasson/mode/tweak/SketchParser.java b/pdex/src/galsasson/mode/tweak/SketchParser.java index affa86e97..8c42f27e9 100644 --- a/pdex/src/galsasson/mode/tweak/SketchParser.java +++ b/pdex/src/galsasson/mode/tweak/SketchParser.java @@ -8,8 +8,6 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import processing.app.Sketch; - public class SketchParser { public ArrayList colorBoxes[]; diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index e568ff6ae..f68f8c2c1 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1008,28 +1008,23 @@ public class ASTGenerator { ASTNode childExpr = getChildExpression(testnode); log("Parent expression : " + getParentExpression(testnode)); log("Child expression : " + childExpr); - if (childExpr instanceof ASTNode) { - if (!noCompare) { - log("Original testnode " - + getNodeAsString(testnode)); - testnode = getParentExpression(testnode); - log("Corrected testnode " - + getNodeAsString(testnode)); - } - ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, - noCompare); - if (expr == null) { - log("Expr is null"); - } else { - log("Expr is " + expr.toString()); - candidates = getMembersForType(expr, childExpr.toString(), - noCompare, false); - } - } - else - { - log("ChildExpr is null"); + + if (!noCompare) { + log("Original testnode " + + getNodeAsString(testnode)); + testnode = getParentExpression(testnode); + log("Corrected testnode " + + getNodeAsString(testnode)); } + ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, + noCompare); + if (expr == null) { + log("Expr is null"); + } else { + log("Expr is " + expr.toString()); + candidates = getMembersForType(expr, childExpr.toString(), + noCompare, false); + } } showPredictions(word); @@ -1263,8 +1258,10 @@ public class ASTGenerator { Class tehClass = null; // First, see if the classname is a fully qualified name and loads straightaway tehClass = loadClass(className); - if(tehClass instanceof Class){ - log(tehClass.getName() + " located straightaway"); + + // do you mean to check for 'null' here? otherwise, this expression is always true [fry] + if (tehClass instanceof Class) { + //log(tehClass.getName() + " located straightaway"); return tehClass; } @@ -1290,7 +1287,7 @@ public class ASTGenerator { return tehClass; } - log("Doesn't exist in package: " + impS.getImportName()); + //log("Doesn't exist in package: " + impS.getImportName()); } @@ -1301,7 +1298,7 @@ public class ASTGenerator { log(tehClass.getName() + " located."); return tehClass; } - log("Doesn't exist in package: " + impS); + //log("Doesn't exist in package: " + impS); } for (String impS : p.getDefaultImports()) { @@ -1311,7 +1308,7 @@ public class ASTGenerator { log(tehClass.getName() + " located."); return tehClass; } - log("Doesn't exist in package: " + impS); + // log("Doesn't exist in package: " + impS); } } @@ -1322,7 +1319,7 @@ public class ASTGenerator { log(tehClass.getName() + " located."); return tehClass; } - log("Doesn't exist in java.lang"); + //log("Doesn't exist in java.lang"); return tehClass; } @@ -1458,8 +1455,7 @@ public class ASTGenerator { .structuralPropertiesForType().iterator(); // logE("Props of " + node.getClass().getName()); while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); + StructuralPropertyDescriptor prop = it.next(); if (prop.isChildProperty() || prop.isSimpleProperty()) { if (node.getStructuralProperty(prop) != null) { @@ -1505,9 +1501,9 @@ public class ASTGenerator { } List nodes = null; if (parent instanceof TypeDeclaration) { - nodes = (List) ((TypeDeclaration) parent).bodyDeclarations(); + nodes = ((TypeDeclaration) parent).bodyDeclarations(); } else if (parent instanceof Block) { - nodes = (List) ((Block) parent).statements(); + nodes = ((Block) parent).statements(); } else { System.err.println("THIS CONDITION SHOULD NOT OCCUR - findClosestNode " + getNodeAsString(parent)); @@ -1618,8 +1614,8 @@ public class ASTGenerator { // Convert tab based pde line number to actual line number int pdeLineNumber = lineNumber + errorCheckerService.mainClassOffset; - log("----getASTNodeAt---- CU State: " - + errorCheckerService.compilationUnitState); +// log("----getASTNodeAt---- CU State: " +// + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); @@ -1634,11 +1630,11 @@ public class ASTGenerator { } // Find closest ASTNode to the linenumber - log("getASTNodeAt: Node line number " + pdeLineNumber); +// log("getASTNodeAt: Node line number " + pdeLineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, pdeLineNumber, offset, name); - log("Node text +> " + lineNode); +// log("Node text +> " + lineNode); ASTNode decl = null; String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to @@ -1649,14 +1645,14 @@ public class ASTGenerator { .getSketch().getCurrentCodeIndex(), lineNumber); String javaCodeLine = getJavaSourceCodeLine(pdeLineNumber); - log(lineNumber + " Original Line num.\nPDE :" + pdeCodeLine); - log("JAVA:" + javaCodeLine); - log("Clicked on: " + name + " start offset: " + offset); +// log(lineNumber + " Original Line num.\nPDE :" + pdeCodeLine); +// log("JAVA:" + javaCodeLine); +// log("Clicked on: " + name + " start offset: " + offset); // Calculate expected java offset based on the pde line OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine); int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length()) + lineNode.getStartPosition(); - log("JAVA ast offset: " + (javaOffset)); +// log("JAVA ast offset: " + (javaOffset)); // Find the corresponding node in the AST ASTNode simpName = dfsLookForASTNode(errorCheckerService.getLatestCU(), @@ -1683,22 +1679,22 @@ public class ASTGenerator { // SimpleName instance found, now find its declaration in code if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); - log(getNodeAsString(simpName)); + // log(getNodeAsString(simpName)); decl = findDeclaration((SimpleName) simpName); if (decl != null) { - logE("DECLA: " + decl.getClass().getName()); +// logE("DECLA: " + decl.getClass().getName()); nodeLabel = getLabelIfType(new ASTNodeWrapper(decl), (SimpleName) simpName); //retLabelString = getNodeAsString(decl); } else { - logE("null"); +// logE("null"); if (scrollOnly) { editor.statusMessage(simpName + " is not defined in this sketch", DebugEditor.STATUS_ERR); } } - log(getNodeAsString(decl)); +// log(getNodeAsString(decl)); /* // - findDecl3 testing @@ -1725,8 +1721,8 @@ public class ASTGenerator { * since it contains all the properties. */ ASTNode simpName2 = getNodeName(decl, nameOfNode); - logE("FINAL String decl: " + getNodeAsString(decl)); - logE("FINAL String label: " + getNodeAsString(simpName2)); +// logE("FINAL String decl: " + getNodeAsString(decl)); +// logE("FINAL String label: " + getNodeAsString(simpName2)); //errorCheckerService.highlightNode(simpName2); ASTNodeWrapper declWrap = new ASTNodeWrapper(simpName2, nodeLabel); //errorCheckerService.highlightNode(declWrap); @@ -2020,6 +2016,7 @@ public class ASTGenerator { pdeOffsets[i][2] = awrap.getPDECodeOffsetForSN(this); } + editor.startCompoundEdit(); for (int i = 0; i < defCU.getChildCount(); i++) { ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU .getChildAt(i))).getUserObject(); @@ -2043,6 +2040,7 @@ public class ASTGenerator { //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.INFORMATION_MESSAGE); editor.ta.setSelectedText(newName); } + editor.stopCompoundEdit(); errorCheckerService.resumeThread(); editor.getSketch().setModified(true); errorCheckerService.runManualErrorCheck(); @@ -2061,8 +2059,8 @@ public class ASTGenerator { */ public void highlightPDECode(int tab, int lineNumber, int lineStartWSOffset, int length) { - log("ASTGen.highlightPDECode: T " + tab + ",L: " + lineNumber + ",LSO: " - + lineStartWSOffset + ",Len: " + length); +// log("ASTGen.highlightPDECode: T " + tab + ",L: " + lineNumber + ",LSO: " +// + lineStartWSOffset + ",Len: " + length); editor.toFront(); editor.getSketch().setCurrentCode(tab); lineStartWSOffset += editor.ta.getLineStartOffset(lineNumber); @@ -2194,13 +2192,12 @@ public class ASTGenerator { * @param tnode */ public static void visitRecur(ASTNode node, DefaultMutableTreeNode tnode) { - Iterator it = node - .structuralPropertiesForType().iterator(); + Iterator it = + node.structuralPropertiesForType().iterator(); //logE("Props of " + node.getClass().getName()); DefaultMutableTreeNode ctnode = null; while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); + StructuralPropertyDescriptor prop = it.next(); if (prop.isChildProperty() || prop.isSimpleProperty()) { if (node.getStructuralProperty(prop) != null) { @@ -2264,19 +2261,18 @@ public class ASTGenerator { public ASTNode dfsLookForASTNode(ASTNode root, String name, int startOffset, int endOffset) { - log("dfsLookForASTNode() lookin for " + name + " Offsets: " + startOffset - + "," + endOffset); +// log("dfsLookForASTNode() lookin for " + name + " Offsets: " + startOffset +// + "," + endOffset); Stack stack = new Stack(); stack.push(root); while (!stack.isEmpty()) { ASTNode node = (ASTNode) stack.pop(); //log("Popped from stack: " + getNodeAsString(node)); - Iterator it = node - .structuralPropertiesForType().iterator(); + Iterator it = + node.structuralPropertiesForType().iterator(); while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); + StructuralPropertyDescriptor prop = it.next(); if (prop.isChildProperty() || prop.isSimpleProperty()) { if (node.getStructuralProperty(prop) instanceof ASTNode) { @@ -2285,10 +2281,10 @@ public class ASTGenerator { && (temp.getStartPosition() + temp.getLength()) >= endOffset) { if(temp instanceof SimpleName){ if(name.equals(temp.toString())){ - log("Found simplename: " + getNodeAsString(temp)); +// log("Found simplename: " + getNodeAsString(temp)); return temp; } - log("Bummer, didn't match"); +// log("Bummer, didn't match"); } else stack.push(temp); @@ -2303,13 +2299,13 @@ public class ASTGenerator { if (temp.getStartPosition() <= startOffset && (temp.getStartPosition() + temp.getLength()) >= endOffset) { stack.push(temp); - log("Pushed onto stack: " + getNodeAsString(temp)); +// log("Pushed onto stack: " + getNodeAsString(temp)); if(temp instanceof SimpleName){ if(name.equals(temp.toString())){ - log("Found simplename: " + getNodeAsString(temp)); +// log("Found simplename: " + getNodeAsString(temp)); return temp; } - log("Bummer, didn't match"); +// log("Bummer, didn't match"); } else stack.push(temp); @@ -2319,7 +2315,7 @@ public class ASTGenerator { } } } - log("dfsLookForASTNode() not found " + name); +// log("dfsLookForASTNode() not found " + name); return null; } @@ -2329,6 +2325,10 @@ public class ASTGenerator { sketchOutline.show(); } + protected void showTabOutline(){ + new TabOutline(errorCheckerService).show(); + } + public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ // Find the first node with this line number, return its offset - jOffset line = pdeLineNumToJavaLineNum(line); @@ -2457,8 +2457,7 @@ public class ASTGenerator { .structuralPropertiesForType().iterator(); //logE("Props of " + node.getClass().getName()); while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); + StructuralPropertyDescriptor prop = it.next(); if (prop.isChildProperty() || prop.isSimpleProperty()) { if (node.getStructuralProperty(prop) != null) { @@ -2490,7 +2489,7 @@ public class ASTGenerator { CompilationUnit root = (CompilationUnit) node.getRoot(); // log("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); if (root.getLineNumber(node.getStartPosition()) == lineNumber) { - logE(3 + getNodeAsString(node) + " len " + node.getLength()); + // logE(3 + getNodeAsString(node) + " len " + node.getLength()); return node; // if (offset < node.getLength()) // return node; @@ -2606,7 +2605,7 @@ public class ASTGenerator { // WARNING: You're entering the Rube Goldberg territory of Experimental Mode. // To debug this code, thou must take the Recursive Leap of Faith. - log("entering --findDeclaration1 -- " + findMe.toString()); + // log("entering --findDeclaration1 -- " + findMe.toString()); ASTNode declaringClass = null; ASTNode parent = findMe.getParent(); ASTNode ret = null; @@ -2622,8 +2621,8 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - log("MI EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); +// log("MI EXP: " + exp.toString() + " of type " +// + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) .getName())); @@ -2646,7 +2645,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration(stp.getName()); - log("MI.SN " + getNodeAsString(declaringClass)); +// log("MI.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, ((MethodInvocation) parent) .getName().toString(), constrains, declaringClass); @@ -2664,8 +2663,8 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - log("FA EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); +// log("FA EXP: " + exp.toString() + " of type " +// + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) .getName())); @@ -2689,7 +2688,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration(stp.getName()); - log("FA.SN " + getNodeAsString(declaringClass)); +// log("FA.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, fa.getName().toString(), constrains, declaringClass); @@ -2705,10 +2704,10 @@ public class ASTGenerator { if (!findMe.toString().equals(qn.getQualifier().toString())) { SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); - log(qn.getQualifier() + "->" + qn.getName()); +// log(qn.getQualifier() + "->" + qn.getName()); declaringClass = findDeclaration(stp.getName()); - log("QN decl class: " + getNodeAsString(declaringClass)); +// log("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); constrains.add(ASTNode.FIELD_DECLARATION); @@ -2718,16 +2717,16 @@ public class ASTGenerator { else{ if(findMe instanceof QualifiedName){ QualifiedName qnn = (QualifiedName) findMe; - log("findMe is a QN, " - + (qnn.getQualifier().toString() + " other " + qnn.getName() - .toString())); +// log("findMe is a QN, " +// + (qnn.getQualifier().toString() + " other " + qnn.getName() +// .toString())); SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); - log(qnn.getQualifier() + "->" + qnn.getName()); +// log(qnn.getQualifier() + "->" + qnn.getName()); declaringClass = findDeclaration(stp.getName()); - log("QN decl class: " - + getNodeAsString(declaringClass)); +// log("QN decl class: " +// + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); constrains.add(ASTNode.FIELD_DECLARATION); @@ -2760,7 +2759,7 @@ public class ASTGenerator { // .toString())); // } while (parent != null) { - log("findDeclaration1 -> " + getNodeAsString(parent)); +// log("findDeclaration1 -> " + getNodeAsString(parent)); for (Object oprop : parent.structuralPropertiesForType()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; if (prop.isChildProperty() || prop.isSimpleProperty()) { @@ -2812,8 +2811,8 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - log("MI EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); +// log("MI EXP: " + exp.toString() + " of type " +// + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) .getName(), @@ -2839,7 +2838,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration2(stp.getName(), alternateParent); - log("MI.SN " + getNodeAsString(declaringClass)); +// log("MI.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, ((MethodInvocation) parent) .getName().toString(), constrains, declaringClass); @@ -2858,8 +2857,8 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - log("FA EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); +// log("FA EXP: " + exp.toString() + " of type " +// + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) .getName(), @@ -2886,7 +2885,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration2(stp.getName(), alternateParent); - log("FA.SN " + getNodeAsString(declaringClass)); +// log("FA.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, fa.getName().toString(), constrains, declaringClass); @@ -2907,8 +2906,8 @@ public class ASTGenerator { if(stp == null) return null; declaringClass = findDeclaration2(stp.getName(), alternateParent); - log(qn.getQualifier() + "->" + qn.getName()); - log("QN decl class: " + getNodeAsString(declaringClass)); +// log(qn.getQualifier() + "->" + qn.getName()); +// log("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); constrains.add(ASTNode.FIELD_DECLARATION); @@ -2918,16 +2917,16 @@ public class ASTGenerator { else{ if(findMe instanceof QualifiedName){ QualifiedName qnn = (QualifiedName) findMe; - log("findMe is a QN, " - + (qnn.getQualifier().toString() + " other " + qnn.getName() - .toString())); +// log("findMe is a QN, " +// + (qnn.getQualifier().toString() + " other " + qnn.getName() +// .toString())); SimpleType stp = extracTypeInfo(findDeclaration2((qnn.getQualifier()), alternateParent)); - log(qnn.getQualifier() + "->" + qnn.getName()); +// log(qnn.getQualifier() + "->" + qnn.getName()); declaringClass = findDeclaration2(stp.getName(), alternateParent); - log("QN decl class: " - + getNodeAsString(declaringClass)); +// log("QN decl class: " +// + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); constrains.add(ASTNode.FIELD_DECLARATION); @@ -2945,7 +2944,7 @@ public class ASTGenerator { // constrains.add(ASTNode.FIELD_DECLARATION); } // TODO: in findDec, we also have a case where parent of type TD is handled. // Figure out if needed here as well. - log("Alternate parent: " + getNodeAsString(alternateParent)); +// log("Alternate parent: " + getNodeAsString(alternateParent)); while (alternateParent != null) { // log("findDeclaration2 -> " // + getNodeAsString(alternateParent)); @@ -2998,14 +2997,14 @@ public class ASTGenerator { - editor.textArea() .getLineStartNonWhiteSpaceOffset(editor.textArea().getCaretLine()); int x = pdeLine.indexOf("//"); - log(x + " , " + caretPos + ", Checking line for comment " + pdeLine); +// log(x + " , " + caretPos + ", Checking line for comment " + pdeLine); //lineStartOffset = editor.textArea(). if (x >= 0 && caretPos > x) { - log("INSIDE a comment"); +// log("INSIDE a comment"); return true; } - log("not within comment"); +// log("not within comment"); return false; } diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 9798f3e8f..62d84a3ca 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -43,7 +43,6 @@ import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.dom.VariableDeclarationFragment; /** * Wrapper class for ASTNode objects @@ -162,8 +161,7 @@ public class ASTNodeWrapper { .structuralPropertiesForType().iterator(); boolean flag = true; while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); + StructuralPropertyDescriptor prop = it.next(); if (prop.isChildListProperty()) { List nodelist = (List) thisNode .getStructuralProperty(prop); diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 7efa14ec0..f93b7aa17 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -18,17 +18,16 @@ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; + import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.Timer; -import java.util.TimerTask; import processing.app.Base; import processing.app.Sketch; -import static processing.mode.experimental.ExperimentalMode.log; - /** * Autosave utility for saving sketch backups in the background after * certain intervals @@ -42,7 +41,7 @@ public class AutoSaveUtil { private Timer timer; - private int saveTime; +// private int saveTime; private File autosaveDir, pastSave; @@ -334,6 +333,7 @@ public class AutoSaveUtil { * @author quarkninja * */ + /* private class SaveTask extends TimerTask{ @Override @@ -348,5 +348,6 @@ public class AutoSaveUtil { } } + */ } diff --git a/pdex/src/processing/mode/experimental/CompilationChecker.java b/pdex/src/processing/mode/experimental/CompilationChecker.java index 9b7e72a78..3e570bd41 100644 --- a/pdex/src/processing/mode/experimental/CompilationChecker.java +++ b/pdex/src/processing/mode/experimental/CompilationChecker.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-14 Martin Leopold and Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + package processing.mode.experimental; import java.io.BufferedReader; @@ -8,7 +26,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -42,6 +59,13 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.eclipse.jface.text.Document; +/** + * + * Provides compilation checking functionality + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ public class CompilationChecker { /** * ICompilationUnit implementation @@ -255,6 +279,7 @@ public class CompilationChecker { /** * ClassLoader implementation */ + /* private class CustomClassLoader extends ClassLoader { private Map classMap; @@ -276,6 +301,7 @@ public class CompilationChecker { return super.findClass(name); } }; + */ private ICompilationUnit generateCompilationUnit() { ASTParser parser = ASTParser.newParser(AST.JLS4); @@ -355,59 +381,6 @@ public class CompilationChecker { return null; } - private void compileAndRun(ICompilationUnit unit, boolean runIt) { - - Map settings = new HashMap(); - settings.put(CompilerOptions.OPTION_LineNumberAttribute, - CompilerOptions.GENERATE); - settings.put(CompilerOptions.OPTION_SourceFileAttribute, - CompilerOptions.GENERATE); - - CompilerOptions ops = new CompilerOptions(settings); - - CompileRequestorImpl requestor = new CompileRequestorImpl(); - Compiler compiler = new Compiler(new NameEnvironmentImpl(unit), - DefaultErrorHandlingPolicies - .proceedWithAllProblems(), ops, - requestor, - new DefaultProblemFactory(Locale - .getDefault())); - - compiler.compile(new ICompilationUnit[] { unit }); - // System.out.println(unit.getContents()); - List problems = requestor.getProblems(); - boolean error = false; - for (Iterator it = problems.iterator(); it.hasNext();) { - IProblem problem = (IProblem) it.next(); - StringBuffer buffer = new StringBuffer(); - buffer.append(problem.getMessage()); - buffer.append(" line: "); - buffer.append(problem.getSourceLineNumber()); - String msg = buffer.toString(); - if (problem.isError()) { - error = true; - msg = "Error:\n" + msg + " " + problem.toString(); - } else if (problem.isWarning()) - msg = "Warning:\n" + msg; - - System.out.println(msg); - } - - if (!error && runIt) { - try { - ClassLoader loader = new CustomClassLoader(getClass().getClassLoader(), - requestor.getResults()); - String className = CharOperation.toString(unit.getPackageName()) + "." - + new String(unit.getMainTypeName()); - Class clazz = loader.loadClass(className); - Method m = clazz.getMethod("main", new Class[] { String[].class }); - m.invoke(clazz, new Object[] { new String[0] }); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - private void compileMeQuitely(ICompilationUnit unit, Map compilerSettings) { Map settings; @@ -433,13 +406,13 @@ public class CompilationChecker { settings = compilerSettings; } - CompilerOptions cop = new CompilerOptions(); - cop.set(settings); +// CompilerOptions cop = new CompilerOptions(); +// cop.set(settings); CompileRequestorImpl requestor = new CompileRequestorImpl(); Compiler compiler = new Compiler(new NameEnvironmentImpl(unit), DefaultErrorHandlingPolicies .proceedWithAllProblems(), - settings, requestor, + new CompilerOptions(settings), requestor, new DefaultProblemFactory(Locale .getDefault())); compiler.compile(new ICompilationUnit[] { unit }); @@ -460,13 +433,13 @@ public class CompilationChecker { static private String[] getSimpleNames(String qualifiedName) { StringTokenizer st = new StringTokenizer(qualifiedName, "."); - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList(); while (st.hasMoreTokens()) { String name = st.nextToken().trim(); if (!name.equals("*")) list.add(name); } - return (String[]) list.toArray(new String[list.size()]); + return list.toArray(new String[0]); } public static void main(String[] args) { @@ -526,6 +499,14 @@ public class CompilationChecker { return prob; } + /** + * Performs compiler error check. + * @param sourceName - name of the class + * @param source - source code + * @param settings - compiler options + * @param classLoader - custom classloader which can load all dependencies + * @return IProblem[] - list of compiler errors and warnings + */ public IProblem[] getErrors(String sourceName, String source, Map settings, URLClassLoader classLoader) { fileName = sourceName; @@ -536,21 +517,6 @@ public class CompilationChecker { compileMeQuitely(generateCompilationUnit(), settings); // System.out.println("getErrors(), Done."); -// if (prob.length > 0) { -// Object[][] data = new Object[prob.length][10]; -// for (int i = 0; i < data.length; i++) { -// IProblem p = prob[i]; -// // data[i] = new -// // Object[]{p.getMessage(),p.getSourceLineNumber(),p.isError(),p}; -// data[i] = new Object[] { p.getOriginatingFileName(), -// p.getMessage(), p.getID(), p.getArguments(), 0, -// p.getSourceStart(), p.getSourceEnd(), -// p.getSourceLineNumber(), p.isError(), p.isWarning() }; -// -// } -// -// return data; -// } return prob; } diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index ef29d5963..cf7ad5c40 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -1,5 +1,4 @@ package processing.mode.experimental; -import static processing.mode.experimental.ExperimentalMode.log; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 00ee4e105..5c3da8b42 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -106,7 +106,7 @@ public class CompletionPanel { textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - log("Suggestion shown: " + System.currentTimeMillis()); + //log("Suggestion shown: " + System.currentTimeMillis()); } public boolean isVisible() { @@ -114,7 +114,7 @@ public class CompletionPanel { } public void setVisible(boolean v){ - log("Pred popup visible."); + //log("Pred popup visible."); popupMenu.setVisible(v); } @@ -243,7 +243,7 @@ public class CompletionPanel { textarea.setCaretPosition(insertionPosition + selectedSuggestion.length()); } - log("Suggestion inserted: " + System.currentTimeMillis()); + //log("Suggestion inserted: " + System.currentTimeMillis()); return true; } catch (BadLocationException e1) { e1.printStackTrace(); diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 8d1f83368..bc4c449ac 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -24,7 +24,6 @@ import galsasson.mode.tweak.SketchParser; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; -import java.awt.Component; import java.awt.Container; import java.awt.EventQueue; import java.awt.FlowLayout; @@ -42,8 +41,6 @@ import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -63,7 +60,6 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; -import javax.swing.border.Border; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; @@ -74,7 +70,6 @@ import processing.app.Base; import processing.app.EditorState; import processing.app.EditorToolbar; import processing.app.Mode; -import processing.app.Preferences; import processing.app.Sketch; import processing.app.SketchCode; import processing.app.Toolkit; @@ -182,7 +177,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { /** * Show outline view */ - protected JMenuItem showOutline; + protected JMenuItem showOutline, showTabOutline; /** * Enable/Disable error logging @@ -194,6 +189,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ protected JCheckBoxMenuItem completionsEnabled; + /** + * UNUSED. Disbaled for now. + */ protected AutoSaveUtil autosaver; public DebugEditor(Base base, String path, EditorState state, Mode mode) { @@ -388,7 +386,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); if(ip != null){ - sbuff.append(errorCheckerService.errorMsgSimplifier.getIDName(ip.getID())); + sbuff.append(ErrorMessageSimplifier.getIDName(ip.getID())); sbuff.append(','); sbuff.append("{"); for (int i = 0; i < ip.getArguments().length; i++) { @@ -568,22 +566,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { debugMenu.add(printThreads); debugMenu.addSeparator(); debugMenu.add(toggleVariableInspectorMenuItem); - debugMenu.addSeparator(); - - // TweakMode code - enableTweakCB = new JCheckBoxMenuItem("Tweak Enabled"); - enableTweakCB.setSelected(ExperimentalMode.enableTweak); - enableTweakCB.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - ExperimentalMode.enableTweak = ((JCheckBoxMenuItem) e - .getSource()).isSelected(); - dmode.savePreferences(); - } - }); - debugMenu.add(enableTweakCB); - // TweakMode code end + // debugMenu.addSeparator(); // XQMode menu items /* @@ -680,10 +663,15 @@ public class DebugEditor extends JavaEditor implements ActionListener { }); debugMenu.add(jitem); */ - showOutline = Toolkit.newJMenuItem("Show Outline", KeyEvent.VK_L); + showOutline = Toolkit.newJMenuItem("Show Sketch Outline", KeyEvent.VK_L); showOutline.addActionListener(this); debugMenu.add(showOutline); + showTabOutline = Toolkit.newJMenuItem("Show Tabs List", KeyEvent.VK_Y); + showTabOutline.addActionListener(this); + debugMenu.add(showTabOutline); + + return debugMenu; } @@ -691,6 +679,45 @@ public class DebugEditor extends JavaEditor implements ActionListener { public JMenu buildModeMenu() { return buildDebugMenu(); } + + public JMenu buildSketchMenu() { + JMenuItem runItem = Toolkit.newJMenuItem(DebugToolbar + .getTitle(DebugToolbar.RUN, false), 'R'); + runItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleRun(); + } + }); + + JMenuItem presentItem = Toolkit.newJMenuItemShift(DebugToolbar + .getTitle(DebugToolbar.RUN, true), 'R'); + presentItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handlePresent(); + } + }); + + JMenuItem stopItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.STOP, + false)); + stopItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleStop(); + } + }); + + JMenuItem enableTweak = Toolkit.newJMenuItemShift("Tweak", 'T'); + enableTweak.setSelected(ExperimentalMode.enableTweak); + enableTweak.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ExperimentalMode.enableTweak = true; + handleRun(); + } + }); + + return buildSketchMenu(new JMenuItem[] { + runItem, presentItem, enableTweak, stopItem }); + } /** * Callback for menu items. Implementation of Swing ActionListener. @@ -748,9 +775,13 @@ public class DebugEditor extends JavaEditor implements ActionListener { Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item"); toggleVariableInspector(); } else if (source.equals(showOutline)){ - log("Show Outline :D"); + log("Show Sketch Outline:"); errorCheckerService.getASTGenerator().showSketchOutline(); } + else if (source.equals(showTabOutline)){ + log("Show Tab Outline:"); + errorCheckerService.getASTGenerator().showTabOutline(); + } } // @Override @@ -779,7 +810,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ @Override protected boolean handleOpenInternal(String path) { - log("handleOpenInternal, path: " + path); + // log("handleOpenInternal, path: " + path); boolean didOpen = super.handleOpenInternal(path); if (didOpen && dbg != null) { // should already been stopped (open calls handleStop) @@ -788,10 +819,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { variableInspector().reset(); // clear contents of variable inspector } //if(didOpen){ - autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); // this is used instead of loadAutosaver(), temp measure - //loadAutoSaver(); - viewingAutosaveBackup = autosaver.isAutoSaveBackup(); - log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); + // autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); // this is used instead of loadAutosaver(), temp measure + // loadAutoSaver(); + // viewingAutosaveBackup = autosaver.isAutoSaveBackup(); + // log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); //} return didOpen; } @@ -1683,12 +1714,85 @@ public class DebugEditor extends JavaEditor implements ActionListener { errorCheckerService.runManualErrorCheck(); } } + + /** + * Handles toggle comment. Slightly improved from the default implementation + * in {@link processing.app.Editor} + */ + protected void handleCommentUncomment() { + // log("Entering handleCommentUncomment()"); + startCompoundEdit(); + + String prefix = getCommentPrefix(); + int prefixLen = prefix.length(); + + int startLine = textarea.getSelectionStartLine(); + int stopLine = textarea.getSelectionStopLine(); + + int lastLineStart = textarea.getLineStartOffset(stopLine); + int selectionStop = textarea.getSelectionStop(); + // If the selection ends at the beginning of the last line, + // then don't (un)comment that line. + if (selectionStop == lastLineStart) { + // Though if there's no selection, don't do that + if (textarea.isSelectionActive()) { + stopLine--; + } + } + + // If the text is empty, ignore the user. + // Also ensure that all lines are commented (not just the first) + // when determining whether to comment or uncomment. + boolean commented = true; + for (int i = startLine; commented && (i <= stopLine); i++) { + String lineText = textarea.getLineText(i).trim(); + if (lineText.length() == 0) + continue; //ignore blank lines + commented = lineText.startsWith(prefix); + } + + // log("Commented: " + commented); + + // This is the line start offset of the first line, which is added to + // all other lines while adding a comment. Required when commenting + // lines which have uneven whitespaces in the beginning. Makes the + // commented lines look more uniform. + int lso = Math.abs(textarea.getLineStartNonWhiteSpaceOffset(startLine) + - textarea.getLineStartOffset(startLine)); + + for (int line = startLine; line <= stopLine; line++) { + int location = textarea.getLineStartNonWhiteSpaceOffset(line); + String lineText = textarea.getLineText(line); + if (lineText.trim().length() == 0) + continue; //ignore blank lines + if (commented) { + // remove a comment + if (lineText.trim().startsWith(prefix + " ")) { + textarea.select(location, location + prefixLen + 1); + } else { + textarea.select(location, location + prefixLen); + } + textarea.setSelectedText(""); + } else { + // add a comment + location = textarea.getLineStartOffset(line) + lso; + textarea.select(location, location); + textarea.setSelectedText(prefix + " "); //Add a '// ' + } + } + // Subtract one from the end, otherwise selects past the current line. + // (Which causes subsequent calls to keep expanding the selection) + textarea.select(textarea.getLineStartOffset(startLine), + textarea.getLineStopOffset(stopLine) - 1); + stopCompoundEdit(); + sketch.setModified(true); + } // TweakMode code /** * Show warnings menu item */ - protected JCheckBoxMenuItem enableTweakCB; + //protected JCheckBoxMenuItem enableTweakCB; String[] baseCode; diff --git a/pdex/src/processing/mode/experimental/DebugToolbar.java b/pdex/src/processing/mode/experimental/DebugToolbar.java index c9616e179..b13d83f45 100755 --- a/pdex/src/processing/mode/experimental/DebugToolbar.java +++ b/pdex/src/processing/mode/experimental/DebugToolbar.java @@ -23,9 +23,9 @@ import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.logging.Level; import java.util.logging.Logger; + import processing.app.Base; import processing.app.Editor; -import processing.app.Preferences; import processing.app.Toolkit; import processing.mode.java.JavaToolbar; diff --git a/pdex/src/processing/mode/experimental/Debugger.java b/pdex/src/processing/mode/experimental/Debugger.java index 50b5d9846..916745268 100755 --- a/pdex/src/processing/mode/experimental/Debugger.java +++ b/pdex/src/processing/mode/experimental/Debugger.java @@ -960,7 +960,7 @@ public class Debugger implements VMEventListener { */ protected List getLocals(ThreadReference t, int depth) { //System.out.println("getting locals"); - List vars = new ArrayList(); + List vars = new ArrayList(); try { if (t.frameCount() > 0) { StackFrame sf = t.frame(0); @@ -1016,7 +1016,7 @@ public class Debugger implements VMEventListener { */ protected List getFields(Value value, int depth, int maxDepth, boolean includeInherited) { // remember: Value <- ObjectReference, ArrayReference - List vars = new ArrayList(); + List vars = new ArrayList(); if (depth <= maxDepth) { if (value instanceof ArrayReference) { return getArrayFields((ArrayReference) value); @@ -1057,7 +1057,7 @@ public class Debugger implements VMEventListener { * @return list of array fields */ protected List getArrayFields(ArrayReference array) { - List fields = new ArrayList(); + List fields = new ArrayList(); if (array != null) { String arrayType = array.type().name(); if (arrayType.endsWith("[]")) { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index dbaba3d94..a68a2ebe8 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -20,11 +20,7 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.logE; -import java.awt.EventQueue; import java.io.File; -import java.io.FileFilter; -import java.lang.reflect.Method; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -50,7 +46,6 @@ import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Base; import processing.app.Editor; @@ -360,6 +355,9 @@ public class ErrorCheckerService implements Runnable{ protected void updateSketchCodeListeners() { for (final SketchCode sc : editor.getSketch().getCode()) { boolean flag = false; + if (sc.getDocument() == null + || ((SyntaxDocument) sc.getDocument()).getDocumentListeners() == null) + continue; for (DocumentListener dl : ((SyntaxDocument)sc.getDocument()).getDocumentListeners()) { if(dl.equals(sketchChangedListener)){ flag = true; @@ -367,7 +365,7 @@ public class ErrorCheckerService implements Runnable{ } } if(!flag){ - log("Adding doc listener to " + sc.getPrettyName()); + // log("Adding doc listener to " + sc.getPrettyName()); sc.getDocument().addDocumentListener(sketchChangedListener); } } @@ -404,7 +402,7 @@ public class ErrorCheckerService implements Runnable{ * Triggers error check */ public void runManualErrorCheck() { - log("Error Check."); + // log("Error Check."); textModified.incrementAndGet(); } @@ -418,7 +416,7 @@ public class ErrorCheckerService implements Runnable{ public void insertUpdate(DocumentEvent e) { if (ExperimentalMode.errorCheckEnabled){ runManualErrorCheck(); - log("doc insert update, man error check.."); + //log("doc insert update, man error check.."); } } @@ -426,7 +424,7 @@ public class ErrorCheckerService implements Runnable{ public void removeUpdate(DocumentEvent e) { if (ExperimentalMode.errorCheckEnabled){ runManualErrorCheck(); - log("doc remove update, man error check.."); + //log("doc remove update, man error check.."); } } @@ -434,7 +432,7 @@ public class ErrorCheckerService implements Runnable{ public void changedUpdate(DocumentEvent e) { if (ExperimentalMode.errorCheckEnabled){ runManualErrorCheck(); - log("doc changed update, man error check.."); + //log("doc changed update, man error check.."); } } @@ -443,15 +441,13 @@ public class ErrorCheckerService implements Runnable{ public int compilationUnitState = 0; protected boolean checkCode() { - //log("checkCode() " + textModified.get() ); - log("checkCode() " + textModified.get()); + // log("checkCode() " + textModified.get()); lastTimeStamp = System.currentTimeMillis(); try { sourceCode = preprocessCode(editor.getSketch().getMainProgram()); compilationUnitState = 0; syntaxCheck(); - log(editor.getSketch().getName() + "1 MCO " - + mainClassOffset); + // log(editor.getSketch().getName() + "1 MCO " + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. //if(hasSyntaxErrors()) astGenerator.buildAST(null); @@ -471,8 +467,7 @@ public class ErrorCheckerService implements Runnable{ // log(sourceCode); // log("--------------------------"); compileCheck(); - log(editor.getSketch().getName() + "2 MCO " - + mainClassOffset); + // log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } astGenerator.buildAST(cu); @@ -699,8 +694,8 @@ public class ErrorCheckerService implements Runnable{ // Code in pde tabs stored as PlainDocument PlainDocument pdeTabs[] = new PlainDocument[editor.getSketch() .getCodeCount()]; - log("calcPDEOffsetsForProbList() mco: " + mainClassOffset + " CU state: " - + compilationUnitState); +// log("calcPDEOffsetsForProbList() mco: " + mainClassOffset + " CU state: " +// + compilationUnitState); javaSource.insertString(0, sourceCode, null); for (int i = 0; i < pdeTabs.length; i++) { @@ -725,8 +720,8 @@ public class ErrorCheckerService implements Runnable{ for (Problem p : problemsList) { int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p .getIProblem().getSourceEnd() - pkgNameOffset; - log(p.toString()); - log("IProblem Start " + prbStart + ", End " + prbEnd); + // log(p.toString()); + // log("IProblem Start " + prbStart + ", End " + prbEnd); int javaLineNumber = p.getSourceLineNumber() - ((compilationUnitState != 2) ? 1 : 2); Element lineElement = javaSource.getDefaultRootElement() diff --git a/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java b/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java index 2f6f2bcf8..20a737dc4 100644 --- a/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java +++ b/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java @@ -7,8 +7,6 @@ import java.util.TreeMap; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; -import static processing.mode.experimental.ExperimentalMode.log; -import static processing.mode.experimental.ExperimentalMode.logE; public class ErrorMessageSimplifier { @@ -64,14 +62,15 @@ public class ErrorMessageSimplifier { return null; IProblem iprob = problem.getIProblem(); String args[] = iprob.getArguments(); - log("Simplifying message: " + problem.getMessage() + " ID: " - + getIDName(iprob.getID())); - log("Arg count: " + args.length); - for (int i = 0; i < args.length; i++) { - log("Arg " + args[i]); - } +// log("Simplifying message: " + problem.getMessage() + " ID: " +// + getIDName(iprob.getID())); +// log("Arg count: " + args.length); +// for (int i = 0; i < args.length; i++) { +// log("Arg " + args[i]); +// } String result = null; + switch (iprob.getID()) { case IProblem.ParsingError: if (args.length > 0) { @@ -107,7 +106,8 @@ public class ErrorMessageSimplifier { break; case IProblem.UndefinedMethod: if (args.length > 2) { - result = "I don't know the function \"" + args[args.length - 2] + "\""; + result = "The method \"" + args[args.length - 2] + "(" + + getSimpleName(args[args.length - 1]) + ")\" doesn't exist"; } break; case IProblem.ParameterMismatch: @@ -118,42 +118,43 @@ public class ErrorMessageSimplifier { result = "The method \"" + args[1] + "\" doesn't expect any parameters"; } else { - result = "The method \"" + args[1] + "\" expects parameters (" + result = "The method \"" + args[1] + + "\" expects parameters like this: " + args[1] + "(" + getSimpleName(args[2]) + ")"; } } break; case IProblem.UndefinedField: if (args.length > 0) { - result = "I don't know the global variable \"" + args[0] + "\""; + result = "The global variable \"" + args[0] + "\" doesn't exist"; } break; case IProblem.UndefinedType: if (args.length > 0) { - result = "I don't know the class \"" + args[0] + "\""; + result = "The class \"" + args[0] + "\" doesn't exist"; } break; case IProblem.UnresolvedVariable: if (args.length > 0) { - result = "I can't recognize the variable \"" + args[0] + "\""; + result = "The variable \"" + args[0] + "\" doesn't exist"; } break; case IProblem.UndefinedName: if (args.length > 0) { - result = "I don't recognize the name \"" + args[0] + "\""; + result = "The name \"" + args[0] + "\" can't be recognized"; } break; case IProblem.TypeMismatch: if (args.length > 1) { - result = "You can't assign a \"" + getSimpleName(args[0]) - + "\" type to a \"" + getSimpleName(args[1]) + "\" type"; + result = "Type mismatch, \"" + getSimpleName(args[0]) + + "\" doesn't match with \"" + getSimpleName(args[1]) + "\""; } break; } - log("Simplified Error Msg: " + result); +// log("Simplified Error Msg: " + result); if (result == null) - return problem.getMessage(); + result = problem.getMessage(); return result; } @@ -189,25 +190,25 @@ public class ErrorMessageSimplifier { String result = null; switch (c) { case ';': - result = "You're missing a semi-colon \";\""; + result = "Missing a semi-colon \";\""; break; case '[': - result = "I sense a missing opening square bracket \"[\""; + result = "Missing opening square bracket \"[\""; break; case ']': - result = "Looks like you forgot to close your square bracket \"]\""; + result = "Missing closing square bracket \"]\""; break; case '(': - result = "I sense a missing opening parentheses \"(\""; + result = "Missing opening parentheses \"(\""; break; case ')': - result = "Looks like you forgot to close your parentheses \")\""; + result = "Missing closing parentheses \")\""; break; case '{': - result = "I sense a missing opening curly brace \"{\""; + result = "Missing opening curly bracket \"{\""; break; case '}': - result = "Looks like you forgot to close your curly brace \"}\""; + result = "Missing closing curly bracket \"}\""; break; default: result = "Consider adding a \"" + c + "\""; diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index c87f73cd8..94d0f9778 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -116,7 +116,8 @@ public class ExperimentalMode extends JavaMode { @Override public String getTitle() { - return "PDE X"; + //return "PDE X"; + return "Java"; } @@ -178,8 +179,8 @@ public class ExperimentalMode extends JavaMode { defaultAutoSaveEnabled = Preferences.getBoolean(prefDefaultAutoSave); ccTriggerEnabled = Preferences.getBoolean(prefCCTriggerEnabled); - // TweakMode code - enableTweak = Preferences.getBoolean(prefEnableTweak); + // TweakMode code - not a sticky preference anymore + // enableTweak = Preferences.getBoolean(prefEnableTweak); } public void savePreferences() { @@ -196,8 +197,8 @@ public class ExperimentalMode extends JavaMode { Preferences.setBoolean(prefDefaultAutoSave, defaultAutoSaveEnabled); Preferences.setBoolean(prefCCTriggerEnabled, ccTriggerEnabled); - // TweakMode code - Preferences.setBoolean(prefEnableTweak, enableTweak); + // TweakMode code - not a sticky preference anymore + // Preferences.setBoolean(prefEnableTweak, enableTweak); } public void ensurePrefsExist() { @@ -225,10 +226,10 @@ public class ExperimentalMode extends JavaMode { if (Preferences.get(prefCCTriggerEnabled) == null) Preferences.setBoolean(prefCCTriggerEnabled, ccTriggerEnabled); - // TweakMode code - if (Preferences.get(prefEnableTweak) == null) { - Preferences.setBoolean(prefEnableTweak, enableTweak); - } + // TweakMode code - not a sticky preference anymore +// if (Preferences.get(prefEnableTweak) == null) { +// Preferences.setBoolean(prefEnableTweak, enableTweak); +// } } @@ -289,7 +290,7 @@ public class ExperimentalMode extends JavaMode { + "field_protected_obj.png"); localVarIcon = new ImageIcon(iconPath + File.separator + "field_default_obj.png"); - log("Icons loaded"); + // log("Icons loaded"); } @@ -343,6 +344,7 @@ public class ExperimentalMode extends JavaMode { public Runner handleRun(Sketch sketch, RunnerListener listener) throws SketchException { if (enableTweak) { + enableTweak = false; return handleTweakPresentOrRun(sketch, listener, false); } else { @@ -366,6 +368,7 @@ public class ExperimentalMode extends JavaMode { public Runner handlePresent(Sketch sketch, RunnerListener listener) throws SketchException { if (enableTweak) { + enableTweak = false; return handleTweakPresentOrRun(sketch, listener, true); } else { diff --git a/pdex/src/processing/mode/experimental/LineBreakpoint.java b/pdex/src/processing/mode/experimental/LineBreakpoint.java index e35cea22e..696726b8a 100755 --- a/pdex/src/processing/mode/experimental/LineBreakpoint.java +++ b/pdex/src/processing/mode/experimental/LineBreakpoint.java @@ -17,17 +17,16 @@ */ package processing.mode.experimental; -import com.sun.jdi.AbsentInformationException; -import com.sun.jdi.Location; -import com.sun.jdi.ReferenceType; -import com.sun.jdi.request.BreakpointRequest; +import static processing.mode.experimental.ExperimentalMode.log; + import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import static processing.mode.experimental.ExperimentalMode.log; -import static processing.mode.experimental.ExperimentalMode.logE; -import static processing.mode.experimental.ExperimentalMode.log2; +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Location; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.request.BreakpointRequest; /** * Model/Controller of a line breakpoint. Can be set before or while debugging. diff --git a/pdex/src/processing/mode/experimental/OffsetMatcher.java b/pdex/src/processing/mode/experimental/OffsetMatcher.java index ef907b50d..3623e4161 100644 --- a/pdex/src/processing/mode/experimental/OffsetMatcher.java +++ b/pdex/src/processing/mode/experimental/OffsetMatcher.java @@ -42,7 +42,7 @@ public class OffsetMatcher { if(pdeCodeLine.trim().equals(javaCodeLine.trim())){ //TODO: trim() needed here? matchingNeeded = false; offsetMatch = new ArrayList(); - log("Offset Matching not needed"); + //log("Offset Matching not needed"); } else { @@ -61,25 +61,25 @@ public class OffsetMatcher { } public int getPdeOffForJavaOff(int start, int length) { - log("PDE :" + pdeCodeLine + "\nJAVA:" + javaCodeLine); + // log("PDE :" + pdeCodeLine + "\nJAVA:" + javaCodeLine); if(!matchingNeeded) return start; - int ans = getPdeOffForJavaOff(start), end = getPdeOffForJavaOff(start + length - 1); - log(start + " java start off, pde start off " - + ans); - log((start + length - 1) + " java end off, pde end off " - + end); - log("J: " + javaCodeLine.substring(start, start + length) + "\nP: " - + pdeCodeLine.substring(ans, end + 1)); + int ans = getPdeOffForJavaOff(start); //, end = getPdeOffForJavaOff(start + length - 1); +// log(start + " java start off, pde start off " +// + ans); +// log((start + length - 1) + " java end off, pde end off " +// + end); +// log("J: " + javaCodeLine.substring(start, start + length) + "\nP: " +// + pdeCodeLine.substring(ans, end + 1)); return ans; } public int getJavaOffForPdeOff(int start, int length) { if(!matchingNeeded) return start; int ans = getJavaOffForPdeOff(start); - log(start + " pde start off, java start off " - + getJavaOffForPdeOff(start)); - log((start + length - 1) + " pde end off, java end off " - + getJavaOffForPdeOff(start + length - 1)); +// log(start + " pde start off, java start off " +// + getJavaOffForPdeOff(start)); +// log((start + length - 1) + " pde end off, java end off " +// + getJavaOffForPdeOff(start + length - 1)); return ans; } @@ -91,8 +91,8 @@ public class OffsetMatcher { } else if (offsetMatch.get(i).javaOffset == javaOff) { // int j = i; while (offsetMatch.get(--i).javaOffset == javaOff) { - log("MP " + offsetMatch.get(i).javaOffset + " " - + offsetMatch.get(i).pdeOffset); +// log("MP " + offsetMatch.get(i).javaOffset + " " +// + offsetMatch.get(i).pdeOffset); } int pdeOff = offsetMatch.get(++i).pdeOffset; while (i > 0 && offsetMatch.get(--i).pdeOffset == pdeOff); @@ -140,8 +140,8 @@ public class OffsetMatcher { // word2 = reverse(word2); int len1 = pdeCodeLine.length(); int len2 = javaCodeLine.length(); - log(pdeCodeLine + " len: " + len1); - log(javaCodeLine + " len: " + len2); + // log(pdeCodeLine + " len: " + len1); + // log(javaCodeLine + " len: " + len2); // len1+1, len2+1, because finally return dp[len1][len2] int[][] dp = new int[len1 + 1][len2 + 1]; diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index 895ffcd01..eafda9366 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -1,19 +1,17 @@ package processing.mode.experimental; -import static processing.mode.experimental.ExperimentalMode.log; - import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; -import java.io.File; import java.util.List; import javax.swing.BoxLayout; -import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -36,8 +34,6 @@ import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; -import processing.app.Base; - public class SketchOutline { protected JFrame frmOutlineView; @@ -52,10 +48,21 @@ public class SketchOutline { protected JTextField searchField; protected DebugEditor editor; + + protected boolean internalSelection = false; public SketchOutline(DefaultMutableTreeNode codeTree, ErrorCheckerService ecs) { errorCheckerService = ecs; editor = ecs.getEditor(); + soNode = new DefaultMutableTreeNode(); + generateSketchOutlineTree(soNode, codeTree); + soNode = (DefaultMutableTreeNode) soNode.getChildAt(0); + tempNode = soNode; + soTree = new JTree(soNode); + createGUI(); + } + + private void createGUI(){ frmOutlineView = new JFrame(); frmOutlineView.setAlwaysOnTop(true); frmOutlineView.setUndecorated(true); @@ -79,11 +86,7 @@ public class SketchOutline { panelTop.add(searchField); jsp = new JScrollPane(); - soNode = new DefaultMutableTreeNode(); - generateSketchOutlineTree(soNode, codeTree); - soNode = (DefaultMutableTreeNode) soNode.getChildAt(0); - tempNode = soNode; - soTree = new JTree(soNode); + soTree.getSelectionModel() .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); soTree.setRootVisible(false); @@ -112,16 +115,13 @@ public class SketchOutline { .min(errorCheckerService.getEditor().ta.getHeight(), frmOutlineView.getHeight()))); frmOutlineView.setLocation(tp.x + errorCheckerService.getEditor().ta - .getWidth() - frmOutlineView.getWidth(), + .getWidth()/2 - frmOutlineView.getWidth()/2, frmOutlineView.getY() + (editor.ta.getHeight() - frmOutlineView .getHeight()) / 2); addListeners(); - } - protected boolean internalSelection = false; - protected void addListeners() { searchField.addKeyListener(new KeyAdapter() { @@ -240,29 +240,40 @@ public class SketchOutline { return; } // log(e); - SwingWorker worker = new SwingWorker() { - - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - if (soTree.getLastSelectedPathComponent() == null) { - return; - } - DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree - .getLastSelectedPathComponent(); - if (tnode.getUserObject() instanceof ASTNodeWrapper) { - ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - awrap.highlightNode(errorCheckerService.astGenerator); - // log(awrap); - //errorCheckerService.highlightNode(awrap); - } - } - }; - worker.execute(); + scrollToNode(); } }); + + soTree.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent me) { + scrollToNode(); + } + }); + } + + private void scrollToNode(){ + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (soTree.getLastSelectedPathComponent() == null) { + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree + .getLastSelectedPathComponent(); + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + awrap.highlightNode(errorCheckerService.astGenerator); + // log(awrap); + //errorCheckerService.highlightNode(awrap); + close(); + } + } + }; + worker.execute(); } protected boolean filterTree(String prefix, DefaultMutableTreeNode tree, diff --git a/pdex/src/processing/mode/experimental/TabOutline.java b/pdex/src/processing/mode/experimental/TabOutline.java new file mode 100644 index 000000000..b570a10e0 --- /dev/null +++ b/pdex/src/processing/mode/experimental/TabOutline.java @@ -0,0 +1,341 @@ +package processing.mode.experimental; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.GridBagLayout; +import java.awt.Point; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; + +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingWorker; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeSelectionModel; + +import processing.app.SketchCode; + +public class TabOutline { + protected JFrame frmOutlineView; + + protected JScrollPane jsp; + + protected DefaultMutableTreeNode tabNode, tempNode; + + protected JTree tabTree; + + protected JTextField searchField; + + protected JLabel lblCaption; + + protected DebugEditor editor; + + protected ErrorCheckerService errorCheckerService; + + protected boolean internalSelection = false; + + public TabOutline(ErrorCheckerService ecs) { + errorCheckerService = ecs; + editor = ecs.getEditor(); + createGUI(); + } + + private void createGUI() { + frmOutlineView = new JFrame(); + frmOutlineView.setAlwaysOnTop(true); + frmOutlineView.setUndecorated(true); + Point tp = errorCheckerService.getEditor().ta.getLocationOnScreen(); + lblCaption = new JLabel("Tabs List (type to filter)"); +// int minWidth = (int) (editor.getMinimumSize().width * 0.7f), maxWidth = (int) (editor +// .getMinimumSize().width * 0.9f); + int minWidth = estimateFrameWidth(), maxWidth = (int) (editor + .getMinimumSize().width * 0.9f); + frmOutlineView.setLayout(new BoxLayout(frmOutlineView.getContentPane(), + BoxLayout.Y_AXIS)); + JPanel panelTop = new JPanel(), panelMiddle = new JPanel(), panelBottom = new JPanel(); + panelTop.setLayout(new GridBagLayout()); + panelMiddle.setLayout(new BoxLayout(panelMiddle, BoxLayout.Y_AXIS)); + panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.Y_AXIS)); + lblCaption.setAlignmentX(Component.LEFT_ALIGNMENT); + panelTop.add(lblCaption); + searchField = new JTextField(); + searchField.setMinimumSize(new Dimension(minWidth, 25)); + panelMiddle.add(searchField); + + jsp = new JScrollPane(); + populateTabTree(); + jsp.setViewportView(tabTree); + jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + jsp.setMinimumSize(new Dimension(minWidth, editor.ta.getHeight() - 10)); + jsp.setMaximumSize(new Dimension(maxWidth, editor.ta.getHeight() - 10)); + + panelBottom.add(jsp); + frmOutlineView.add(panelTop); + frmOutlineView.add(panelMiddle); + frmOutlineView.add(panelBottom); + frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frmOutlineView.pack(); + frmOutlineView.setBounds(tp.x + + errorCheckerService.getEditor().ta + .getWidth() - minWidth, + tp.y, + minWidth, + estimateFrameHeight()); + frmOutlineView.setMinimumSize(new Dimension(minWidth, Math + .min(errorCheckerService.getEditor().ta.getHeight(), + frmOutlineView.getHeight()))); + frmOutlineView.setLocation(tp.x + + errorCheckerService.getEditor().ta + .getWidth()/2 - frmOutlineView.getWidth()/2, + frmOutlineView.getY() + + (editor.ta.getHeight() - frmOutlineView + .getHeight()) / 2); + DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tabTree.getCellRenderer(); + renderer.setLeafIcon(null); + renderer.setClosedIcon(null); + renderer.setOpenIcon(null); + addListeners(); + } + + private void addListeners() { + searchField.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent evt) { + if (tabTree.getRowCount() == 0) + return; + + internalSelection = true; + + if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) { + close(); + } else if (evt.getKeyCode() == KeyEvent.VK_ENTER) { + if (tabTree.getLastSelectedPathComponent() != null) { + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) tabTree + .getLastSelectedPathComponent(); + //log("Enter Key, Tab: " + tnode); + switchToTab(tnode.toString()); + close(); + } + } else if (evt.getKeyCode() == KeyEvent.VK_UP) { + if (tabTree.getLastSelectedPathComponent() == null) { + tabTree.setSelectionRow(0); + return; + } + + int x = tabTree.getLeadSelectionRow() - 1; + int step = jsp.getVerticalScrollBar().getMaximum() + / tabTree.getRowCount(); + if (x == -1) { + x = tabTree.getRowCount() - 1; + jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar() + .getMaximum()); + } else { + jsp.getVerticalScrollBar().setValue((jsp.getVerticalScrollBar() + .getValue() - step)); + } + tabTree.setSelectionRow(x); + } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) { + if (tabTree.getLastSelectedPathComponent() == null) { + tabTree.setSelectionRow(0); + return; + } + int x = tabTree.getLeadSelectionRow() + 1; + + int step = jsp.getVerticalScrollBar().getMaximum() + / tabTree.getRowCount(); + if (x == tabTree.getRowCount()) { + x = 0; + jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar() + .getMinimum()); + } else { + jsp.getVerticalScrollBar().setValue((jsp.getVerticalScrollBar() + .getValue() + step)); + } + tabTree.setSelectionRow(x); + } + } + }); + + searchField.getDocument().addDocumentListener(new DocumentListener() { + + public void insertUpdate(DocumentEvent e) { + updateSelection(); + } + + public void removeUpdate(DocumentEvent e) { + updateSelection(); + } + + public void changedUpdate(DocumentEvent e) { + updateSelection(); + } + + private void updateSelection() { + SwingWorker worker = new SwingWorker() { + protected Object doInBackground() throws Exception { + String text = searchField.getText().toLowerCase(); + tempNode = new DefaultMutableTreeNode(); + filterTree(text, tempNode, tabNode); + return null; + } + + protected void done() { + tabTree.setModel(new DefaultTreeModel(tempNode)); + ((DefaultTreeModel) tabTree.getModel()).reload(); +// for (int i = 0; i < tabTree.getRowCount(); i++) { +// tabTree.expandRow(i); +// } + internalSelection = true; + tabTree.setSelectionRow(0); + } + }; + worker.execute(); + } + }); + + tabTree.addTreeSelectionListener(new TreeSelectionListener() { + + public void valueChanged(TreeSelectionEvent e) { + + if (internalSelection) { + //log("Internal selection"); + internalSelection = (false); + return; + } + // log(e); + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (tabTree.getLastSelectedPathComponent() == null) { + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) tabTree + .getLastSelectedPathComponent(); + //log("Clicked " + tnode); + switchToTab(tnode.toString()); + close(); + } + }; + worker.execute(); + } + }); + + tabTree.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent me) { + if (tabTree.getLastSelectedPathComponent() == null) { + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) tabTree + .getLastSelectedPathComponent(); + //log("Clicked " + tnode); + switchToTab(tnode.toString()); + close(); + } + }); + + frmOutlineView.addWindowFocusListener(new WindowFocusListener() { + public void windowLostFocus(WindowEvent e) { + close(); + } + + public void windowGainedFocus(WindowEvent e) { + } + }); + } + + private void switchToTab(String tabName) { + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.getPrettyName().equals(tabName)) { + editor.getSketch().setCurrentCode(editor.getSketch().getCodeIndex(sc)); + } + } + } + + private void populateTabTree() { + tabNode = new DefaultMutableTreeNode("Tabs"); + for (SketchCode sc : editor.getSketch().getCode()) { + DefaultMutableTreeNode tab = new DefaultMutableTreeNode( + sc.getPrettyName()); + tabNode.add(tab); + } + tempNode = tabNode; + tabTree = new JTree(tabNode); + tabTree.getSelectionModel() + .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + tabTree.setRootVisible(false); + tabTree.setSelectionRow(editor.getSketch().getCurrentCodeIndex()); + } + + protected boolean filterTree(String prefix, DefaultMutableTreeNode tree, + DefaultMutableTreeNode mainTree) { + if (mainTree.isLeaf()) { + return (mainTree.getUserObject().toString().toLowerCase() + .startsWith(prefix)); + } + + boolean found = false; + for (int i = 0; i < mainTree.getChildCount(); i++) { + DefaultMutableTreeNode tNode = new DefaultMutableTreeNode( + ((DefaultMutableTreeNode) mainTree + .getChildAt(i)) + .getUserObject()); + if (filterTree(prefix, tNode, + (DefaultMutableTreeNode) mainTree.getChildAt(i))) { + found = true; + tree.add(tNode); + } + } + return found; + } + + private int estimateFrameWidth() { + FontMetrics fm = editor.ta.getGraphics().getFontMetrics(); + int w = fm.stringWidth(lblCaption.getText()) + 10; + for (int i = 0; i < editor.getSketch().getCodeCount(); i++) { + w = Math.max(w, fm.stringWidth(editor.getSketch().getCode(i) + .getPrettyName()) + 10); + } + return w; + } + + private int estimateFrameHeight() { + int textHeight = jsp.getGraphics().getFontMetrics().getHeight() + 2; + int t = Math.max(4, editor.getSketch().getCodeCount() + 3); + return Math.min(textHeight * t, frmOutlineView.getHeight()); + } + + public void show() { + frmOutlineView.setVisible(true); + } + + public void close() { + frmOutlineView.setVisible(false); + frmOutlineView.dispose(); + } + + public boolean isVisible() { + return frmOutlineView.isVisible(); + } + +} diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index fe333c8e4..82a8e311c 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -38,7 +38,6 @@ import java.util.Map; import javax.swing.DefaultListModel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; -import javax.swing.text.BadLocationException; import processing.app.syntax.JEditTextArea; import processing.app.syntax.TextAreaDefaults; @@ -246,7 +245,7 @@ public class TextArea extends JEditTextArea { // errorCheckerService.runManualErrorCheck(); // Provide completions only if it's enabled if (ExperimentalMode.codeCompletionsEnabled - && !ExperimentalMode.ccTriggerEnabled) { + && (!ExperimentalMode.ccTriggerEnabled || suggestion.isVisible())) { log("[KeyEvent]" + evt2.getKeyChar() + " |Prediction started: " + System.currentTimeMillis()); log("Typing: " + fetchPhrase(evt2) + " " @@ -774,7 +773,7 @@ public class TextArea extends JEditTextArea { - getLineStartOffset(getCaretLine())); location.y = lineToY(getCaretLine()) + getPainter().getFontMetrics().getHeight() + getPainter().getFontMetrics().getDescent(); - log("TA position: " + location); + //log("TA position: " + location); } catch (Exception e2) { e2.printStackTrace(); return; @@ -805,7 +804,7 @@ public class TextArea extends JEditTextArea { protected void hideSuggestion() { if (suggestion != null) { suggestion.hide(); - log("Suggestion hidden."); + //log("Suggestion hidden."); suggestion = null; } } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index bade2b345..cebe21e84 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -358,7 +358,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter // horizontalAdjustment); int y = ta.lineToY(line); y += fm.getLeading() + fm.getMaxDescent(); - int height = fm.getHeight(); +// int height = fm.getHeight(); int start = ta.getLineStartOffset(line) + problem.getPDELineStartOffset(); int pLength = problem.getPDELineStopOffset() + 1 - problem.getPDELineStartOffset(); @@ -513,8 +513,8 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter String tooltipText = errorCheckerService.getASTGenerator() .getLabelForASTNode(line, word, xLS); - log(errorCheckerService.mainClassOffset + " MCO " - + "|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); +// log(errorCheckerService.mainClassOffset + " MCO " +// + "|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); if (tooltipText != null) return tooltipText; return word; @@ -623,7 +623,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter for (int tab=0; tab(); + locals = new ArrayList(); + thisFields = new ArrayList(); + declaredThisFields = new ArrayList(); this.setTitle(editor.getSketch().getName()); @@ -537,7 +540,6 @@ public class VariableInspector extends javax.swing.JFrame { * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ - @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { @@ -805,7 +807,7 @@ public class VariableInspector extends javax.swing.JFrame { * @return the filtered list. */ protected List filterNodes(List nodes, VariableNodeFilter filter) { - List filtered = new ArrayList(); + List filtered = new ArrayList(); for (VariableNode node : nodes) { if (filter.accept(node)) { filtered.add(node); diff --git a/pdex/src/processing/mode/experimental/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java index 91b613521..b9a63b45a 100755 --- a/pdex/src/processing/mode/experimental/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -107,14 +107,15 @@ public class XQPreprocessor { // System.out.println("------------XQPreProc End-----------------"); // Calculate main class offset - int position = doc.get().indexOf("{") + 1; - int lines = 0; - for (int i = 0; i < position; i++) { - if (doc.get().charAt(i) == '\n') { - lines++; - } - } - lines += 2; + // removed unused 'lines' tabulation [fry 140726] +// int position = doc.get().indexOf("{") + 1; +// int lines = 0; +// for (int i = 0; i < position; i++) { +// if (doc.get().charAt(i) == '\n') { +// lines++; +// } +// } +// lines += 2; // System.out.println("Lines: " + lines); return doc.get(); diff --git a/pdex/todo.txt b/pdex/todo.txt index c177853c6..b8d2c6d7e 100644 --- a/pdex/todo.txt +++ b/pdex/todo.txt @@ -12,11 +12,25 @@ Manindra Moharana (me@mkmoharana.com) Critical Bugs ------------- --[ ] Better memory management. #1 +-[x] Better memory management. #1 -[ ] Breakpoints in classes. #47 +Misc Tasks +---------- + +-[x] Trim CompilationChecker class + +-[x] Refactoring should support single undo + +Import Suggestion +----------------- + +-[ ] Ignore case while looking for classname + +-[ ] Prevent running into a suggestion loop + Normal Bugs ----------- -[x] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 @@ -35,16 +49,14 @@ Enhancements/New Features -[ ] Gotta fix PEH for multiple errors per line. Will be slightly meticulous. +-[x] Better comment/uncomment - ignores leading whitespaces, and more uniform // placement. + -[ ] When viewing Outline View, instead of showing the beginning of the list, it should select the current node element within which the cursor is presently positioned. -[ ] Begin work on code snippets. --[ ] JUnit Testing? - -[ ] Preferences panel -[ ] Line Numbers - - diff --git a/todo.txt b/todo.txt index 087bc1ead..cc5100af0 100644 --- a/todo.txt +++ b/todo.txt @@ -1,14 +1,16 @@ -0228 pde -X increase heap size to 256m (-Xmx256) per Manindra request -X use a ButtonGroup so that the current Mode cannot be de-selected -X https://github.com/processing/processing/issues/2545 +0229 pde (3.0a2) -pulls -X Implementation of a list of open sketches in the Sketch menu -X https://github.com/processing/processing/pull/2551 -_ color selector for the pref (not reading it properly) -_ https://github.com/processing/processing/pull/2568 +_ "Platform is ${platform}" message during 'ant clean' + +_ add a new pref for the 3.0 sketchbook location +_ remove minim +_ add the new sound library to the build process + +_ double-clicking a .pde file doesn't open properly on OS X +_ https://github.com/processing/processing/issues/2639 +_ OS X export button not disabled on other platforms +_ https://github.com/processing/processing/issues/2642 _ look at the sound library https://github.com/wirsing/ProcessingSound @@ -590,8 +592,7 @@ _ https://github.com/processing/processing/issues/943 PDE / Manager -_ contrib properties files ignored in favor of contributions.txt from p5.org -_ https://github.com/processing/processing/issues/2572 +_ something to set min/max versions that are supported by a library _ ability to cancel a download/install _ we shouldn't use .properties extension for modes, et al _ because a .properties file is iso8859-1