Skip to content

Instantly share code, notes, and snippets.

@ancientstraits
Created November 10, 2024 18:13
Show Gist options
  • Select an option

  • Save ancientstraits/0c220d40f9868e294388f1b8ba26ed13 to your computer and use it in GitHub Desktop.

Select an option

Save ancientstraits/0c220d40f9868e294388f1b8ba26ed13 to your computer and use it in GitHub Desktop.

Revisions

  1. ancientstraits created this gist Nov 10, 2024.
    158 changes: 158 additions & 0 deletions main.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,158 @@
    import wave
    from pathlib import Path
    import json
    import time
    import sys
    import keyboard
    import pyaudio

    writing = False
    reverse = False
    reverse_key = {}
    paused = False
    pause_time = 0.0
    poses = {}
    is_pressed = {}

    def n_samples_to_time(n_samples, sample_rate):
    total_secs = n_samples / sample_rate
    mins = total_secs // 60
    secs = total_secs % 60
    subsecs = (secs * 100) % 100
    return f'{int(mins)}:{int(secs)}.{int(subsecs)} '

    def pressed(key):
    if keyboard.is_pressed(key):
    if key in is_pressed and is_pressed[key]:
    return False
    else:
    # print(key)
    is_pressed[key] = True
    return True
    else:
    if key in is_pressed and is_pressed[key]:
    # print('no', key)
    is_pressed[key] = False
    return False
    def num_pressed():
    for i in range(10):
    if pressed(str(i)):
    return str(i)
    return False

    def reverse_audio(audio, sample_size, chunk_size):
    ret = b''
    for i in range(sample_size*chunk_size, 0, -sample_size):
    ret += audio[i-sample_size:i]
    return ret

    CHUNK = 1024

    if len(sys.argv) < 3:
    print(f'Plays a wave file. Usage: {sys.argv[0]} infile.wav outfile.wav')
    sys.exit(-1)

    # load positions from save file
    save_file_path = sys.argv[1] + '.json'
    if Path(save_file_path).exists():
    with open(save_file_path, 'r') as f:
    arr = json.loads(f.read())
    for entry in arr:
    poses[entry['key']] = entry['offset']
    reverse_key[entry['key']] = entry['reverse']

    out = wave.open(sys.argv[2], 'wb')

    with wave.open(sys.argv[1], 'rb') as wf:
    out.setnchannels(wf.getnchannels())
    out.setsampwidth(wf.getsampwidth())
    out.setframerate(wf.getframerate())

    # Instantiate PyAudio and initialize PortAudio system resources (1)
    p = pyaudio.PyAudio()

    # Open stream (2)
    stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
    channels=wf.getnchannels(),
    rate=wf.getframerate(),
    output=True)

    # Play samples from the wave file (3)
    while True:
    print(f'\r{n_samples_to_time(wf.tell(), wf.getframerate())}', end='')
    if not paused:
    data = wf.readframes(CHUNK)
    if not len(data):
    break
    if reverse:
    data = reverse_audio(data, wf.getsampwidth()*wf.getnchannels(), CHUNK)
    stream.write(data)
    if writing:
    out.writeframes(data)

    if reverse:
    pos = wf.tell() - 2*CHUNK
    if pos < 0:
    reverse = False
    pos = 0
    wf.setpos(pos)

    if pressed('esc'):
    break
    if pressed('space'):
    if paused and writing:
    out.writeframes(b'\x00' * wf.getsampwidth() * wf.getnchannels() * round(
    wf.getframerate() * (time.time() - pause_time)
    ))
    else:
    pause_time = time.time()
    paused = not paused

    if pressed('r'):
    reverse = not reverse
    if pressed('w'):
    writing = not writing
    if writing:
    print('Writing started')
    else:
    print('Writing stopped')

    seek_mul = 5 if keyboard.is_pressed('shift') else 1
    if pressed('a'):
    pos = wf.tell() - seek_mul*wf.getframerate()
    if pos < 0:
    pos = 0
    wf.setpos(pos)
    if pressed('d'):
    pos = wf.tell() + seek_mul*wf.getframerate()
    if (pos >= wf.getnframes()):
    pos = wf.getnframes() - 1
    wf.setpos(pos)

    num = num_pressed()
    if not num:
    continue
    # print('OOOOOOOOOOOOO')
    if keyboard.is_pressed('ctrl'):
    pos = wf.tell()
    print(f'poses[{num}] = {pos}')
    poses[num] = pos
    reverse_key[num] = reverse
    elif (num in poses) and poses[num]:
    reverse = reverse_key[num]
    wf.setpos(poses[num])

    # Close stream (4)
    stream.close()

    # Release PortAudio system resources (5)
    p.terminate()

    out.close()

    json_arr = []
    for key in poses:
    json_arr.append({'key': key, 'offset': poses[key], 'reverse': reverse_key[key]})
    with open(save_file_path, 'w') as f:
    f.write(json.dumps(json_arr))