diff --git a/Channel.pde b/Channel.pde index 7d6cb5d..8e87c40 100644 --- a/Channel.pde +++ b/Channel.pde @@ -4,10 +4,8 @@ import java.util.Stack; public class ChannelOsc { HashMap current_notes; // Pairs - Env[] circular_array_envs; - int curr_env_index = 0; float curr_global_amp = 1.0; // channel volume (0.0 to 1.0) - float amp_multiplier = 1.0; // basically expression + float amp_multiplier = 1.0; // basically expression float curr_global_bend = 0.0; // channel pitch bend (-curr_bend_range to curr_bend_range semitones) float curr_global_pan = 0.0; // channel stereo panning (-1.0 to 1.0) float curr_bend_range = 2.0; // channel pitch bend range +/- semitones... uh, sure. @@ -16,7 +14,6 @@ public class ChannelOsc { String please_how_many_midi_params_are_there = "dw, around 100+"; // darn. boolean silenced = false; // mute button int osc_type; - float[] env_values; Oscillator osc; float pulse_width = 0.5; ChannelDisplay disp; @@ -27,17 +24,16 @@ public class ChannelOsc { float last_amp = 0.0; float last_freq = 0; int last_notecode = -1; + int midi_program = 0; ChannelOsc() { current_notes = new HashMap(); - circular_array_envs = new Env[CIRCULAR_ARR_SIZE]; } ChannelOsc(int osc_type) { current_notes = new HashMap(); - circular_array_envs = new Env[CIRCULAR_ARR_SIZE]; set_osc_type(osc_type); } @@ -64,9 +60,13 @@ public class ChannelOsc { void play_note(int note_code, int velocity) { if (curr_global_amp <= 0 || silenced) return; + if (osc_type == 4) { + play_drum(note_code, velocity); + return; + } stop_note(note_code); - int mod_note_code = floor( note_code + curr_noteDetune + player.ktrans.transform[(note_code - 2 + player.mid_rootnote) % 12] ); + float mod_note_code = note_code + curr_noteDetune + player.ktrans.transform[(note_code - 2 + player.mid_rootnote) % 12]; float freq = midi_to_freq(mod_note_code); float amp = map(velocity, 0, 127, 0.0, 1.0); @@ -78,32 +78,38 @@ public class ChannelOsc { } s.pan(curr_global_pan); s.amp(amp * (osc_type == 1 || osc_type == 2 ? 0.12 : 0.05) * curr_global_amp * amp_multiplier); // give a volume boost to TRI and SIN - - /*Env e = circular_array_envs[curr_env_index]; - if (e == null) { - e = new Env(PARENT); - circular_array_envs[curr_env_index] = e; - }*/ if (osc_type == 0) ((Pulse) s).width(pulse_width); - if (env_values != null && env_values.length == 4) { - Env e = new Env(PARENT); - e.play(s, env_values[0], env_values[1], env_values[2], env_values[3]); // will come back to envelopes... great potential but buggy :( - } - else s.play(); + s.play(); last_amp = amp; last_freq = freq; - last_notecode = mod_note_code; - /*curr_env_index++; - if (curr_env_index >= CIRCULAR_ARR_SIZE) curr_env_index = 0;*/ + last_notecode = floor(mod_note_code); + } + + + void play_drum(int note_code, int velocity) { + float amp = map(velocity, 0, 127, 0.0, 1.0); + + int sample_code = note_code_to_percussion(note_code); + SoundFile s = (SoundFile) samples[sample_code-1]; + if (s == null || s.isPlaying()) return; + + s.amp(amp * 0.32 * curr_global_amp * amp_multiplier); + s.play(); + + last_amp = amp; + last_freq = sample_code; + last_notecode = note_code; } void stop_note(int note_code) { - SoundObject s = current_notes.get(note_code); - if (s == null) return; - s.stop(); + if (osc_type != 4) { + SoundObject s = current_notes.get(note_code); + if (s == null) return; + s.stop(); + } last_amp = 0.0; last_freq = 0.0; @@ -122,20 +128,16 @@ public class ChannelOsc { else this.osc_type = int(osc_type); } - void set_env_values(float[] env_values) { - this.env_values = env_values; - } - void set_expression(int value) { amp_multiplier = map(value, 0, 127, 0.0, 1.0); - set_all_oscs_amp(); + if (osc_type != 4) set_all_oscs_amp(); } void set_volume(int value) { curr_global_amp = map(value, 0, 127, 0.0, 1.0); - set_all_oscs_amp(); + if (osc_type != 4) set_all_oscs_amp(); } @@ -160,7 +162,8 @@ public class ChannelOsc { void set_bend(int bits_lsb, int bits_msb) { - // i can't believe i finally achieved this... + if (osc_type == -1) return; // no bend for drums... + int value = (bits_msb << 7) + bits_lsb; curr_global_bend = map(value, 0, 16383, -1.0, 1.0) * curr_bend_range; float freq_ratio = (float) Math.pow(2, curr_global_bend / 12.0); @@ -184,8 +187,8 @@ public class ChannelOsc { void set_muted(boolean how) { if (how) shut_up(); - silenced = how; disp.button_mute.set_pressed(how); + silenced = how; } @@ -211,56 +214,6 @@ public class ChannelOsc { -class ChannelOscDrum extends ChannelOsc { - SoundFile[] samples; - - - ChannelOscDrum() { - super(); - - // preloading samples... - samples = new SoundFile[4]; - for (int i = 1; i <= samples.length; i++) { - samples[i-1] = new SoundFile(PARENT, "samples/" + i + ".wav"); - } - } - - - void play_note(int note_code, int velocity) { - if (curr_global_amp <= 0 || silenced) return; - - float amp = map(velocity, 0, 127, 0.0, 1.0); - - int sample_code = note_code_to_percussion(note_code); - SoundFile s = (SoundFile) samples[sample_code-1]; - if (s == null || s.isPlaying()) return; - - s.amp(amp * 0.22 * curr_global_amp); - s.play(); - - last_amp = amp; - last_freq = sample_code; - last_notecode = note_code; - } - - - void stop_note(int note_code) { - last_amp = 0.0; - last_freq = 0; - last_notecode = -1; - } - - - void set_volume(int volume) { - curr_global_amp = map(volume, 0, 127, 0.0, 1.0); - } - - - void set_bend(int bits_lsb, int bits_msb) {} // no bend for drums!! -} - - - Oscillator get_new_osc(int osc_type) { // This notation will be used switch (osc_type) { @@ -270,7 +223,9 @@ Oscillator get_new_osc(int osc_type) { return new TriOsc(PARENT); case 2: return new SinOsc(PARENT); - default: + case 3: return new SawOsc(PARENT); + default: + return null; } } diff --git a/LabsModule.pde b/LabsModule.pde index 209d05f..62627c5 100644 --- a/LabsModule.pde +++ b/LabsModule.pde @@ -10,7 +10,8 @@ public class LabsModule extends PApplet { public void settings() { - this.size(210, 300); + if (osname.contains("Windows")) this.size(210, 356); + else this.size(210, 330); } @@ -38,13 +39,15 @@ public class LabsModule extends PApplet { b2.show_label = false; Button b3 = new Button("tempo", "tempo"); b3.show_label = false; + Button b7 = new Button("overrideOscs", "overrideOscs"); + b7.show_label = false; Button b4 = new Button("transform", "transform"); b4.show_label = false; Button b5 = new Button("sysSynth", "sysSynth"); b5.show_label = false; Button b6 = new Button("midiIn", "midiIn"); b6.show_label = false; - Button[] bs = new Button[] {b1, b2, b3, b4, b5, b6}; + Button[] bs = new Button[] {b1, b2, b3, b7, b4, b5, b6}; all_buttons = new ButtonToolbar(8, 45, 0, 1.3, bs); } @@ -66,7 +69,7 @@ public class LabsModule extends PApplet { player.set_all_freqDetune(val); } catch (NumberFormatException nfe) { - ui.showErrorDialog("Invalid value. Examples: 10, -90.2, 0, 167.74", "Can't"); + ui.showErrorDialog("Invalid value. Examples: 3, -10.2, 0, 67.74", "Can't"); } catch (NullPointerException npe) {} } @@ -77,7 +80,7 @@ public class LabsModule extends PApplet { player.set_all_noteDetune(val); } catch (NumberFormatException nfe) { - ui.showErrorDialog("Invalid value. Examples: 4, -10.2, 0, 8.74", "Can't"); + ui.showErrorDialog("Invalid value. Examples: 4, -1.2, 0, 8.74", "Can't"); } catch (NullPointerException npe) {} } @@ -94,6 +97,24 @@ public class LabsModule extends PApplet { catch (NullPointerException npe) {} } + else if (all_buttons.collided("overrideOscs", this)) { + String selection = ui.showSelectionDialog( + "Override all channels with which oscillator?", + "LabsModule", + Arrays.asList("Pulse W0.125", "Pulse W0.25", "Pulse W0.5", "Pulse W0.75", "Triangle", "Sine", "Saw") + ); + + if (selection != null) { + if (selection.equals("Pulse W0.125")) player.set_all_osc_types(0.125); + if (selection.equals("Pulse W0.25")) player.set_all_osc_types(0.25); + if (selection.equals("Pulse W0.5")) player.set_all_osc_types(0.5); + if (selection.equals("Pulse W0.75")) player.set_all_osc_types(0.75); + if (selection.equals("Triangle")) player.set_all_osc_types(1); + if (selection.equals("Sine")) player.set_all_osc_types(2); + if (selection.equals("Saw")) player.set_all_osc_types(3); + } + } + else if (all_buttons.collided("transform", this)) { String selection = new UiBooster().showSelectionDialog( "New key/chord mode?", @@ -135,7 +156,8 @@ public class LabsModule extends PApplet { void mouseMoved() { if (all_buttons.collided("freqDetune", this) || all_buttons.collided("noteDetune", this) || - all_buttons.collided("tempo", this) || + all_buttons.collided("tempo", this) || + all_buttons.collided("overrideOscs", this) || all_buttons.collided("transform", this) || all_buttons.collided("sysSynth", this) || all_buttons.collided("midiIn", this) @@ -161,15 +183,16 @@ public class LabsModule extends PApplet { this.textFont(fonts[2]); this.fill(t.theme[0]); this.textAlign(CENTER, CENTER); - this.text("Experimental options!\nUse at own risk.", this.width/2, 22); + this.text("Experimental options!\nUse at your own risk.", this.width/2, 22); this.textFont(fonts[1]); this.text(player.last_freqDetune, 179, 60); this.text(player.last_noteDetune, 179, 99); this.text("x" + player.seq.getTempoFactor(), 179, 138); - this.text(curr_transform, 179, 177); - this.text((player.system_synth ? "On" : "Off"), 179, 216); - this.text((player.midi_in_mode ? "On" : "Off"), 179, 255); + //this.text("x", 179, 177); + this.text(curr_transform, 179, 216); + this.text((player.system_synth ? "On" : "Off"), 179, 255); + this.text((player.midi_in_mode ? "On" : "Off"), 179, 294); all_buttons.redraw(this); } diff --git a/P3synth.pde b/P3synth.pde index f66cf1a..29babbc 100644 --- a/P3synth.pde +++ b/P3synth.pde @@ -6,10 +6,11 @@ import java.awt.*; import processing.awt.PSurfaceAWT; final processing.core.PApplet PARENT = this; -final float VERCODE = 22.99; +final float VERCODE = 23.11; final float OVERALL_VOL = 0.7; Frame frame; +String osname; Player player; LabsModule win_labs; DnDListener dnd_listener; @@ -17,6 +18,7 @@ PImage[] logo_anim; PImage[] osc_type_textures; PImage logo_icon; PFont[] fonts; +SoundFile[] samples; ThemeEngine t; ButtonToolbar media_buttons; ButtonToolbar setting_buttons; @@ -27,7 +29,9 @@ WaitingDialog dialog_meta_msgs; HashMap config_map; void settings() { - size(724, 436); + osname = System.getProperty("os.name"); + if (osname.contains("Windows")) size(724, 460); + else size(724, 430); } @@ -49,6 +53,7 @@ void setup() { setup_fonts(); setup_buttons(); setup_config(); + setup_samples(); t.set_theme(config_map.get("theme name")); player = new Player(); @@ -157,6 +162,13 @@ void redraw_all() { } +void setup_samples() { + samples = new SoundFile[4]; + for (int i = 1; i <= samples.length; i++) { + samples[i-1] = new SoundFile(PARENT, "samples/" + i + ".wav"); + } +} + void setup_images() { logo_anim = new PImage[8]; diff --git a/Player.pde b/Player.pde index 9af0a6e..9f84931 100644 --- a/Player.pde +++ b/Player.pde @@ -40,6 +40,7 @@ class Player { final int TEMPO_LIMIT = 1000; final String DEFAULT_STOPPED_MSG = "Drag and drop a file to play..."; + boolean new_engine = false; Sequencer seq; KeyTransformer ktrans; Thread sent; @@ -89,7 +90,7 @@ class Player { for (int i = 0; i < nChannels; i++) { channels[i] = new ChannelOsc(-1); - if (i == 9) channels[i] = new ChannelOscDrum(); + if (i == 9) channels[i] = new ChannelOsc(4); channels[i].create_display(12 + 180 * (i / 4), 64 + 72 * (i % 4), i); channels[i].disp.redraw(false); // draw meters at value 0 @@ -145,6 +146,7 @@ class Player { String play_file(String filename) { set_playing_state(-1); + if (midi_in_mode) stop_midi_in(); File file = new File(filename); try { @@ -157,7 +159,7 @@ class Player { set_playing_state(1); } catch(InvalidMidiDataException imde) { - return "Invalid Midi data!"; + return "Invalid MIDI data!"; } catch(IOException ioe) { return "I/O Error!"; @@ -234,7 +236,6 @@ class Player { void stop_midi_in() { midi_in_mode = false; - shut_up_all(); sent.interrupt(); try { sock.close(); @@ -242,6 +243,7 @@ class Player { } catch (IOException ioe) { println("ioe on close???"); } ui.showInfoDialog("MIDI In disconnected!"); + set_playing_state(-1); } @@ -374,11 +376,13 @@ class Player { } else if (comm == ShortMessage.PROGRAM_CHANGE) { - if (data1 >= 112) channels[chan].curr_global_amp = 0.0; + if (chan == 9) { + channels[chan].set_osc_type(4); + } else { channels[chan].set_osc_type(program_to_osc(data1)); - channels[chan].set_env_values(program_to_env(data1)); } + channels[chan].midi_program = data1; } else if (comm == ShortMessage.PITCH_BEND) { diff --git a/Resources.pde b/Resources.pde index 6bb8443..3e3ec4a 100644 --- a/Resources.pde +++ b/Resources.pde @@ -80,16 +80,16 @@ int[] minor_rootnotes = { float[] prog_osc_relationship = { - 2, 1, 1, 0.5, 0.5, 0.5, 0.3, 0.3, 0.3, 1, 1, 1, 1, 0.5, - 0.3, 0.3, 1, 1, 1, 0.7, 0.7, 0.3, 0.7, 0.3, 2, 1, 2, - 0.3, 1, 0.3, 0.3, 3, 1, 1, 3, 1, 1, 1, 1, 1, 3, 3, - 3, 0.7, 3, 2, 1, 1, 3, 0.7, 0.7, 0.7, 1, 1, 0.5, - 0.5, 0.3, 0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.3, 1, 0.5, 0.5, 2, 1, 2, 2, 1, 0.5, 0.5, 1, 2, - 0.7, 3, 0.5, 0.7, 0.3, 0.3, 0.7, 1, 0.3, 0.7, 0.7, - 0.7, 0.3, 0.3, 0.7, 0.5, 0.3, 0.5, 0.3, 0.7, 0.7, 0.3, 1, - 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 1, 1, 0.5, 0.7, 1, 1, - 1, 1, 2, 0.7, 0.7, 0.3, 0.5, 0.7, 1, 3, 0.3, 0.3 + 2, 1, 1, .25, .75, .25, .125, .125, .75, 1, 1, 1, 1, .25, + .125, .125, 1, 1, 1, .5, .5, .125, .5, .125, 2, 1, 2, + .125, 1, .125, .125, 3, 1, 1, 3, 1, 1, 1, 1, 1, 3, 3, + 3, .5, 3, 2, 1, 1, 3, .5, .5, .5, 1, 1, .25, .25, .125, + .125, .125, .75, .25, .25, .25, .75, .25, .25, .25, .75, + 1, .25, .25, 2, 1, 2, 2, 1, .25, .25, 1, 2, .5, 3, .25, + .5, .125, .125, .5, 1, .125, .5, .5, .5, .75, .125, .5, + .25, .125, .75, .125, .5, .5, .125, 1, .125, .125, .125, + .125, .75, .125, .125, 1, 1, .25, .5, 1, 1, 1, 1, 2, .5, + 4, 4, 4, 4, 4, 4, 4, 4 }; float program_to_osc(int prog) { @@ -97,12 +97,6 @@ float program_to_osc(int prog) { } -float[] program_to_env(int prog) { - // attack time, sustain time, sustain amp, release time - return null; -} - - // 1 → closed hihat, 2 → open hihat, 3 → snare, 4 → tom int[] notecode_perc_relationship = { 4, 4, 4, 3, 3, 3, 4, 1, 4, 1, 4, 2, diff --git a/UIServer.pde b/UIServer.pde index 4c94a7a..8f40fdf 100644 --- a/UIServer.pde +++ b/UIServer.pde @@ -24,7 +24,8 @@ class ChannelDisplay { float meter_velocity = 0.0; // aka channel's last_amp String label_note = ""; int label_osc_type = -1; - int label_pulse_width = 5; + int label_midi_program = 1; + float label_pulse_width = 0.5; float meter_bend = 0.0; float meter_pan = 0.0; @@ -56,9 +57,10 @@ class ChannelDisplay { meter_ch_volume = parent.curr_global_amp * parent.amp_multiplier; meter_velocity = parent.last_amp; + label_osc_type = parent.osc_type; int notecode = parent.last_notecode - 21; - if (id == 9) { if (notecode <= -1) label_note = "| |"; else label_note = "/ \\"; } + if (label_osc_type == 4) { if (notecode <= -1) label_note = "| |"; else label_note = "/ \\"; } else { if (notecode < 0) label_note = "-"; else { @@ -68,8 +70,7 @@ class ChannelDisplay { } } - label_osc_type = parent.osc_type; - label_pulse_width = int(parent.pulse_width * 10); + label_pulse_width = parent.osc_type == 0 ? parent.pulse_width : -1; meter_bend = parent.curr_global_bend / parent.curr_bend_range; // transform +/- channel's curr_bend_range, we need +/- 1.0 meter_pan = parent.curr_global_pan; } @@ -153,19 +154,23 @@ class ChannelDisplay { // Osc type label fill(t.theme[0]); - if (id == 9) { - image(osc_type_textures[5], x+133, y+5); - } - else { - image(osc_type_textures[label_osc_type+1], x+133, y+5); - //if (label_osc_type == 0) text(label_pulse_width, x+145, y+16); // maybe also show pulse width when applicable + int auxY = 0; + if (label_pulse_width != -1) { + auxY = -5; + stroke(t.theme[0]); + fill(t.theme[1]); + rect(x+130, y+23, 28, 4, 4); + fill(t.theme[3]); + noStroke(); + rect(x+131, y+24, 27 * label_pulse_width, 3, 4); } + image(osc_type_textures[label_osc_type+1], x+133, y+5+auxY); // Pitch bend curve stroke(t.theme[0]); strokeWeight(2); noFill(); - if (id != 9) bezier(x+104, y+42, x+104 + 12 * meter_bend, y+42 + -12 * meter_bend, x+120 + 12 * meter_bend, y+56 + -12 * meter_bend, x+120, y+56); + if (label_osc_type != 4) bezier(x+104, y+42, x+104 + 12 * meter_bend, y+42 + -12 * meter_bend, x+120 + 12 * meter_bend, y+56 + -12 * meter_bend, x+120, y+56); else text("x", x+113, y+48); // no bend for drums... // Panning meter