Skip to content

Commit

Permalink
Auto-generate documentation for each Node class
Browse files Browse the repository at this point in the history
  • Loading branch information
ideoforms committed Nov 9, 2023
1 parent 9a2c953 commit e353fc0
Show file tree
Hide file tree
Showing 148 changed files with 1,743 additions and 174 deletions.
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Regenerate the auto-generated Python bindings: `auxiliary/scripts/generate-node-python-bindings.py > source/src/python/nodes.cpp`
- Add unit tests to the appropriate test script in `tests`
- Re-run the tests: `python3 setup.py test`
- Update the stubs (see below)

## Build: C++

Expand Down Expand Up @@ -43,7 +44,7 @@ auxiliary/scripts/generate-node-python-bindings.py --markdown > docs/library/ind
To generate and serve the docs:

```
pip3 install mkdocs mkdocs-material mkdocs-include-markdown-plugin
pip3 install mkdocs mkdocs-material mkdocs-include-markdown-plugin mkdocs-git-revision-date-localized-plugin
mkdocs serve
```

Expand Down
71 changes: 65 additions & 6 deletions auxiliary/scripts/generate-node-python-bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def generate_markdown(node_classes) -> str:
Returns:
The complete docs/library.md markdown file
"""
output_markdown = ""
output_markdown = "# Node reference library\n"

for folder, classes in node_classes.items():
if folder in documentation_omit_folders:
Expand All @@ -285,14 +285,70 @@ def generate_markdown(node_classes) -> str:
output_markdown += "\n## " + folder_title + "\n\n"
for cls in classes:
if cls.constructors:
output_markdown_params = ", ".join(
("%s=%s" % (param.name, param.default)) for param in cls.constructors[0])
output_markdown += "- **%s**: %s `(%s)`\n" % (cls.name, cls.docs, output_markdown_params)
header = "# Node reference library\n"
output_markdown = header + output_markdown
cls_doc_path = "%s/%s.md" % (folder, cls.name.lower())
output_markdown += "- **[%s](%s)**: %s\n" % (cls.name, cls_doc_path, cls.docs)
output_markdown += "\n---\n"

return output_markdown


def write_markdown_by_category(node_classes) -> str:
"""
Generate Markdown documentation for the Node reference library
Args:
node_classes: dict of all Node classes
Returns:
The complete docs/library.md markdown file
"""

# Also outputs mkdocs index with following format:
# - Analysis:
# - Analysis: library/analysis/index.md
# - CrossCorrelate: library/analysis/crosscorrelate.md

root_directory = "docs/library"
for folder, classes in node_classes.items():
if folder in documentation_omit_folders:
continue
folder_title = folder_name_to_title(folder)
folder_path = os.path.join(root_directory, folder)
os.makedirs(folder_path, exist_ok=True)
folder_index_path_rel = os.path.join(folder, "index.md")
folder_index_path_abs = os.path.join(root_directory, folder_index_path_rel)
# print(" - \"%s\":" % (folder_title))
print(" - \"%s\": library/%s" % (folder_title, folder_index_path_rel))
with open(folder_index_path_abs, "w") as fd:
fd.write(f"[Reference library](../index.md) > [{folder_title}](index.md)\n\n")
fd.write(f"# {folder_title}\n\n")

for cls in classes:
if cls.constructors:
cls_doc_path = "%s.md" % (cls.name.lower())
fd.write("- **[%s](%s)**: %s\n" % (cls.name, cls_doc_path, cls.docs))

# output_markdown_params = ", ".join(
# ("%s=%s" % (param.name, param.default)) for param in cls.constructors[0])
# output = "- **%s**: %s `(%s)`\n" % (cls.name, cls.docs, output_markdown_params)

for cls in classes:
if cls.constructors:
cls_doc_path = "%s.md" % (cls.name.lower())
cls_doc_abs_path = os.path.join(root_directory, folder, cls_doc_path)
with open(cls_doc_abs_path, "w") as fd:
fd.write(f"[Reference library](../index.md) > [{folder_title}](index.md) > [{cls.name}]({cls_doc_path})\n\n")
fd.write(f"# {cls.name}\n\n")
fd.write(f"{cls.docs}\n\n")

output_markdown_params = ", ".join(
("%s=%s" % (param.name, param.default)) for param in cls.constructors[0])
output_markdown_params = output_markdown_params.replace("nullptr", "None")
fd.write(f"Signature:\n")
fd.write(f"```python\n")
fd.write(f"{cls.name}({output_markdown_params})\n")
fd.write(f"```\n")

def generate_node_table(node_classes) -> str:
"""
Generate a tabular list of all Node classes, in Markdown format.
Expand Down Expand Up @@ -323,6 +379,8 @@ def main(args):
print(generate_markdown(node_classes))
elif args.table:
print(generate_node_table(node_classes))
elif args.categories:
write_markdown_by_category(node_classes)
else:
print(generate_bindings(node_classes))

Expand All @@ -331,6 +389,7 @@ def main(args):
parser = argparse.ArgumentParser()
parser.add_argument("-m", "--markdown", action="store_true")
parser.add_argument("-t", "--table", action="store_true")
parser.add_argument("-c", "--categories", action="store_true")
args = parser.parse_args()

main(args)
16 changes: 12 additions & 4 deletions docs/graph/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ There are a number of graph configuration parameters that can be used to change
| sample_rate | The audio sample rate to use. |
| cpu_usage_limit | Imposes a hard limit on the CPU usage permitted by SignalFlow. If the estimated (single-core) CPU usage exceeds this value, no more nodes or patches can be created until it returns to below the limit. Floating-point value between 0..1, where 0.5 means 50% CPU. |

### Configuring the graph programmatically
---

## Configuring the graph programmatically

To specify an alternative config, create and populate an `AudioGraphConfig` object before the graph is started:

Expand All @@ -27,7 +29,9 @@ config.output_buffer_size = 2048
graph = AudioGraph(config)
```

### Configuring the graph via ~/.signalflow/config
---

## Configuring the graph via ~/.signalflow/config

To specify a configuration that is used by all future SignalFlow sessions, create a file `~/.signalflow/config`, containing one or more of the "Graph configuration" fields listed above.

Expand All @@ -52,7 +56,9 @@ signalflow configure

This will use your default `$EDITOR` to open the configuration, or `pico` if no editor is specified.

### Configuring the graph via environmental variables
---

## Configuring the graph via environmental variables

SignalFlow config can also be set by setting an environmental variable in your shell. Variable names are identical to the upper-case version of the config string, prefixed with `SIGNALFLOW_`. For example:

Expand All @@ -61,7 +67,9 @@ export SIGNALFLOW_OUTPUT_DEVICE_NAME="MacBook Pro Speakers"
export SIGNALFLOW_OUTPUT_BUFFER_SIZE=1024
```

### Printing the current config
---

## Printing the current config

To print the current configuration to stdout:

Expand Down
2 changes: 2 additions & 0 deletions docs/graph/recording.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ To record output in formats other than the default stereo, `start_recording` tak
!!! note
At present, only .wav is supported as an output format for global audio recordings.

---

## Offline (non-real-time) rendering

It is also possible to perform non-real-time rendering of a synthesis graph, by synthesizing audio output to a `Buffer` which can then be saved to disk:
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
title: Explore sound synthesis and DSP with Python

# SignalFlow: Explore sound synthesis and DSP with Python

SignalFlow is a sound synthesis framework whose goal is to make it quick and intuitive to explore complex sonic ideas. It has a simple Python API, allowing for rapid prototyping in Jupyter notebooks or on the command-line. It comes with over 100 signal processing classes for creative exploration, from filters and delays to FFT-based spectral processing and Euclidean rhythm generators.
Expand Down Expand Up @@ -59,5 +61,3 @@ At its core, SignalFlow has a handful of key concepts.

- [Installing SignalFlow](installation/index.md)
- [Example code](http://github.com/ideoforms/signalflow/tree/master/examples)

---
10 changes: 10 additions & 0 deletions docs/library/analysis/crosscorrelate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Analysis](index.md) > [CrossCorrelate](crosscorrelate.md)

# CrossCorrelate

Outputs the cross-correlation of the input signal with the given buffer. If hop_size is zero, calculates the cross-correlation every sample.

Signature:
```python
CrossCorrelate(input=None, buffer=None, hop_size=0)
```
7 changes: 7 additions & 0 deletions docs/library/analysis/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Reference library](../index.md) > [Analysis](index.md)

# Analysis

- **[CrossCorrelate](crosscorrelate.md)**: Outputs the cross-correlation of the input signal with the given buffer. If hop_size is zero, calculates the cross-correlation every sample.
- **[OnsetDetector](onsetdetector.md)**: Simple time-domain onset detector. Outputs an impulse when an onset is detected in the input. Maintains short-time and long-time averages. An onset is registered when the short-time average is threshold x the long-time average. min_interval is the minimum interval between onsets, in seconds.
- **[VampAnalysis](vampanalysis.md)**: Feature extraction using the Vamp plugin toolkit.
10 changes: 10 additions & 0 deletions docs/library/analysis/onsetdetector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Analysis](index.md) > [OnsetDetector](onsetdetector.md)

# OnsetDetector

Simple time-domain onset detector. Outputs an impulse when an onset is detected in the input. Maintains short-time and long-time averages. An onset is registered when the short-time average is threshold x the long-time average. min_interval is the minimum interval between onsets, in seconds.

Signature:
```python
OnsetDetector(input=0.0, threshold=2.0, min_interval=0.1)
```
10 changes: 10 additions & 0 deletions docs/library/analysis/vampanalysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Analysis](index.md) > [VampAnalysis](vampanalysis.md)

# VampAnalysis

Feature extraction using the Vamp plugin toolkit.

Signature:
```python
VampAnalysis(input=0.0, plugin_id="vamp-example-plugins:spectralcentroid:linearcentroid")
```
10 changes: 10 additions & 0 deletions docs/library/buffer/beatcutter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [BeatCutter](beatcutter.md)

# BeatCutter

Cuts a buffer into segment_count segments, and stutters/jumps with the given probabilities.

Signature:
```python
BeatCutter(buffer=None, segment_count=8, stutter_probability=0.0, stutter_count=1, jump_probability=0.0, duty_cycle=1.0, rate=1.0, segment_rate=1.0)
```
10 changes: 10 additions & 0 deletions docs/library/buffer/bufferlooper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [BufferLooper](bufferlooper.md)

# BufferLooper

Read and write from a buffer concurrently, with controllable overdub.

Signature:
```python
BufferLooper(buffer=None, input=0.0, feedback=0.0, loop_playback=false, loop_record=false)
```
10 changes: 10 additions & 0 deletions docs/library/buffer/bufferplayer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [BufferPlayer](bufferplayer.md)

# BufferPlayer

Plays the contents of the given buffer. start_time/end_time are in seconds. When a clock signal is receives, rewinds to the start_time.

Signature:
```python
BufferPlayer(buffer=None, rate=1.0, loop=0, start_time=None, end_time=None, clock=None)
```
10 changes: 10 additions & 0 deletions docs/library/buffer/bufferrecorder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [BufferRecorder](bufferrecorder.md)

# BufferRecorder

Records the input to a buffer. feedback controls overdub.

Signature:
```python
BufferRecorder(buffer=None, input=0.0, feedback=0.0, loop=false)
```
10 changes: 10 additions & 0 deletions docs/library/buffer/feedbackbufferreader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [FeedbackBufferReader](feedbackbufferreader.md)

# FeedbackBufferReader

Counterpart to FeedbackBufferWriter.

Signature:
```python
FeedbackBufferReader(buffer=None)
```
10 changes: 10 additions & 0 deletions docs/library/buffer/feedbackbufferwriter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [FeedbackBufferWriter](feedbackbufferwriter.md)

# FeedbackBufferWriter

Counterpart to FeedbackBufferReader.

Signature:
```python
FeedbackBufferWriter(buffer=None, input=0.0, delay_time=0.1)
```
10 changes: 10 additions & 0 deletions docs/library/buffer/grainsegments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [GrainSegments](grainsegments.md)

# GrainSegments

GrainSegments

Signature:
```python
GrainSegments(buffer=None, clock=0, target=0, offsets={}, values={}, durations={})
```
10 changes: 10 additions & 0 deletions docs/library/buffer/granulator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [Granulator](granulator.md)

# Granulator

Granulator. Generates a grain from the given buffer each time a clock signal is received, with the given duration/rate/pan parameters. The input buffer can be mono or stereo.

Signature:
```python
Granulator(buffer=None, clock=0, pos=0, duration=0.1, pan=0.0, rate=1.0, max_grains=2048)
```
13 changes: 13 additions & 0 deletions docs/library/buffer/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Reference library](../index.md) > [Buffer](index.md)

# Buffer

- **[BeatCutter](beatcutter.md)**: Cuts a buffer into segment_count segments, and stutters/jumps with the given probabilities.
- **[BufferLooper](bufferlooper.md)**: Read and write from a buffer concurrently, with controllable overdub.
- **[BufferPlayer](bufferplayer.md)**: Plays the contents of the given buffer. start_time/end_time are in seconds. When a clock signal is receives, rewinds to the start_time.
- **[BufferRecorder](bufferrecorder.md)**: Records the input to a buffer. feedback controls overdub.
- **[FeedbackBufferReader](feedbackbufferreader.md)**: Counterpart to FeedbackBufferWriter.
- **[FeedbackBufferWriter](feedbackbufferwriter.md)**: Counterpart to FeedbackBufferReader.
- **[GrainSegments](grainsegments.md)**: GrainSegments
- **[Granulator](granulator.md)**: Granulator. Generates a grain from the given buffer each time a clock signal is received, with the given duration/rate/pan parameters. The input buffer can be mono or stereo.
- **[SegmentPlayer](segmentplayer.md)**: Trigger segments of a buffer at the given onset positions.
10 changes: 10 additions & 0 deletions docs/library/buffer/segmentplayer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Buffer](index.md) > [SegmentPlayer](segmentplayer.md)

# SegmentPlayer

Trigger segments of a buffer at the given onset positions.

Signature:
```python
SegmentPlayer(buffer=None, onsets={})
```
7 changes: 7 additions & 0 deletions docs/library/control/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Reference library](../index.md) > [Control](index.md)

# Control

- **[MouseX](mousex.md)**: Outputs the normalised cursor X position, from 0 to 1. Currently only supported on macOS.
- **[MouseY](mousey.md)**: Outputs the normalised cursor Y position, from 0 to 1. Currently only supported on macOS.
- **[MouseDown](mousedown.md)**: Outputs 1 if the left mouse button is down, 0 otherwise. Currently only supported on macOS.
10 changes: 10 additions & 0 deletions docs/library/control/mousedown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Control](index.md) > [MouseDown](mousedown.md)

# MouseDown

Outputs 1 if the left mouse button is down, 0 otherwise. Currently only supported on macOS.

Signature:
```python
MouseDown(button_index=0)
```
10 changes: 10 additions & 0 deletions docs/library/control/mousex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Control](index.md) > [MouseX](mousex.md)

# MouseX

Outputs the normalised cursor X position, from 0 to 1. Currently only supported on macOS.

Signature:
```python
MouseX()
```
10 changes: 10 additions & 0 deletions docs/library/control/mousey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Control](index.md) > [MouseY](mousey.md)

# MouseY

Outputs the normalised cursor Y position, from 0 to 1. Currently only supported on macOS.

Signature:
```python
MouseY()
```
10 changes: 10 additions & 0 deletions docs/library/envelope/adsrenvelope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Reference library](../index.md) > [Envelope](index.md) > [ADSREnvelope](adsrenvelope.md)

# ADSREnvelope

Attack-decay-sustain-release envelope. Sustain portion is held until gate is zero.

Signature:
```python
ADSREnvelope(attack=0.1, decay=0.1, sustain=0.5, release=0.1, gate=0)
```
Loading

0 comments on commit e353fc0

Please sign in to comment.