Giter VIP home page Giter VIP logo

melopy's People

Contributors

asteriskman7 avatar b1naryth1ef avatar caoilteguiry avatar gal-leib avatar jdan avatar kylepreston avatar parent5446 avatar scubbo avatar timgates42 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

melopy's Issues

Render status

I would love to see an implementation of a status bar for when a song is rendering. However, I think something like printing "10% done! 20% done!" is ugly. Is it possible to draw a static textbar on console? Similar to how something like wget looks when you fetch data from the web.

Syntax for writing music using Melopy

So an idea I've had for a while...

I now want to bring to life. The main purpose of Melopy was too allow me to write melodies with python code. This looks great with Melopy's functions, but I'm looking to add something cool to utility - a parser for a new syntax used for writing music.

Goal

It started with the idea of Mary Had a Little Lamb.

4|EDCDEEE-DDD-EGG-EDCDEEEEDDEDC

What does this do? First it read's the octave. 4. Then a pipe - then some notes. The letters will correspond to notes in the pre-defined octave, and dashes represent rests. From here I decided to conjure up a sort of syntax.

Basics

From here I decided that each new line could be read as a change in octave. For instance, if we were to play the C major scale...

4|CDEFGAB
5|C

We would need to jump to the 5th octave. We do this by going to the next line, defining the octave again, and continuing to write our notes.

So what kind of notes are these? Well, like music - I wanted the "default" so-to-speak to be quarter notes. From here, we could shorten them, or make them longer. As follows.

  • nothing - a quarter note example: ABC
  • () - half the time. meaning A(BC) is a quarter note A followed by two eighth notes, B and C
    • (()) - one quarter the time. we can have various levels of parenthesis to make faster notes.
  • - double the time. [A] becomes a half-note A and [[D]] becomes a whole note D
    • Both apply to rests. ((-)) is a sixteenth rest and [-] is a half rest.
  • { } - grouped notes become a chord. {DF#A} would correspond to D major
  • || - double pipe allows you to change octave without entering a new line
    • 4|{A||5|E}||4| ... corresponds to A major (see how we had to jump an octave? (and come back)

Future

That's all I have for now as far as syntax goes. We need to add things that allow you to define the waveform, title, etc before the actual notes. This is a design decision that needs to be made. We also need syntax for ties.

The important thing is to be very thorough in your documentation.

As far as a file goes, I believe this should be placed in utility.py as the method parse()

Readme major_scale example is wrong

The readme has an example that uses melopy.major_scale('C5') but there is no major_scale function. I think this should be something like melopy.generateScale('major', 'C5').

I will be happy to fix this if someone can confirm that I'm not just missing something.

If no one replies in a week or so I'll assume I'm right and make the change.

Live Playing

We need to make a play() or sample() method which gives Melopy that capabilities of playing sound right from .data. This shouldn't be terribly hard to achieve, considering programs like Audacity do it without issue. Any ideas?

Setup.py

Do we need it? All it has done for me so far is create a headache.

ImportError: Cannot import name find_packages

So I made myself a clone of Melopy and downloaded it onto my windows and Linux machine. Whenever I try to use setup.py it spits back an error!

"Traceback (most recent call last):
File "setup.py", line 7, in
from distutils.core import setup, find_packages
ImportError: cannot import name find_packages"

Anyone know whats going on? I just wanted to mess around with it, I'm not a python wizard!

Strange behavior from 'examples'

Consider the following code.

from melopy import * 

m = Melopy()
print m.volume

Since volume defaults to 50, the following should print 50. If we direct ourselves to the project root directory and run this code. It works perfectly.

However, if we navigate into the examples/ directory and run this code, the output is 16383.5. I cannot for the life of me figure out why this is happening.

meep examples don't work when executed from examples dir

On my machine __file__ returns just the filename when called from the examples dir so

m.parsefile(os.path.dirname(__file__) + '/meeps/furelise.mp')

results in /meeps/furelise.mp which does not exist.

A better way would be:

m.parsefile(os.path.abspath('./meeps/furelise.mp'))

Clicks in audio output

When notes are rendered, their wave data is added for some number of samples and then stopped. If the last sample rendered for a note has a large amplitude, this can result in adjacent samples with very large differences. This produces a click in the audio.

Section 2 of this page describes the problem with some helpful images: https://ask.audio/articles/5-mistakes-to-avoid-when-editing-audio

Two potential solutions:

  1. Continue rendering a note until it gets to some low threshold where a click will not occur. This could extend notes by nearly 1/2 the note period in the worst case (around 1/20th of a second for low notes?). Need protection against a situation where a note frequency is high relative to the sampling frequency and it takes multiple periods (if ever) before you get a low amplitude sample.

  2. Fade every note to zero over the last few samples. Depending on how many samples is necessary to fix the problem, this could change the character of the note in an undesirable way.

Idea: Added return types

I posted this on the reddit thread, but I thought I'd dump it in here too just to gauge the response of those not on the reddit thread. It might be a smart idea to allow people to choose an output, as final objects are sometimes useful. It's not really that big of a deal, nor is it a dealbreaker in overhead/runtime, just an extra if statement.

Like so:

def generate_minor_triad(start,returnType="list"):
    """Generates a minor triad using the pattern [3,4] (Returns: List)"""
    minor_triad = [3, 4]
    output = iterate(start, minor_triad)
    if returnType == 'list':
        return output
    elif returnType == 'tuple':
        return tuple([i for i in y])

need triplets (and other divisions of the beat)

nice work!

my first thought on reading through the syntax was... how do you do triplets? the halving/doubling thing is a clever simplification and other multiples like 5 etc are more rare, but triplets are pretty essential.

I thought maybe you could get by with just a { } operator... say you're currently counting in 'quarter notes', then { } would give you quarter-note triplets and [{ ... }] would give you eighth-note triplets etc.

In replying to my other comment you suggested a syntax like {3}( ... ). I would interpret this maybe as a way to specify the multiple of the following brackets, i.e. {2} is the default if not specified. Reading about triplets they actually represent 'three notes in the space of two', i.e. a multiple of 1.5.

But reading more about things like quintuplets, conventional notation allows more awkward fractions such as 5/3... at which point you wouldn't want to use a 'floating point' type of syntax.

So that would suggest (based on your example) something like {3,2}[ ... ] for triplets. But then what would {3,2}( ... ) mean? If behind the scenes we're converting that syntax to a calculation like (3/2) * x or (3/2) / x it turns out only one of those gives a musically relevant answer. To get slower triplets correctly you'd have to do ({3,2}[ ... ]).

So maybe the 'fractional brackets' should be restricted to use with square 'speed up' brackets only, or not even associated with either [ ] or ( ) brackets at all, to avoid confusion.

So I would come back around to { ... } 'triplet brackets' as shorthand, with an extended syntax like maybe {5/3: ... } for weirder subdivisions.

README.md no longer corresponds to project set up

>>> # Returns the frequency of the note (key) keys from A0
>>> melopy.frequency_from_key(49)
440

>>> # Returns the frequency of a note represented by a string
>>> melopy.frequency_from_note('A4')
440

As you can see, the README is outdated. We have since divided the project into 3 sub-categories, melopy, scales, and utility.

The README must change accordingly

  • melopy.py contains the Melopy class - we use this for generating noise
  • scales.py contains methods for generating arrays of scales, chords, etc.
  • utility.py contains operations for determining the frequency of a given note, the note from a given key, etc.

We should subdivide the README accordingly.

License?

I am completely unfamiliar with open-source licenses, but I have seen some developers get MIT licenses before anyone else even touches their project. Maybe getting one might not be such a bad idea? What's the process?

[minor] Scale generation doesn't work properly

The reason I've marked this as minor is that anyone with a good music theory background should be able to fix this pretty quickly.

>>> from melopy.scales import *
>>> minor_scale('C')
['C4', 'D4', 'D#4', 'F4', 'G4', 'G#4', 'A#4']
>>> 

As you can see here, Melopy determines that D and D# are both in C minor. This is technically correct, but the real way to write this would be to use D and then Eb. The same goes for Ab instead of G#. Essentially, the rule of thumb is that the same letter can't appear twice in a scale. The error lies in our iterate() method in scales.py.

def iterate(start, pattern, rType="list"):
    """Iterates over a pattern starting at a given note"""
    start_key = key_from_note(start)
    ret = [start_key]
    for step in pattern:
        ret.append(ret[-1] + step)
    ret = map(note_from_key, ret)
    return bReturn(ret, rType)

All we need is to implement an error check that prevents the same letter from appearing twice.

Fix/refactor tests

Tests are very minmal and seem to bring out a odd nose bug. It would be a good idea to refactor. I'd be more then happy to work on this. This is a prerequisite to #37

Rename meeps to something else

So I'm going to start publicizing our music-writing syntax a little more, and I am suggesting a name change from meeps to something that doesn't sound as dumb. Changes will be reflected in the examples/ directory (also changing the file extensions).

We need chords

Currently, Melopy works pretty well with single notes. Introduce chords and you've got trouble. You can see my login in the add_wave() method, but it really doesn't work very well. It also currently impossible to generate chords from add_quarter_note(), etc.

Essentially, I do not know how chords work as far as data in the wave file goes. Do you add the value to the one that's currently there? Do you average them?

This needs some fixing, and some reorganizing. Let's rethink chords.

Errors during setup

Just following the steps on the README...

airosol:Projects jordan$ mkdir Melopy_ghost
airosol:Projects jordan$ cd Melopy_ghost/
airosol:Melopy_ghost jordan$ git clone [email protected]:prezjordan/Melopy.git .
Cloning into ....
remote: Counting objects: 219, done.
remote: Compressing objects: 100% (159/159), done.
remote: Total 219 (delta 100), reused 176 (delta 57)
Receiving objects: 100% (219/219), 31.09 KiB, done.
Resolving deltas: 100% (100/100), done.
airosol:Melopy_ghost jordan$ ls
MIT-LICENSE     melopy          tests
README.markdown     requirements.txt
examples        setup.py
airosol:Melopy_ghost jordan$ python setup.py install
running install
error: can't create or remove files in install directory

The following error occurred while trying to add or remove files in the
installation directory:

    [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/test-easy-install-1964.write-test'

The installation directory you specified (via --install-dir, --prefix, or
the distutils default setting) was:

    /Library/Python/2.7/site-packages/

Perhaps your account does not have write access to this directory?  If the
installation directory is a system-owned directory, you may need to sign in
as the administrator or "root" account.  If you do not have administrative
access to this machine, you may wish to choose a different installation
directory, preferably one that is listed in your PYTHONPATH environment
variable.

For information on other options, you may wish to consult the
documentation at:

  http://peak.telecommunity.com/EasyInstall.html

Please make the appropriate changes for your system and try again.

...sudo works, however...

airosol:Melopy_ghost jordan$ sudo python setup.py install
Password:
running install
running bdist_egg
running egg_info
creating Melopy.egg-info
writing Melopy.egg-info/PKG-INFO
writing top-level names to Melopy.egg-info/top_level.txt
writing dependency_links to Melopy.egg-info/dependency_links.txt
writing manifest file 'Melopy.egg-info/SOURCES.txt'
reading manifest file 'Melopy.egg-info/SOURCES.txt'
writing manifest file 'Melopy.egg-info/SOURCES.txt'
installing library code to build/bdist.macosx-10.7-intel/egg
running install_lib
running build_py
creating build
creating build/lib
creating build/lib/melopy
copying melopy/__init__.py -> build/lib/melopy
copying melopy/melopy.py -> build/lib/melopy
creating build/lib/tests
copying tests/__init__.py -> build/lib/tests
copying tests/melopy_tests.py -> build/lib/tests
creating build/bdist.macosx-10.7-intel
creating build/bdist.macosx-10.7-intel/egg
creating build/bdist.macosx-10.7-intel/egg/melopy
copying build/lib/melopy/__init__.py -> build/bdist.macosx-10.7-intel/egg/melopy
copying build/lib/melopy/melopy.py -> build/bdist.macosx-10.7-intel/egg/melopy
creating build/bdist.macosx-10.7-intel/egg/tests
copying build/lib/tests/__init__.py -> build/bdist.macosx-10.7-intel/egg/tests
copying build/lib/tests/melopy_tests.py -> build/bdist.macosx-10.7-intel/egg/tests
byte-compiling build/bdist.macosx-10.7-intel/egg/melopy/__init__.py to __init__.pyc
byte-compiling build/bdist.macosx-10.7-intel/egg/melopy/melopy.py to melopy.pyc
byte-compiling build/bdist.macosx-10.7-intel/egg/tests/__init__.py to __init__.pyc
byte-compiling build/bdist.macosx-10.7-intel/egg/tests/melopy_tests.py to melopy_tests.pyc
creating build/bdist.macosx-10.7-intel/egg/EGG-INFO
copying Melopy.egg-info/PKG-INFO -> build/bdist.macosx-10.7-intel/egg/EGG-INFO
copying Melopy.egg-info/SOURCES.txt -> build/bdist.macosx-10.7-intel/egg/EGG-INFO
copying Melopy.egg-info/dependency_links.txt -> build/bdist.macosx-10.7-intel/egg/EGG-INFO
copying Melopy.egg-info/top_level.txt -> build/bdist.macosx-10.7-intel/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating dist
creating 'dist/Melopy-0.0.0-py2.7.egg' and adding 'build/bdist.macosx-10.7-intel/egg' to it
removing 'build/bdist.macosx-10.7-intel/egg' (and everything under it)
Processing Melopy-0.0.0-py2.7.egg
Copying Melopy-0.0.0-py2.7.egg to /Library/Python/2.7/site-packages
Adding Melopy 0.0.0 to easy-install.pth file

Installed /Library/Python/2.7/site-packages/Melopy-0.0.0-py2.7.egg
Processing dependencies for Melopy==0.0.0
Finished processing dependencies for Melopy==0.0.0
airosol:Melopy_ghost jordan$ ls
MIT-LICENSE     dist            setup.py
Melopy.egg-info     examples        tests
README.markdown     melopy
build           requirements.txt

Is there a reason for this behavior?

Make progress bar printing optional

When using the render function, the printing of the progress bar is a significant percentage of the total time of the function. Printing should be optional. For reference, printing the progress was added in response to #28 .

I'd like to try something where a new named argument is passed to render to supply a callback function. The callback function will be called every time the percentage changes. I'll add a new function that will replicate the current behavior and that will be the default. If something that isn't "callable" is passed (like None or "" or False) we'll skip the callback and print nothing resulting in faster performance.

If this isn't workable right now, we should at least end up with a flag to disable printing the progress bar.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.