diff --git a/Channel.pde b/Channel.pde index a4f2af1..700a08a 100644 --- a/Channel.pde +++ b/Channel.pde @@ -1,11 +1,10 @@ import processing.sound.*; import java.util.Stack; -import java.util.ConcurrentModificationException; public class ChannelOsc { int id; - HashMap current_notes; // Pairs + HashMap current_notes; // Pairs float curr_global_amp = 1.0; // channel volume (0.0 to 1.0) float amp_multiplier = 1.0; // basically expression float curr_global_bend = 0.0; // channel pitch bend (-curr_bend_range to curr_bend_range semitones) @@ -33,14 +32,14 @@ public class ChannelOsc { ChannelOsc() { - current_notes = new HashMap(); + current_notes = new HashMap(); curr_holding = new ArrayList(); curr_sostenuting = new ArrayList(); } ChannelOsc(int osc_type) { - current_notes = new HashMap(); + current_notes = new HashMap(); curr_holding = new ArrayList(); curr_sostenuting = new ArrayList(); set_osc_type(osc_type); @@ -48,9 +47,7 @@ public class ChannelOsc { void create_display(int x, int y, int id) { - ChannelDisplay d; - if (demo_ui) d = new ChannelDisplayDemo(x, y, id, this); - else d = new ChannelDisplay(x, y, id, this); + ChannelDisplay d = new ChannelDisplay(x, y, id, this); this.disp = d; this.id = id; } @@ -58,15 +55,6 @@ public class ChannelOsc { void redraw_playing() { this.disp.redraw(true); // draw meters with updated values - try { - for (RTSoundObject s : current_notes.values()) { - s.tick(); - } - } - catch (ConcurrentModificationException cme) { - print("cme"); - return; - } } @@ -91,21 +79,21 @@ public class ChannelOsc { } stop_note(note_code); - float mod_note_code = 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(note_code, 0, 127, 0.0, 1.0); + float amp = map(velocity, 0, 127, 0.0, 1.0); - RTSoundObject s = current_notes.get(note_code); + Oscillator s = (Oscillator) current_notes.get(note_code); if (s == null) { - s = new RTSoundObject(get_new_osc(this.osc_type)); + s = get_new_osc(this.osc_type); s.freq((freq + curr_freqDetune) * bend_freq_ratio); current_notes.put(note_code, s); } s.pan(curr_global_pan); s.amp(amp * (osc_type == 1 || osc_type == 2 ? 0.12 : 0.05) * curr_global_amp * amp_multiplier * (soft_pedal ? 0.5 : 1)); // give a volume boost to TRI and SIN - if (osc_type == 0) ((Pulse) s.osc).width(pulse_width); + if (osc_type == 0) ((Pulse) s).width(pulse_width); - if (!demo_ui) s.play(); + s.play(); last_amp = amp; last_freq = freq; @@ -119,11 +107,11 @@ public class ChannelOsc { int sample_code = note_code_to_percussion(note_code); SoundFile s = (SoundFile) samples[sample_code-1]; if (s == null) return; - if (s.isPlaying()) s.stop(); + if (s.isPlaying()) stop_note(note_code); s.pan(curr_global_pan); - s.amp(amp * 0.2 * curr_global_amp * amp_multiplier * (soft_pedal ? 0.5 : 1)); - if (!demo_ui) s.play(); + s.amp(amp * 0.32 * curr_global_amp * amp_multiplier * (soft_pedal ? 0.5 : 1)); + s.play(); last_amp = amp; last_freq = sample_code; @@ -132,11 +120,6 @@ public class ChannelOsc { void stop_note(int note_code) { - stop_note(note_code, false); - } - - - void stop_note(int note_code, boolean force) { /* if (hold_pedal) { curr_holding.add(note_code); return; @@ -146,9 +129,9 @@ public class ChannelOsc { } */ // really disliking how this sounds lol if (osc_type != 4) { - RTSoundObject s = current_notes.get(note_code); + SoundObject s = current_notes.get(note_code); if (s == null) return; - s.stop(force); + s.stop(); } last_amp = 0.0; @@ -173,8 +156,8 @@ public class ChannelOsc { if (osc_type == 4) return; sostenuto_pedal = value < 63 ? false : true; if (sostenuto_pedal) { - for (Entry s : this.current_notes.entrySet()) { - if (s.getValue().osc.isPlaying()) { + for (Entry s : this.current_notes.entrySet()) { + if (((Oscillator) s.getValue()).isPlaying()) { curr_sostenuting.add(s.getKey()); } } @@ -234,8 +217,8 @@ public class ChannelOsc { void set_all_oscs_amp() { - for (RTSoundObject s : current_notes.values()) { - s.amp((osc_type == 1 || osc_type == 2 ? 0.12 : 0.05) * curr_global_amp * amp_multiplier * (soft_pedal ? 0.5 : 1) * last_amp); + for (SoundObject s : current_notes.values()) { + ((Oscillator) s).amp((osc_type == 1 || osc_type == 2 ? 0.12 : 0.05) * curr_global_amp * amp_multiplier * (soft_pedal ? 0.5 : 1) * last_amp); } } @@ -247,9 +230,9 @@ public class ChannelOsc { curr_global_bend = map(value, 0, 16383, -1.0, 1.0) * curr_bend_range; bend_freq_ratio = (float) Math.pow(2, curr_global_bend / 12.0); - for (Entry s_pair : current_notes.entrySet()) { + for (Entry s_pair : current_notes.entrySet()) { float new_freq = midi_to_freq(s_pair.getKey() + curr_noteDetune) * bend_freq_ratio; - s_pair.getValue().freq(new_freq + curr_freqDetune); + ((Oscillator) s_pair.getValue()).freq(new_freq + curr_freqDetune); last_freq = new_freq; } } @@ -258,7 +241,7 @@ public class ChannelOsc { void set_pan(int value) { curr_global_pan = map(value, 0, 127, -1.0, 1.0); - for (RTSoundObject s : current_notes.values()) { + for (SoundObject s : current_notes.values()) { s.pan(curr_global_pan); } } @@ -268,7 +251,6 @@ public class ChannelOsc { if (how) shut_up(); disp.button_mute.set_pressed(how); silenced = how; - } @@ -276,7 +258,7 @@ public class ChannelOsc { set_hold(0); set_sostenuto(0); set_soft(0); - for (int note_code : current_notes.keySet()) stop_note(note_code, true); + for (int note_code : current_notes.keySet()) stop_note(note_code); } diff --git a/LabsModule.pde b/LabsModule.pde index ea34d19..e4443df 100644 --- a/LabsModule.pde +++ b/LabsModule.pde @@ -10,8 +10,8 @@ public class LabsModule extends PApplet { public void settings() { - if (osname.contains("Windows")) this.size(210, 404); - else this.size(210, 360); + if (osname.contains("Windows")) this.size(210, 324); + else this.size(210, 280); } @@ -45,11 +45,7 @@ public class LabsModule extends PApplet { b4.show_label = false; Button b6 = new Button("midiIn", "midiIn"); b6.show_label = false; - Button b8 = new Button("rtEngine", "rtEngine"); - b8.show_label = false; - Button b9 = new Button("demoUi", "demoUi"); - b9.show_label = false; - Button[] bs = new Button[] {b1, b2, b3, b7, b4, b6, b8, b9}; + Button[] bs = new Button[] {b1, b2, b3, b7, b4, b6}; all_buttons = new ButtonToolbar(8, 45, 0, 1.4, bs); } @@ -138,51 +134,6 @@ public class LabsModule extends PApplet { if (!player.midi_in_mode) player.start_midi_in(); else player.stop_midi_in(); } - - else if (all_buttons.collided("rtEngine", this)) { - player.shut_up_all(); - NO_REALTIME = !NO_REALTIME; - } - - else if (all_buttons.collided("demoUi", this)) { - Form form = ui.createForm("Customize demo UI") - .addText("Title") - .addTextArea("Description") - .addText("Format") - .addSelection( - "Pulse 1 width", - Arrays.asList("Unchanged", "0.125", "0.25", "0.5", "0.75") - ) - .addSelection( - "Pulse 2 width", - Arrays.asList("Unchanged", "0.125", "0.25", "0.5", "0.75") - ) - .addButton("Toggle demo UI", new Runnable() { public void run() { - ui.showInfoDialog("Setting will take effect on next program restart."); - config_map.put("demoable uiserver", demo_ui ? "0" : "1"); - save_config(); - }}) - .setCloseListener(new FormCloseListener() { public void onClose(Form form) { - String t = form.getByIndex(0).asString(); - String d = form.getByIndex(1).asString(); - String f = form.getByIndex(2).asString(); - String w1 = (String) form.getByIndex(3).getValue(); - String w2 = (String) form.getByIndex(4).getValue(); - - if (!t.equals("")) demo_title = t; - if (!d.equals("")) demo_description = d; - if (!f.equals("")) demo_layout = f; - if (!w1.equals("Unchanged")) player.channels[0].set_osc_type(Float.parseFloat(w1)); - if (!w2.equals("Unchanged")) player.channels[1].set_osc_type(Float.parseFloat(w2)); - }}) - .run(); - - form.getByIndex(0).setValue(demo_title); - form.getByIndex(1).setValue(demo_description); - form.getByIndex(2).setValue(demo_layout); - - form.getWindow().setSize(240, 520); - } } //this.redraw_all(); @@ -195,9 +146,7 @@ public class LabsModule extends PApplet { all_buttons.collided("tempo", this) || all_buttons.collided("overrideOscs", this) || all_buttons.collided("transform", this) || - all_buttons.collided("midiIn", this) || - all_buttons.collided("rtEngine", this) || - all_buttons.collided("demoUi", this) + all_buttons.collided("midiIn", this) ) { this.cursor(HAND); } @@ -229,7 +178,6 @@ public class LabsModule extends PApplet { //this.text("x", 179, 177); this.text(curr_transform, 179, 216); this.text((player.midi_in_mode ? "On" : "Off"), 179, 255); - this.text((NO_REALTIME ? "Off" : "On"), 179, 294); all_buttons.redraw(this); } diff --git a/P3synth.pde b/P3synth.pde index 4bc69ea..e006131 100644 --- a/P3synth.pde +++ b/P3synth.pde @@ -25,6 +25,7 @@ PFont[] fonts; SoundFile[] samples; ThemeEngine t; boolean showed_sf_tip = false; +boolean is_newbie = false; ButtonToolbar media_buttons; ButtonToolbar setting_buttons; Button b_meta_msgs; @@ -147,11 +148,12 @@ void load_config(boolean just_opened) { } catch (FileNotFoundException fnfe) { println("load fnfe"); + is_newbie = true; ui.showInfoDialog( "Welcome! Please check your audio levels.\n\n" + "For help on advanced usage, check the HELP button or\n" + - "the project's website at https://vlcoo.github.io/p3synth\n" + "the project's website at https://vlcoo.net/p3synth\n" ); save_config(); } @@ -342,10 +344,11 @@ void mouseReleased() { "Drag and drop a new MIDI file to play.\n" + "REPLAY: skip back to the beginning of the song.\n" + "PAUSE: pause any playing music or resume if paused.\n" + - "EXIT: safely close the program.\n\n" + + "STOP: unload the file.\n\n" + "The Labs menu has experimental playback/tinkering options!\n" + - "The buttons on the other side provide some info and configs.\n\n" + + "The buttons on the other side provide some info and configs.\n" + + "Try loading a soundfont file by dropping it into the upper right box!\n\n" + "Left click the X on any channel to mute it, or right click it to solo.\n" + "You can use the lower left rectangle to control the song's position.\n" + @@ -420,7 +423,7 @@ void mouseReleased() { } else if (player.disp.collided_sfload_rect()) { - if (!player.system_synth && player.sf_filename.equals("Default") && !showed_sf_tip) { + if (is_newbie && !showed_sf_tip && !player.system_synth && player.sf_filename.equals("Default")) { ui.showWarningDialog( "Bonus: drag and drop SF2/DLS file in that box to load it!\n", "Switching modes" diff --git a/Player.pde b/Player.pde index 6b74d32..8fea2b6 100644 --- a/Player.pde +++ b/Player.pde @@ -161,6 +161,11 @@ class Player { String play_file(String filename) { + return play_file(filename, false); + } + + + String play_file(String filename, boolean keep_paused) { if (midi_in_mode) stop_midi_in(); File file = new File(filename); if (system_synth) try_match_soundfont(filename); @@ -174,7 +179,7 @@ class Player { midi_resolution = mid.getResolution(); curr_filename = filename; setTicks(0); - set_playing_state(1); + set_playing_state(keep_paused ? 0 : 1); } catch(InvalidMidiDataException imde) { return "Invalid MIDI data!"; @@ -287,9 +292,8 @@ class Player { if (playing_state_before >= 0) { prep_javax_midi(); - play_file(prev_filename); + play_file(prev_filename, playing_state_before == 0); // keep paused if it was setTicks(prev_ticks); - if (playing_state_before == 0) set_playing_state(0); // keep paused if it was } } diff --git a/RTSoundObject.pde b/RTSoundObject.pde deleted file mode 100755 index 062763a..0000000 --- a/RTSoundObject.pde +++ /dev/null @@ -1,123 +0,0 @@ -/** crude but good enough implementation of a SoundObject - * that supports amp attack-sustain-release envelope - * and frequency modulation - */ -class RTSoundObject { - Oscillator osc; - int playing = 0; - int osc_type; - float amp = 1.0; - float freq = 0.0; - float enved_amp = 0.0; - float modded_freq = 0.0; - - int amp_env_start_ticks = 1; // attack duration - float amp_env_start_mod = 0.8; // attack strength - float amp_env_mid_amp = 0.8; // sustain amplitude - int amp_env_end_ticks = 6; // release duration - float amp_env_end_mod = 0.1; // release strength - - float freq_mod_mod = 0.25; // modulation strength - int freq_mod_startafter = 16; // modulation delay - float freq_mod_limit = 0.5; // modulation bounds - - int amp_env_start_curtick = 0; - int amp_env_end_curtick = 0; - int freq_mod_curtick = 0; - int freq_mod_curdir = 1; - - - RTSoundObject(Oscillator osc) { - this.osc = osc; - } - - - void tick() { - if (NO_REALTIME || playing == 0) return; - - if (freq_mod_curtick >= freq_mod_startafter) { - modded_freq += freq_mod_mod * freq_mod_curdir; - if (modded_freq > freq + freq_mod_limit || modded_freq < freq - freq_mod_limit) freq_mod_curdir *= -1; - osc.freq(modded_freq); - } - - if (playing == 1) { - if (amp_env_start_curtick <= amp_env_start_ticks) { - enved_amp += amp_env_start_mod; - amp_env_start_curtick++; - } - else if (enved_amp != amp_env_mid_amp) enved_amp = amp_env_mid_amp; - osc.amp(constrain(enved_amp, 0, 1) * amp); - } - - else if (playing == -1) { - if (amp_env_end_curtick <= amp_env_end_ticks) { - enved_amp -= amp_env_end_mod; - amp_env_end_curtick++; - osc.amp(constrain(enved_amp, 0, 1) * amp); - } - else { - osc.stop(); - playing = 0; - reset_mods_and_envs(); - } - } - - freq_mod_curtick++; - } - - - void freq(float f) { - this.freq = f; - this.modded_freq = f; - freq_mod_curdir = 1; - freq_mod_curtick = 0; - osc.freq(f); - } - - - void pan(float p) { - osc.pan(p); - } - - - void amp(float a) { - this.amp = a; - if (NO_REALTIME) osc.amp(a); - else this.enved_amp = a; - } - - - void reset_mods_and_envs() { - osc.freq(freq); - enved_amp = 0; - modded_freq = freq; - amp_env_start_curtick = 0; - amp_env_end_curtick = 0; - freq_mod_curdir = 1; - freq_mod_curtick = 0; - } - - - void play() { - reset_mods_and_envs(); - if (NO_REALTIME) osc.amp(amp); - else osc.amp(0); - osc.play(); - playing = 1; - } - - - void stop() { - stop(false); - } - - - void stop(boolean force) { - if (force || NO_REALTIME) { - osc.stop(); - reset_mods_and_envs(); - } - else playing = -1; - } -}