diff --git a/.gitignore b/.gitignore index 92a6c10..b2f54a4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__/ *.mus .idea/* venv/ +SMNP.egg-info diff --git a/Pipfile b/Pipfile index 7cd84b0..11d5114 100644 --- a/Pipfile +++ b/Pipfile @@ -10,7 +10,6 @@ sounddevice = "*" soundfile = "*" numpy = "*" matplotlib = "*" -tkinter = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index d05286b..a7370d0 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -106,25 +106,25 @@ }, "numpy": { "hashes": [ - "sha256:03f2ebcbffcce2dec8860633b89a93e80c6a239d21a77ae8b241450dc21e8c35", - "sha256:078c8025da5ab9e8657edc9c2a1e9642e06e953bc7baa2e65c1aa9d9dfb7e98b", - "sha256:0fbfa98c5d5c3c6489cc1e852ec94395d51f35d9ebe70c6850e47f465038cdf4", - "sha256:1c841033f4fe6801648180c3033c45b3235a8bbd09bc7249010f99ea27bb6790", - "sha256:2c0984a01ddd0aeec89f0ce46ef21d64761048cd76c0074d0658c91f9131f154", - "sha256:4c166dcb0fff7cb3c0bbc682dfb5061852a2547efb6222e043a7932828c08fb5", - "sha256:8c2d98d0623bd63fb883b65256c00454d5f53127a5a7bcdaa8bdc582814e8cb4", - "sha256:8cb4b6ae45aad6d26712a1ce0a3f2556c5e1484867f9649e03496e45d6a5eba4", - "sha256:93050e73c446c82065b7410221b07682e475ac51887cd9368227a5d944afae80", - "sha256:a3f6b3024f8826d8b1490e6e2a9b99e841cd2c375791b1df62991bd8f4c00b89", - "sha256:bede70fd8699695363f39e86c1e869b2c8b74fb5ef135a67b9e1eeebff50322a", - "sha256:c304b2221f33489cd15a915237a84cdfe9420d7e4d4828c78a0820f9d990395c", - "sha256:f11331530f0eff69a758d62c2461cd98cdc2eae0147279d8fc86e0464eb7e8ca", - "sha256:fa5f2a8ef1e07ba258dc07d4dd246de23ef4ab920ae0f3fa2a1cc5e90f0f1888", - "sha256:fb6178b0488b0ce6a54bc4accbdf5225e937383586555604155d64773f6beb2b", - "sha256:fd5e830d4dc31658d61a6452cd3e842213594d8c15578cdae6829e36ad9c0930" + "sha256:05dbfe72684cc14b92568de1bc1f41e5f62b00f714afc9adee42f6311738091f", + "sha256:0d82cb7271a577529d07bbb05cb58675f2deb09772175fab96dc8de025d8ac05", + "sha256:10132aa1fef99adc85a905d82e8497a580f83739837d7cbd234649f2e9b9dc58", + "sha256:12322df2e21f033a60c80319c25011194cd2a21294cc66fee0908aeae2c27832", + "sha256:16f19b3aa775dddc9814e02a46b8e6ae6a54ed8cf143962b4e53f0471dbd7b16", + "sha256:3d0b0989dd2d066db006158de7220802899a1e5c8cf622abe2d0bd158fd01c2c", + "sha256:438a3f0e7b681642898fd7993d38e2bf140a2d1eafaf3e89bb626db7f50db355", + "sha256:5fd214f482ab53f2cea57414c5fb3e58895b17df6e6f5bca5be6a0bb6aea23bb", + "sha256:73615d3edc84dd7c4aeb212fa3748fb83217e00d201875a47327f55363cef2df", + "sha256:7bd355ad7496f4ce1d235e9814ec81ee3d28308d591c067ce92e49f745ba2c2f", + "sha256:7d077f2976b8f3de08a0dcf5d72083f4af5411e8fddacd662aae27baa2601196", + "sha256:a4092682778dc48093e8bda8d26ee8360153e2047826f95a3f5eae09f0ae3abf", + "sha256:b458de8624c9f6034af492372eb2fee41a8e605f03f4732f43fc099e227858b2", + "sha256:e70fc8ff03a961f13363c2c95ef8285e0cf6a720f8271836f852cc0fa64e97c8", + "sha256:ee8e9d7cad5fe6dde50ede0d2e978d81eafeaa6233fb0b8719f60214cf226578", + "sha256:f4a4f6aba148858a5a5d546a99280f71f5ee6ec8182a7d195af1a914195b21a2" ], "index": "pypi", - "version": "==1.17.1" + "version": "==1.17.2" }, "pycparser": { "hashes": [ diff --git a/README.md b/README.md index 4272157..5629ec6 100644 --- a/README.md +++ b/README.md @@ -253,7 +253,7 @@ Note literal is written with the following syntax: ; where PITCH := (c|d|e|f|g|a) [b|#] | h# | b - | (C|D|E|F|G|A) [B|#] | H# | B + | (C|D|E|F|G|A) [b|#] | H# | B OCTAVE := 1-9 DURATION := /non-negative integer/ ``` @@ -277,7 +277,7 @@ Examples (note that pitch is case-insensitive): * `@F5:2` is half note with pitch *f''* * `@g#3:4d` is dotted quarter note with pitch *g♯* * `@Ab6:16` is sixteenth note with pitch *a♭'''* -* `@b2:1` is whole note with pitch *B* (*H♯*) +* `@b2:1` is whole note with pitch *B* (*H♭*) * `@C#1:32d` is dotted thirty-second note with pitch *C♯,* **Note:** note literal syntax cannot include any whitespace character. @@ -2364,3 +2364,9 @@ to see what is going on at each language processing stage: * `--ast` - *pretty-prints* abstract syntax tree as parser's output for passed code * `--dry-run` - runs language-processing tools without involving evaluator +## Installation +To install SMNP: +1. Make sure you have already installed *PortAudio* in your OS (it is required by Audio Module +to send data frames to your sound device) +2. Clone this repository and enter to it +3. Run `pip install .` inside root repository folder diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..29a30b0 --- /dev/null +++ b/setup.py @@ -0,0 +1,36 @@ +import os + +from setuptools import setup, find_packages + + +def file(file): + return open(os.path.join(os.path.dirname(__file__), file)).read() + +setup( + name='SMNP', + version=file('smnp/meta/__version__.txt'), + packages=find_packages(), + description=file('smnp/meta/__description__.txt'), + author='Bartlomiej P. Pluta', + url='https://gitlab.com/bartlomiej.pluta/smnp', + install_requires=[ + "cffi>=1.12.3", + "cycler>=0.10.0", + "kiwisolver>=1.1.0", + "matplotlib>=3.1.1", + "numpy>=1.17.2", + "pycparser>=2.19", + "pyparsing>=2.4.2", + "python-dateutil>=2.8.0", + "six>=1.12.0", + "sounddevice>=0.3.13", + "soundfile>=0.10.2" + ], + entry_points={ + 'console_scripts': ['smnp=smnp.main:main'] + }, + package_data={ + 'smnp.library.code': ['main.mus'], + 'smnp.meta': ['__version__.txt', '__description__.txt'] + } +) \ No newline at end of file diff --git a/smnp/calc.py b/smnp/calc.py deleted file mode 100644 index e5f8115..0000000 --- a/smnp/calc.py +++ /dev/null @@ -1,66 +0,0 @@ -from smnp.ast.node.model import Node -from smnp.ast.parser import Parser -from smnp.token.tokenizer import tokenize -from smnp.token.type import TokenType - - -class Atom(Node): - def __init__(self, value, pos): - super().__init__(pos) - self.children = [value] - - @property - def value(self): - return self[0] - -class Operation(Node): - def __init__(self, left, op, right, pos): - super().__init__(pos) - self.children = [left, op, right] - - @property - def left(self): - return self[0] - - @property - def operator(self): - return self[1] - - @property - def right(self): - return self[2] - -def atom(): - return Parser.oneOfTerminals(TokenType.INTEGER, TokenType.NOTE, TokenType.STRING, createNode=lambda val, pos: Atom(val, pos)) - -def chain(): - return Parser.leftAssociativeOperatorParser(atom(), [TokenType.DOT], atom(), lambda left, op, right: Operation(left, op, right, op.pos), name="chain") - -def factor(): - return Parser.leftAssociativeOperatorParser(chain(), [TokenType.DOUBLE_ASTERISK], chain(), lambda left, op, right: Operation(left, op, right, op.pos), name="factor") - -def term(): - return Parser.leftAssociativeOperatorParser(factor(), [TokenType.ASTERISK, TokenType.SLASH], factor(), lambda left, op, right: Operation(left, op, right, op.pos), name="term") - -def expr(): - return Parser.leftAssociativeOperatorParser(term(), [TokenType.PLUS, TokenType.MINUS], term(), lambda left, op, right: Operation(left, op, right, op.pos), name="expr") -# -def evaluate(node): - if type(node) == Atom: - return node.value - lhs = evaluate(node.left) - rhs = evaluate(node.right) - return { - "+": int(lhs) + int(rhs), - "*": int(lhs) * int(rhs), - "-": int(lhs) - int(rhs), - "/": int(lhs) / int(rhs), - "**": int(lhs) ** int(rhs) - }[node.operator.value] - -def draft(): - - tokens = tokenize(['"fesf fe" + "fsefsef" + "fsefs"']) - e = expr() - node = e(tokens).node - node.print() diff --git a/smnp/cli/parser.py b/smnp/cli/parser.py index 1ad3aeb..4414483 100644 --- a/smnp/cli/parser.py +++ b/smnp/cli/parser.py @@ -1,13 +1,16 @@ import argparse -VERSION = "0.1" -DESCRIPTION = """ - Simple Music Notation Processor is a command line tool enabling you to do some music stuff using custom domain-specific language. -""" +from pkg_resources import resource_string + + +def file(file): + return resource_string('smnp.meta', file).decode("utf-8") + + class CliParser(object): def __init__(self): - self.parser = argparse.ArgumentParser(description=DESCRIPTION) + self.parser = argparse.ArgumentParser(description=file("__description__.txt")) self.parser.add_argument('file', nargs='*', help='a file containing SMNP code') self.parser.add_argument('-c', '--code', action='append', default=[], type=str, help='a string with SMNP code') self.parser.add_argument('-m', '--mic', action='store_true', help='test microphone level') @@ -17,7 +20,7 @@ class CliParser(object): self.parser.add_argument('--tokens', action='store_true', help='print tokens of parsed code') self.parser.add_argument('--ast', action='store_true', help='print abstract syntax tree of parsed code') self.parser.add_argument('--dry-run', action='store_true', help='don\'t execute passed code') - self.parser.version = VERSION + self.parser.version = file("__version__.txt") def parse(self): return self.parser.parse_args() \ No newline at end of file diff --git a/smnp/meta/__description__.txt b/smnp/meta/__description__.txt new file mode 100644 index 0000000..e616977 --- /dev/null +++ b/smnp/meta/__description__.txt @@ -0,0 +1 @@ +Simple Music Notation Processor is a command line tool enabling you to do some music stuff using custom domain-specific language. \ No newline at end of file diff --git a/smnp/meta/__init__.py b/smnp/meta/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smnp/meta/__version__.txt b/smnp/meta/__version__.txt new file mode 100644 index 0000000..ceab6e1 --- /dev/null +++ b/smnp/meta/__version__.txt @@ -0,0 +1 @@ +0.1 \ No newline at end of file