#!/usr/bin/python
# -*- coding: utf-8 -*-
# beep-play
# Author: DarkRanger <darkranger.no-ip.org>
# Version: 20151022
# License: GNU General Public License

import os, sys, platform, subprocess, time

HELP = '''Usage:
$ sudo ./beep-play.py <DURATION> <TABLE-OF-FREQUENCIES.TXT> <NOTATION.TXT>
Example:
$ sudo ./beep-play.py 200 table.txt demo.txt
$ beep-play.exe 200 table.txt demo.txt
'''

def read_notes(path):
    notes = []
    if os.path.isfile(path):
        txt = open(path, "r")
        for line in txt.readlines():
            if not line.startswith("#"):
                for note in line.split():
                    notes.append(note.strip())
        txt.close()
    return notes

def read_freqs(path):
    freqs = {}
    if os.path.isfile(path):
        txt = open(path, "r")
        for line in txt.readlines():
            if not line.startswith("#"):
                pair = line.split()
                if len(pair) >= 2:
                    try:
                        freqs.update({pair[0].strip():float(pair[1].strip())})
                    except:
                        pass
        txt.close()
    return freqs

def get_duration(initial_duration, note):
    multiplier = note.count("-")
    if multiplier != 0:
        duration = initial_duration * 2.05 * multiplier
        return duration
    else:
        return initial_duration

def get_freq(note, freqs):
    freq = 0
    note = note.replace("-", "")
    if note in freqs:
        freq = freqs[note]
    return freq

def show_progress(pointer, total):
    sys.stdout.write("\r%d/%d" % (pointer, total))
    sys.stdout.flush()
    if pointer == total:
        print("")

def show_progress_bar(pointer, total):
    percentage = pointer * 100 / total
    brick = "=" * int(percentage / 5)
    sys.stdout.write("\r[%s](%d%%)" % (brick.ljust(20), percentage))
    sys.stdout.flush()
    if pointer == total:
        print("")

def winsound_wrapper(initial_duration, freqs, notes):
    import winsound
    total = len(notes)
    pointer = 0
    for note in notes:
        freq = get_freq(note, freqs)
        duration = get_duration(initial_duration, note)
        pointer =  pointer + 1
        show_progress(pointer, total)
        if freq != 0:
            winsound.Beep(int(freq), int(duration))
        else:
            time.sleep(duration / 1000) 

def beep_wrapper(initial_duration, freqs, notes):
    lsmod_process = subprocess.Popen(["lsmod | grep pcspkr"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    msg, error = lsmod_process.communicate()
    total = len(notes)
    pointer = 0

    if "pcspkr" in msg.decode():
        for note in notes:
            freq = get_freq(note, freqs)
            duration = get_duration(initial_duration, note)
            pointer =  pointer + 1
            show_progress(pointer, total)
            if freq != 0:
                beep_process = subprocess.Popen(["beep -f %f -l %d" % (freq, duration)], shell=True, stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
                msg, error = beep_process.communicate()
                if error:
                    print(error)
                    break
            else:
                time.sleep(duration / 1000)
    else:
        print("Module 'pcspkr' is not loaded, use 'sudo modprobe pcspkr' to load the module.")
    
def beep_play():
    if len(sys.argv) >= 4 and sys.argv[1].isdigit():
        initial_duration = float(sys.argv[1])
        freqs = read_freqs(sys.argv[2])
        notes = read_notes(sys.argv[3])

        if platform.system() == "Windows":
            winsound_wrapper(initial_duration, freqs, notes)
        else:
            beep_wrapper(initial_duration, freqs, notes)
    else:
        print(HELP)

if __name__ == "__main__":
   beep_play()

