extends Control var sample_hz = 22050.0 # Keep the number of samples to mix low, GDScript is not super fast. var pulse_hz = 440.0 * 2 var phase = 0.0 var morse_state := false var playback: AudioStreamPlayback = null var vol_on := -30 func _process(_delta): fill_buffer() func fill_buffer(): var increment = pulse_hz / sample_hz var frames_available = playback.get_frames_available() for i in range(frames_available): playback.push_frame(Vector2.ONE * sin(phase * TAU)) phase = fmod(phase + increment, 1.0) func _ready(): $Player.stream.mix_rate = sample_hz $Player.volume_db = -100 $Player.play() playback = $Player.get_stream_playback() fill_buffer() OS.open_midi_inputs() print(OS.get_connected_midi_inputs()) func set_morse_state(state: bool): MorseState.set_state(state) morse_state = state if state: %ColorRect.color = Color(0, 128, 0) $Player.volume_db = vol_on else: %ColorRect.color = Color(0, 0, 0) $Player.volume_db = -100 func _on_morse_button_down() -> void: set_morse_state(true) func _on_morse_button_up() -> void: set_morse_state(false) func _input(input_event): if input_event is InputEventMIDI: _process_midi_event(input_event) func _process_midi_event(midi_event): if midi_event.channel in [0, 9]: if midi_event.message == MIDI_MESSAGE_NOTE_ON: set_morse_state(true) elif midi_event.message == MIDI_MESSAGE_NOTE_OFF: set_morse_state(false) #print(midi_event) #print("Channel ", midi_event.channel) #print("Message ", midi_event.message) #print("Pitch ", midi_event.pitch) #print("Velocity ", midi_event.velocity) #print("Instrument ", midi_event.instrument) #print("Pressure ", midi_event.pressure) #print("Controller number: ", midi_event.controller_number) #print("Controller value: ", midi_event.controller_value) func _make_tone(freq_hz: float, length: float, sample_rate: int, amplitude: int): var result: Array[int] = [] var _phase := 0.0 var increment: float = freq_hz / float(sample_rate) for i in range(round(sample_rate * length)): result.append(int(round(sin(_phase * TAU) * amplitude))) _phase = fmod(_phase + increment, 1.0) return result func _on_wav_button_pressed() -> void: var data: Array[int] = [] var _use_test_data := false var amp := 100 if not _use_test_data: data.append_array(_make_tone(0, 0.2, sample_hz, amp)) var _morse_on := true for n in range(1, MorseState.states.size()): var _freq = pulse_hz if _morse_on else 0.0 print(_freq, " of length ", MorseState.states[n] / 1000.0) data.append_array(_make_tone(_freq, MorseState.states[n] / 1000.0, sample_hz, amp)) _morse_on = not _morse_on data.append_array(_make_tone(0, 0.2, sample_hz, amp)) else: data.append_array(_make_tone(pulse_hz, 0.5, sample_hz, 100)) data.append_array(_make_tone(0, 0.5, sample_hz, 100)) data.append_array(_make_tone(pulse_hz, 0.5, sample_hz, 100)) data.append_array(_make_tone(0, 0.5, sample_hz, 100)) data.append_array(_make_tone(pulse_hz, 0.5, sample_hz, 100)) # save wav var wav := AudioStreamWAV.new() wav.format = AudioStreamWAV.FORMAT_8_BITS wav.mix_rate = sample_hz wav.stereo = false wav.data = data print("Writing WAV with ", data.size(), " length") var proposed_fname := "morse-" + Time.get_datetime_string_from_system(true) + ".wav" match OS.get_name(): ["Linux", "macOS", "Windows"]: wav.save_to_wav("/tmp/foo.wav") "Android": print("Whaaat") "Web": print("download") # we either write our own wave header method or we use a temporary file # FIXME: find out if we have our own temp / if our filename needs to be random var tmp_file := "/tmp/morse.wav" wav.save_to_wav(tmp_file) # var wav_file := FileAccess.open(tmp_file, FileAccess.READ) var wav_data := FileAccess.get_file_as_bytes(tmp_file) JavaScriptBridge.download_buffer(wav_data, proposed_fname, "audio/vnd.wave") var platform: print("Saving not supported on platform " + platform) func _on_reset_button_pressed() -> void: MorseState.reset()