diff --git a/Live player/LICENSE.md b/Live player/LICENSE.md new file mode 100644 index 0000000..46827dd --- /dev/null +++ b/Live player/LICENSE.md @@ -0,0 +1,28 @@ +Chorizo.py : +==== + +This script allows you to play music using a chorizo (or whatever food you +like) keyboard ! See README for more info and links. + +As all the other scripts in this repository, I release it under a very +permissive license. To make a long story short : do whatever you want with +this script (but try to have fun :), I don't mind. It would be cool to quote +the origin of the script if you reuse it, but you don't have to. I'd like to +be noticed of what you did cool with it (if you think it's worth). :) +Ah, I almost forgot : If by chance we ever meet and you think this script is +worth, you can buy me a soda :) + + Phyks + + +Sound4Python.py : https://github.com/standarddeviant/sound4python +==== +Note : The version of sound4python.py in this project is slightly modified (some print statements commented and a bugfix). + +Copyright (C) 2013 dave.crist@gmail.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Live player/player.py b/Live player/player.py new file mode 100755 index 0000000..4eacbe0 --- /dev/null +++ b/Live player/player.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +# ============================================================================ +# This script allows you to play music using a chorizo (or whatever food you +# like) keyboard ! See README for more info and links. + +# As all the other scripts in this repository, I release it under a very +# permissive license. To make a long story short : do whatever you want with +# this script (but try to have fun :), I don't mind. It would be cool to quote +# the origin of the script if you reuse it, but you don't have to. I'd like to +# be noticed of what you did cool with it (if you think it's worth). :) +# Ah, I almost forgot : If by chance we ever meet and you think this script is +# worth, you can buy me a soda :) +# +# Phyks +# ============================================================================= + +from sound4python import sound +from multiprocessing import Process +import math + +class _Getch: + """Gets a single character from standard input. Does not echo to the +screen.""" + def __init__(self): + try: + self.impl = _GetchWindows() + except ImportError: + self.impl = _GetchUnix() + + def __call__(self): return self.impl() + + +class _GetchUnix: + def __init__(self): + import tty, sys + + def __call__(self): + import sys, tty, termios + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + + +class _GetchWindows: + def __init__(self): + import msvcrt + + def __call__(self): + import msvcrt + return msvcrt.getch() + +getch = _Getch() + +def play_wave(frequency=440, nb_secs=1.): + sine_wave = [] + for i in range(math.ceil(nb_secs*framerate)+1): + sine_wave.append(int(16384*math.sin(2*math.pi*frequency*i/framerate))) + + sound(sine_wave) + +framerate = 16000 +processes = [] +frequency = 440 + +print("Running... Press q to quit.") +running = True +while running: + char = getch() + if char == "q": + running = False + continue + elif char == "a": + frequency = 440 + elif char == "b": + frequency = 493.88 + elif char == "c": + frequency = 523.25 + elif char == "d": + frequency = 587.33 + elif char == "e": + frequency = 659.26 + elif char == "f": + frequency = 698.46 + elif char == "g": + frequency = 783.99 + else: + continue + + print("Playing "+char.upper()) + processes.append(Process(target=play_wave, args=(frequency, 0.2))) + processes[-1].start() + +for i in processes: + i.join() diff --git a/Live player/sound4python.py b/Live player/sound4python.py new file mode 100644 index 0000000..fff9450 --- /dev/null +++ b/Live player/sound4python.py @@ -0,0 +1,99 @@ + +try: import tempfile, wave, subprocess, os, signal, struct +except: + print("E: sound4python is unable to import a combination of %s"% + ("tempfile, wave, subprocess, os, signal, struct")) + +FNULL = open(os.devnull,'w') +def launchWithoutConsole(args,output=False): + """Launches args windowless and waits until finished""" + startupinfo = None + if( 'STARTUPINFO' in dir(subprocess) ): + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + if( output ): + return subprocess.Popen(args, stdin=subprocess.PIPE, + stdout=subprocess.PIPE,startupinfo=startupinfo, ) + else: + return subprocess.Popen(args, stdin=subprocess.PIPE, + stdout=FNULL ,stderr=FNULL, startupinfo=startupinfo) + +# sound4python +def sound(itr,samprate=16000,autoscale=True,output=False): + try: import numpy as np; foundNumpy=True; + except: + foundNumpy=False; + + #for now, assume 1-D iterable + mult = 1 + if( autoscale ): + mult = 32767.0 / max(itr) + #mult = 128.0 / max(itr) + + #create file in memory + #with tempfile.SpooledTemporaryFile() as memFile: + memFile = tempfile.SpooledTemporaryFile() + + #create wave write objection pointing to memFile + waveWrite = wave.open(memFile,'wb') + waveWrite.setsampwidth(2) # int16 default + waveWrite.setnchannels(1) # mono default + waveWrite.setframerate(samprate) # 8kHz default + + wroteFrames=False + #Let's try to create sound from NumPy vector + if( foundNumpy ): + if( type(itr)==np.array ): + if( itr.ndim == 1 or itr.shape.count(1) == itr.ndim - 1 ): + waveWrite.writeframes( (mult*itr.flatten()).astype(np.int16).tostring() ) + wroteFrames=True + else: #we have np, but the iterable isn't a vector + waveWrite.writeframes( (mult*np.array(itr)).astype(np.int16).tostring() ) + wroteFrames=True + if( not wroteFrames and not foundNumpy ): + #python w/o np doesn't have "short"/"int16", "@h" is "native,aligned short" + # BAD : waveWrite.writeframes( struct.pack(len(itr)*"@h",[int(mult*itm) for itm in itr]) ) + writeValues = [] + for itm in itr: + packed_value = struct.pack('h', int(mult*itm)) + waveWrite.writeframes(packed_value) + + wroteFrames=True + + if( not wroteFrames ): + print("E: Unable to create sound. Only 1D numpy arrays and numerical lists are supported.") + waveWrite.close() + return None + + #configure the file object, memFile, as if it has just been opened for reading + memFile.seek(0) + + try: + # getting here means wroteFrames == True + #print("\nAttempting to play a mono audio stream of length") + #print(" %.2f seconds (%.3f thousand samples at sample rate of %.3f kHz)"% + # ( 1.0*len(itr)/samprate , len(itr)/1000. , int(samprate)/1000.) ) + p=launchWithoutConsole(['sox','-','-d']) + except: + print("E: Unable to launch sox.") + print("E: Please ensure that sox is installed and on the path.") + print("E: Try 'sox -h' to test sox installation.") + waveWrite.close() + return None + + try: + p.communicate(memFile.read()) + p.wait() + except: + print("E: Unable to send in-memory wave file to stdin of sox subprocess.") + waveWrite.close() + return None + #os.kill(p.pid,signal.CTRL_C_EVENT) +#end def sound(itr,samprate=8000,autoscale=True) + + + + + + + diff --git a/README.md b/README.md index 1f83c49..d31522e 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ This is just a simple C code to handle wave files (see files wave_stuf.* for the * _generateur.c_ which is the main program * _generateur_musicsheet.py_ which is just a simple program to generate basic music sheet to use with the main program * _wave_stuff.*_ which are the functions to handle wave files +* _Live_player/*_ : a python script to play music in live, using a, b, c, d, e, f and g keys on your keyboard. ## Usage of the main program