Skip to content
James H Ball edited this page Jan 31, 2024 · 21 revisions

Osci-render User Documentation

WARNING: THIS IS OUTDATED AND FOR THE LEGACY VERSION OF OSCI-RENDER, NOT OSCI-RENDER 2.0.

The goal of this documentation is to describe all aspects of osci-render in detail. If you read this and still have questions that you think should be answered in the documentation, please raise an issue and let me know.

Getting started

todo

Project select screen

The project select screen is the first thing you'll see when you open osci-render. It's your hub for starting or re-opening projects and for learning about new features in osci-render.

image

Here, you can open any recent projects, look at the changelog for the latest versions, and open log folders for debugging any errors.

The most common thing you'll be doing here is opening a previous project, or starting a new one with the "Start new project" button.

Changelog

The changelog mirrors the same changelog linked in GitHub releases. It should be an extensive view of any new changes added in recent versions of osci-render. Older versions are not documented here.

Any contributors to specific versions are mentioned, as well as anybody that suggested the feature or raised the issue :)

Recent files

Any project that you open in osci-render is saved to a list of recent files that will appear here every time you open osci-render. Clicking on any item in the list will open it in osci-render. Items in the list are ordered by how recently they were opened, so if you open a project at the bottom, it will move to the top the next time you look at the recent files.

Starting muted

The audio from osci-render is very loud on start-up! This is a 'feature' in the sense that the image should ideally be as large as possible when displayed, so we need the volume of the audio to be loud so that it takes up more space.

To mitigate against this, you can start osci-render muted by checking "Start muted" underneath the "Start new project" button. This setting is remembered for when you next open osci-render.

This will have the effect of setting the volume slider in the Effects panel to 0 so that there is no audio. You can then start playing audio by changing the slider value to something above 0. The default volume value is 3 which should create an image that takes up the entire size of the oscilloscope display.

Error log files

Unfortunately, osci-render is still in very active development and will run into errors! To help fix any bugs or errors, the log files are incredibly useful for me to understand what problems are occurring and isolate the issue to a particular part of the program.

Any error whilst running is saved to these log files, as well as more minor logs to give me extra information whilst debugging.

To open the folder containing error logs, click the "Open log folder" button. This shows you every log created for every time you've run osci-render. There might be a lot in here, and it's fine to delete these if they are taking up space. There is a maximum size of 1MiB for any individual log file, but this is unlikely to ever be reached and most log files are less than 1KiB in size.

When creating an issue for osci-render, always provide a log file to help solve the problem! Please check the log files beforehand if there is any information about your username, machine name, or directory structure that you'd like to keep private.

Supported files

Osci-render supports the following file types: .obj, .txt, .svg, and .lua. The default file that opens when you start a new project is a default 3D cube .obj file.

You can open a file using the "Choose File" button in the Main settings panel.

Any file type can be edited when it's opened using the "Edit file" button. This opens a text editor window that allows you to change anything about the file. This could include changing the position of a cube's corner or changing the text displayed.

.obj files

.obj files are 3D objects that can be displayed as a wireframe mesh in osci-render. The rotation of the object in each axis can be controlled using the 3D .obj settings panel.

Osci-render supports extremely complex 3D objects if you give it enough time to calculate the most efficient way of traversing the 3D object when drawing it on the screen. This process can take a minute or more for complicated objects. For objects with a lot of vertices, you can enable GPU rendering if you have a computer with a decent graphics card to render the movement of the object at a higher framerate. This becomes essential when you are also hiding the hidden edges of an object.

There is a great list of example .obj files available here: https://people.sc.fsu.edu/~jburkardt/data/obj/obj.html

.txt files

.txt files are the simplest file type. Any text in the file is rendered to the display in the default sans-serif font of your operating system. To change the font being used, as well as the font style (Plain, Bold, or Italic), you can select the different options under View in the menu bar and then "Text File Font" and "Text File Font Style".

.txt files are also the most 'sensible' file to edit in osci-render since any changes made are immediately reflected as text.

To customize the size of some lines of text, you can write $text_size= followed by a number at the start of the line to change the text size for that line. e.g. $text_size=50 will make the text size 50 for that line. The default text size is 100. If for some reason you still want to write $text_size=, you can escape it with a backslash. e.g. \$text_size=50. This slightly changes the syntax for writing a backslash, as you now need to write \\ instead of \.

.svg files

.svg files are common vector image formats that look great on an oscilloscope as they are not defined in terms of pixels, but rather shapes and positions. They also naturally trace a path, making the image very crisp with very few jumps of the oscilloscope beam.

A great list of example .svg files is available here: https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/

.lua files (Lua live-coding)

.lua files in osci-render are used to generate raw audio samples using the Lua programming language. These work differently from the other files since they are a 'micro-program' within osci-render and have a state that you can completely configure yourself.

When you create a .lua file using the Create File button, and then edit the file using Edit File, you will see an example script that renders a mini version of osci-render within osci-render. It is well commented and explains in detail how you could write a similar program in Lua.

The return type of a Lua program is an array of two values. These correspond to the left and right audio channels of a single audio sample, or the x and y coordinates of a single dot drawn to the screen. These values should fall in the range of -1 to +1, with { -1, -1 } being the left-most, bottom-most point, { 0, 0 } being the centre of the display, and { 1, 1 } being the right-most, top-most point.

The most simple program would return a single dot or audio sample in the centre of the display. This would be silent if you were to listen to it since there is no movement in the image: return { 0, 0 }

Pre-defined variables

step is the name of a variable available by default which is the current sample number that is being generated. It is incremented every time the script is called, so it starts off with a value of 1 and will increase by one every time the script runs. step is fundamental when used as a 'phase' or 'theta' when calling mathematical functions that have a periodic output, like math.sin, math.cos, or math.tan.

An example Lua program that draws a simple circle using step is as follows:

return { math.sin(step / 1000), math.cos(step / 1000) }

Here, we are using the math.sin and math.cos functions provided by Lua and detailed more below. A list of other interesting functions in the Lua math library is here.

The math library also provides some constants such as math.pi that are very useful when dealing with rotation.

slider_a, slider_b, slider_c, slider_d, and slider_e are other pre-defined variables that all correspond to the value of the corresponding sliders in the .lua file settings. When you change the value of a slider, or the slider's value is being animated by one of the animation effects, you'll see the value of this change.

You can use the slider_X variables to control various aspects of the program, such as the ratio between frequencies in a Lissajous pattern, or the speed at which something oscillates.

Helpful tips and examples

When declaring a new variable, you might find it helpful to be able to set an initial value the first time the script runs, but use the previous value of the variable when it next runs. You can do this simply with the following:

-- sets 'theta' to 0 initially, or the previous value of
-- 'theta' the last time this script ran
theta = theta or 0

This would allow you to replicate the behaviour of step (i.e. starting at 1 and incrementing every call to the script) by doing:

my_step = my_step or 1
my_step = my_step + 1

A fully comprehensive example of a complicated Lua script project for osci-render can be found here: https://james.ball.sh/docs/osci-seption.osci and the script is also below:

-- a=start point, b=end point, t=drawing progress
function line(a, b, t)
  return {
    a.x + t * (b.x - a.x),
    a.y + t * (b.y - a.y)
  }
end

focal_length = slider_c
camera_z = slider_b * 3

-- projects a 3D point into 2D
function project(point)
  return {
    x=point.x * focal_length / (point.z - camera_z),
    y=point.y * focal_length / (point.z - camera_z)
  }
end

-- rotates a point in 3D
function rotate(point, rotate_x, rotate_y, rotate_z)
  x1 = point.x
  y1 = point.y
  z1 = point.z
  
  -- rotate around x-axis
  cos = math.cos(rotate_x)
  sin = math.sin(rotate_x)
  y2 = cos * y1 - sin * z1
  z2 = sin * y1 + cos * z1

  -- rotate around y-axis
  cos = math.cos(rotate_y)
  sin = math.sin(rotate_y)
  x2 = cos * x1 + sin * z2
  z3 = -sin * x1 + cos * z2

  -- rotate around z-axis
  cos = math.cos(rotate_z)
  sin = math.sin(rotate_z)
  x3 = cos * x2 - sin * y2
  y3 = sin * x2 + cos * y2
  
  return {
    x=x3,
    y=y3,
    z=z3
  }
end

num_points = 16
-- 3D cube draw path
points = {
  {x=-1.0, y=-1.0, z=1.0},
  {x=1.0, y=-1.0, z=1.0},
  {x=1.0, y=-1.0, z=-1.0},
  {x=-1.0, y=-1.0, z=-1.0},
  {x=1.0, y=-1.0, z=-1.0},
  {x=1.0, y=1.0, z=-1.0},
  {x=-1.0, y=1.0, z=-1.0},
  {x=-1.0, y=-1.0, z=-1.0},
  {x=-1.0, y=-1.0, z=1.0},
  {x=1.0, y=-1.0, z=1.0},
  {x=1.0, y=1.0, z=1.0},
  {x=-1.0, y=1.0, z=1.0},
  {x=1.0, y=1.0, z=1.0},
  {x=1.0, y=1.0, z=-1.0},
  {x=-1.0, y=1.0, z=-1.0},
  {x=-1.0, y=1.0, z=1.0}
}

-- percentage of the image that has currently been drawn
drawing_progress = drawing_progress or 0
drawing_progress = drawing_progress + 0.001 * slider_a
progress_cutoff = slider_e

if drawing_progress > progress_cutoff then
  drawing_progress = 0
end

-- get the index of the start point of the current line
start_index = math.floor(drawing_progress * num_points + 1)
-- end point of current line is the next in the points table
end_index = start_index + 1
if end_index > num_points then
  end_index = 1
end

-- doing this to avoid recomputation for every sample.
-- prev_start ~= start_index == true whenever a new line has started
if prev_start ~= start_index then
  rotate_speed = slider_d * step / 10000
  -- rotate and project the start and end points
  proj_start = project(rotate(points[start_index], rotate_speed, rotate_speed, 0))
  proj_end = project(rotate(points[end_index], rotate_speed, rotate_speed, 0))
end

prev_start = start_index

-- work out what the relative progress drawn of the current line is
draw_length = 1.0 / num_points
line_progress = drawing_progress - (start_index - 1) * draw_length
line_progress = num_points * line_progress

return line(proj_start, proj_end, line_progress)

This is 'osci-render inside of osci-render' and generates audio samples to render the default cube that is displayed when you create a new osci-render project.

Optimising for performance

Every single audio sample is generated with a call to the Lua program you've written. This means at high sample rates (i.e. 192kHz) you will run into performance issues if you are trying to generate complicated sounds as the script is literally running 192,000 times per second! Because of this, you need to take performance into consideration if you are thinking about developing something complex in osci-render.

The example script above is a very good case study for optimising the script for running at a high sample rate. The expensive functions in my program are project and rotate. Both of these, but especially rotate, do a lot of complex maths to rotate the point drawn and then project this into 2D coordinates. If I were to perform this for every single audio sample it would be extremely expensive and the audio samples would not be generated quickly enough.

Instead, I only perform the rotation and projection when the line tracing the shape of the cube changes line. I make the assumption that there isn't much rotation between drawing the start of a line and the end of the line, and so the 2D coordinates of the start and end points don't change whilst the line is drawn. This is a fair assumption to make, as at any audible frequency and reasonable rotation speed the lines are drawn so quickly that there is very little rotation whilst drawing the line.

If it were to take only 0.001 seconds to draw a single line, then I'm only doing expensive computation 1000 times per second, rather than 192,000 times per second if I did this for every audio sample. That's a 192x performance increase for practically nothing!

Re-using computation, or reducing expensive computation to only once every few-hundred audio samples, is the best way to improve performance.

If I were to create a game, physics engine, or anything that required constant computation every 'frame', it's best to only do this computation occasionally rather than every audio sample. You could do this by having the expensive computation in an if statement using step:

-- only do the expensive computation if step is a multiple of 400
-- this means it only runs every 400 audio samples (which is still 480 times per second at 192kHz!)
if step % 400 == 0 then
  -- expensive computation
end

Menu bar

Osci-render currently doesn't have a dedicated settings menu. Instead, the menu bar provides any settings that you are unlikely to need to use whilst performing or synthesising music. The menu bar is located at the top of the main application after opening a project:

menu bar

File

image

The File menu shows all project-related actions. This includes a list of recent projects, actions to open a project, and also save the current project.

In addition to using the menu, you can also use the following keyboard shortcuts:

  • Open Project - Ctrl/Cmd + O
  • Save Project - Ctrl/Cmd + S
  • Save Project As - Ctrl/Cmd + Shift + S

Audio

image

Audio settings contain options to change the audio device you are outputting to, as well as recording the current audio being synthesised to a .wav file.

Changing audio device

You should see a list of different audio devices, as well as the sample rate and number of channels available for each device. The audio devices named "default" are all using Java's sound engine, which has the best-supported audio across different operating systems, however, this has the caveat of not being able to choose a different sound output to your operating system's default. To mitigate this, on Windows and Linux (unfortunately not macOS) you also have access to the rest of the audio devices on your machine.

Using audio devices with many audio channels

Osci-render supports multi-channel output at a basic level. If osci-render detects that you have an audio interface with more than 2 outputs, it will allow you to choose these as an option in the list of audio devices. You can then control the value of all additional channels using the "Brightness" slider. This will be an inaudible signal and only makes sense if you are using a DC-coupled audio interface since it's a static signal. This is named "Brightness" as it's currently only a static signal for use with CRT displays that have a Z channel for the intensity of the electron beam.

Recording audio

Osci-render supports high-quality lossless recordings of the audio being synthesised as a .wav file. You can either click "Record" or use the keyboard shortcut Ctrl/Cmd + R to start recording. When recording starts, this menu item will change to say "Stop recording" and when you press it or use Ctrl/Cmd + R again, it will stop recording and ask for you to provide a file name and location to save the .wav file. If no location is provided, osci-render will save it in the folder that it is being run from, to make sure that the recording isn't lost. When a file is saved, the location it has been saved to is detailed at the bottom of the Main settings panel.

You can also create a recording for a fixed length of time using the "Timed recording?" checkbox and then configure how long you want the recording to be using the "Record length" text box. This will automatically stop recording after the time has elapsed, prompting you for a location to save the recording immediately after the recording has finished.

If you want to record the audio with a different bit depth or format, you can also change the "Recording audio sample" from the dropdown. The following audio sample formats are available:

  • Unsigned 8-bit integer
  • Signed 8-bit integer
  • Signed 16-bit integer (default)
  • Signed 24-bit integer
  • Signed 32-bit integer

You should not notice any significant difference in audio or visual quality, especially past 16-bit. For reference, Java's sound engine (the default for osci-render) will play audio to your audio device using 16-bit signed integer audio samples.

MIDI

image

The MIDI settings have a few actions to reset MIDI, and configure the MIDI channel being primarily used for visuals. Read MIDI Control for much more information on controlling sliders

"Reset MIDI Mappings" unbinds any sliders that are currently bound to a MIDI CC channel. This can also be triggered with the keyboard shortcut Ctrl/Cmd + M.

"Stop MIDI Notes" is used to stop all notes that osci-render thinks are being held down. This can happen if the MIDI signals being received are malformed and don't have a 'stop note' or 'release key' message. This should be very uncommon and shouldn't need to be used.

"Reset MIDI" resets osci-render to the state before any MIDI notes are played. This might be needed if you accidentally play a MIDI note and want to go back to the default behaviour when you start osci-render of constantly playing a note.

"Deadzone" increases the area on a slider that snaps to 0 when controlling it with a MIDI CC device. This is needed as MIDI CC messages only have 128 different values, which is not much granularity at all. This might mean there is no position on a MIDI CC slider that has a value of 0. To mitigate against this, the deadzone snaps to 0 when a MIDI CC value is close to the zero point and increasing the deadzone means that it snaps when further away from the zero point.

"Main MIDI Channel" chooses the main MIDI channel used for osci-render's visuals. Osci-render only renders the image you have open at one frequency at a time - so you cannot play chords with a single image. Therefore, this selects which channel should be used to create this image. All other channels are then simple sine waves. For more explanation of this, look at the MIDI Control section.

The "Note Attack" and "Note Decay" are fairly standard options for controlling the sound of the MIDI note. They change the time it takes for a note played to reach full volume, and the time it takes after the note stops for it to be silent respectively. Attack and decay values of 0 will result in harsh notes that instantly start and stop playing.

View

image

The View settings control various aspects of how the image looks and how it is rendered on a CRT display. They are more concerned with video rather than audio (though of course, they are one and the same).

"Flip X Direction" and "Flip Y Direction" mirror the image in either the X or Y axis, which can be useful if your CRT display or software has flipped axes.

Hiding hidden meshes and GPU rendering

"Hide Hidden Meshes" is a more experimental setting that hides any edges of a 3D object that should be hidden by the mesh of the object - treating it as a solid object that light cannot pass through. This gives the impression of the object looking more 'real'. This setting is heavily inspired by VAMP by Chris Allen who developed a similar plugin for Blender for use with OsciStudio. This requires a fairly expensive calculation to determine whether each point on a mesh is visible to the camera and this runs in real time. Because of this, don't expect very complicated meshes to render at high framerates when this is enabled.

Below shows an example of the substantial increase in image quality when this is enabled when rendered at the same frequency.

Hide Hidden Meshes

This isn't possible at all on complicated objects unless you are using GPU rendering. Enabling "Render using GPU" utilises the graphics card on your machine to do all the expensive calculations. Rotations of complex 3D objects and projections of each vertex into 2D can all be accelerated with the GPU, as well as the previously mentioned "Hide Hidden Meshes" feature. With the example video above, I get around 4 frames per second when trying to hide hidden edges without using the GPU. This is compared with an uncapped framerate when using GPU rendering!

GPU rendering is disabled by default due to incompatibility with some machines. It uses OpenCL which is already installed on Windows, meaning there shouldn't be any setup required to use it. On macOS and Linux, you might need to first install OpenCL for this to have any effect. On Linux, if you are using Intel(R) integrated graphics, you should be able to install Intel(R) Graphics Compute Runtime to get this working. If anyone using macOS could provide insight into whether this works, please make an issue or email me at [email protected].

Sliders

image

The Sliders menu allows you to change the minimum and maximum values that any slider in the interface can have. You can choose a slider to modify by using the dropdown, and then change the minimum and maximum values using the "Min" and "Max" text boxes.

Sliders mapped to MIDI CC channels will use the new range, and any animations will now animate between the new min and max values set. This is the easiest way of making an animation only oscillate between a smaller range of values than the default.

Window

image

The Window menu currently only has an option to open the Software Oscilloscope.

Software Oscilloscope

The Software Oscilloscope, aptly named 'sosci' is the best way to use osci-render if you don't have a real analogue oscilloscope. It uses a modified version of the amazing woscope library by m1el.

NOTE: The software oscilloscope doesn't (currently) work on Safari. Please use Firefox or Chrome!

Software Oscilloscope

Clicking on "Open Software Oscilloscope" will open james.ball.sh/oscilloscope in your default browser. If no audio is playing back or osci-render hasn't connected, you'll see a green dot in the centre of the display. As soon as you open osci-render with this webpage open and can hear audio, you'll see the image generated by the software oscilloscope.

Using the two sliders at the top-left, you can configure the intensity/brightness of the beam using the intensity slider, as well as the hue of the lines drawn.

Main interface

image

Main settings panel

image

The main settings panel is where you can open new files and folders, as well as edit open files and create new files. There is also text on this panel describing the current frequency, the currently open file, and information about audio recordings.

File modification

In the top-left are all the file modification buttons. These allow you to do the following:

  • Open one of the supported file types using "Choose File" which opens up a file dialog allowing you to choose a file
  • Edit the file in a separate text editor window that is currently open using "Edit File"
  • Close the currently open file using "Close File"
  • Open a folder containing supported file types using "Choose Folder" which opens all of the files in osci-render

Editing files happens instantaneously and changes are immediately reflected in the visuals and audio. This means you can modify .obj files, for example, from within osci-render and change the position of vertices, or type a sentence and have it be written in real-time when editing .txt files.

When you have multiple files open, you can cycle between them using the 'j' and 'k' keys on your keyboard to move forward and backwards through the list of files. You can also press 'i' to start the playback of all the files so that they cycle automatically. You can then use 'u' and 'o' to change the speed of the playback and press 'i' again to stop playback.

When you open a folder, the files will be opened in alphabetical order, so if you want to cycle through the files in a particular order, you should keep this in mind.

If you close all open files, the file name will change to "No files open!" and any audio will stop.

You can also create new files from within osci-render using the text box and dropdown at the bottom of the panel to type the name and choose the type of the file, and then create it using "Create File". This will add it to the files you currently have open. When you create a file like this, an appropriate demo/example file is created for the file type chosen:

.lua example file
--
-- .lua files can be used to make your own custom audio sources!
-- Lua documentation: https://www.lua.org/docs.html
--
-- All variables are saved between calls to this script.
--
-- Below is a simple example of an audio effect that makes a
-- nice visual on an oscilloscope and shows off some of the
-- functionality available.
--
-- The variable 'step' used below is incremented with every
-- call to this script, starting at 1.
--

-- sets 'theta' to 0 initially, or the previous value of
-- 'theta' the last time this script ran
theta = theta or 0

-- updates 'theta' using 'step'
theta = theta + math.sqrt(step) / 1000000000

-- 'slider_a', 'slider_b', ..., 'slider_e' are controlled by
-- the respective sliders in the .lua file settings
left_scale = 0.3 * slider_a
right_scale = 0.3 * slider_b

-- Returns audio samples that will be played back
return {
  -- left audio channel
  left_scale * math.tan(theta * step),
  -- right audio channel
  right_scale * math.tan(theta * step + math.pi / 2)
}

Draws an experimental oscillating tan function.

.svg example file
<svg><path d="M 0,0 a 75,75 0 1,0 150,0 a 75,75 0 1,0 -150,0"/></svg>

Draws a circle.

.obj example file
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/4/2 7/6/2 8/7/2
f 8/8/3 7/9/3 5/10/3 6/11/3
f 6/12/4 2/13/4 4/5/4 8/14/4
f 2/13/5 1/1/5 3/4/5 4/5/5
f 6/11/6 5/10/6 1/1/6 2/13/6

Draws a 3D cube.

.txt example file
hello

Draws the text hello.

Other

When recording audio, the text at the bottom of the panel will change to "Recording...", and upon saving the file successfully it will change to the file location where it has been saved.

The current 'actual' frequency of the audio is displayed for each audio channel next to "L/R Frequency". This will potentially be very different to the Target frequency slider as it considers the frequency after all effects have been applied. This is calculated using a Fourier Transform, which works by 'binning' different frequencies, so this number is an approximation of the real frequency you hear.

The Octave slider snaps to specific values between -5 and +5. These values correspond to the number of octave shifts to be applied to the current frequency as specified in the Target frequency slider. Increasing the audio by a single octave has the effect of doubling the target frequency, whereas decreasing the octave halves the frequency.

The Mic Volume slider controls how sensitive microphone input affecting sliders is. If you change the range of this slider using the Sliders menu item, you can also make the microphone input decrease a slider's value.

3D .obj settings panel

image

The 3D .obj settings panel contains all settings relating to the rotation and focal length of 3D objects in osci-render. Every setting here can be animated and controlled by MIDI.

The focal length slider changes the focal length of the camera looking at the object. Smaller values will make the make look smaller and perspective effects will be stronger, whereas larger values increase the size of the image and make the image look 'flatter'.

The three sliders for 3D rotation, "Rotate x", "Rotate y", and "Rotate z" control the three axes of rotation for the object. When the rotation speed is set to zero, this will change the rotation in that axis without any other animated movement. When the rotation speed is positive, it will rotate in the direction specified by these sliders, and a negative speed moves it in the opposite direction.

"Rotate speed" controls how fast the object rotates according to the three sliders controlling the rotation direction. Currently, the higher the frequency of the image, the faster the object will rotate as each 'frame' is rendered more quickly. This is something that I am unsure whether should be changed so that rotation speed is consistent. It currently has the nice effect of spinning faster when the frequency is higher, but there is no way of having a consistent rotation speed. If you have any feedback on this, please let me know!

"Reset Rotation" sets all of the rotation axes sliders and rotation speed slider to 0 so that the 3D object is in the original default rotation.

You can also control the x and y axes of rotation by moving the mouse if you select "Rotate with Mouse". This moves the x and y slider values between 0 and 1 depending on the position of your mouse within osci-render and can be a nice way of positioning the object. You can press the Esc key once you are in a position you're happy with to disable any more mouse rotation without needing to click on the checkbox again.

Fixed rotation axis

Next to the three rotation axes in 3D .obj file settings, and also next to the 3D rotation sliders for the 3D perspective effect, there is the following icon:

fixed rotation axis

When clicking this, it will change to a red colour and the rotation in that axis will not be rotated/animated when the rotation speed is non-zero. This means that you can position the object on one axis and then spin it on another axis - rather than both axes spinning at the same time. You can think of this as setting the rotation speed on that specific axis to 0.

.lua settings panel

image

The sliders in this panel are used to control the pre-defined variables available to use in a Lua live-coding script.

Each slider corresponds to the value of a pre-defined variable with a similar name when writing a Lua program. For example, the value of "Slider a" can be accessed as slider_a in Lua. These can all be animated and controlled with MIDI as you could expect.

"Reset Step Counter" resets the value of the step pre-defined variable back to the original value of 1. This can be useful if you are writing a Lua program that uses step as a way of animating through different sounds or visuals - you can 'reset' the animation using this.

Audio effects panel

audio effects

The audio effects are one of the most important parts of osci-render. Here, you can make any transformations to the image and audio that you're rendering from the files you've opened.

This covers each in detail, along with a GIF of every effect so you can see the visual effect.

All effects have been designed in a way such that a value of 0 means that the effect is completely disabled and will not change the visuals or audio, whereas higher values apply the effect more.

Every single effect can be animated.

Vector cancelling

Vector cancelling is one of the least intuitive effects available. It works by negating or 'flipping' the occasional audio sample by multiplying it by -1 in the left/x and right/y audio channels. The value of the slider determines how frequently the audio samples are flipped. The default value (approx. 0.111) flips the audio samples every other sample, and as you increase the slider, it will negate more often, making the mirrored image the prominent one.

This makes use of extremely high-frequency audio so visualisation of this will vary a lot on different CRT displays. It also does not 'accurately' display using the software oscilloscope, so this is really one for you to test with yourself.

vector cancelling

This effect has very little effect on the audio, other than the volume. You will hear some artifacts from the extremely high-frequency audio, but otherwise, it's not obvious it's even enabled from the audio alone.

At the default value of around 0.111, you will hear almost nothing, but still get an image on your display. This is because at this value every other sample is inverted and the audio 'cancels' itself out - making it almost silent.

Bit crush

Bit crush makes the image look pixelated by limiting the precision of every audio sample or point drawn to the display. This means that values such as 0.11 or 0.09 might get rounded to 0.1 creating a 'blocky' feel to the visuals and audio.

bit crush

At small values, the audio doesn't change much whilst the image is clearly different. However, at much larger values, both the image and audio are extremely distorted.

Wobble

The wobble effect applies a sine wave to the image at a similar frequency to the image. This displaces it with a signal that is almost the same, creating an oscillation or 'wobble' effect. Occasionally, this can apply a sine wave that is exactly the same frequency, removing any oscillation and displacing the image slightly.

wobble

You will hear a faint sine wave if your image is being rendered in audible ranges frequencies that gets louder as you increase the value of the slider.

The frequency of the sine wave is calculated when you enable the wobble effect using the actual frequency of the output audio, as reported in the Main settings panel. It is re-calculated whenever you change the file you have open or re-enable the effect.

Smoothing

Smoothing uses a window average over some of the last audio samples to 'smoothen' out the image and reduce any rapid changes in frequency by making sharp corners more curved. The value of the slider increases the size of the window that is used to take an average, making the image smoother.

smoothing

You can clearly hear the effect this has on the audio, reducing any 'buzzing' or other unwanted artifacts of rapid changes in frequency.

Vertical shift

For every other audio sample or point drawn, the vertical shift applies a displacement to the image either in the positive or negative y direction. This means in the first sample drawn, it might increase the y position, and in the next sample, it will decrease the y position. This gives the effect of making horizontal lines 'thicker'.

vertical shift

This is another effect that can vary how it looks a lot depending on what kind of display you use since it takes advantage of very high-frequency audio to change how the image looks, without changing the audio much at all.

Horizontal shift

Very similar to the vertical shift effect, except now the displacement is in the x-axis. This creates very similar visuals to the vertical shift, but now the vertical lines look thicker.

horizontal shift

Translation

The translation effect moves the image around the screen according to the values of the translation x and y textboxes. The x textbox controls the horizontal position of the image, and the y textbox controls the vertical position.

As well as changing the value in the textbox, you can also move the object more intuitively using your mouse by selecting the "Translate with Mouse" checkbox. Whilst this is checked, moving your mouse will move the image on the screen. Press Esc to disable the checkbox and leave the image in the position of your mouse.

To reset the translation back to the origin without having to accurately position your mouse or change the value of the textboxes, just click "Reset Translation".

Translation scale changes how sensitive the image is to translation. It is most useful for when you want to make fine adjustments to the translation using your mouse, or want to significantly increase the translation.

translation

You can also choose to translate the image in an ellipse, using the x and y translation values to control the size and shape of the ellipse. The translation speed slider can be used to control how quickly it moves in the elliptical path.

This effect has almost no effect on the audio and is mainly a visual effect. You might hear the effects of applying translation in an ellipse if you have an extremely high translation speed.

Volume

There are two volume sliders in osci-render. The first, "Master volume", is self-explanatory and controls the volume of the whole program. This is set to 0 by default if in the project select screen you tick the checkbox for "Start muted", and otherwise has a default value of 3.

The second volume slider modifies the sine waves of the non-main audio channels when playing back midi. This is used to control how much of these sine waves you want to see and hear, as they will distort the image.

2D Rotate

2D Rotate speed controls how quickly the image rotates. When the value is at 0, no rotation is applied. At values larger than 0 it rotates anti-clockwise, and at values less than 0 it rotates clockwise.

rotate

You can hear a 'rotation' or panning audio effect when this is active and can clearly hear how quickly it is rotating.

3D Perspective

3D perspective treats the image as a 3D object. It acts as if the image is projected onto a flat face and then that face is rotated around in 3D.

When the 3D perspective slider is at 0, no effect is applied. Between 0 and 1, the effect is partially applied, and at 1 it is fully enabled. You can get some very interesting effects when it's between 0 and 1 as it is halfway between being a 3D object and being a 2D image.

The 3D Distance slider controls how far away from the camera the 3D object is. If you increase the value, it will have the effect of making the image smaller. Since this is perspective projected from 3D coordinates into 2D, perspective distortion will appear. This also controls the value of the z pre-defined variable when modifying the depth function.

The 3D rotation controls mirror those in the 3D .obj settings panel, including the fixed rotation axis icons to the right of the rotation axis sliders.

"Reset 3D Rotation" behaves as you would expect and resets all the rotation sliders back to 0.

Using Lua live-coding, you can also modify the function that controls the 3D position of every point drawn to the screen. This could allow you to change the depth of the image in a sine wave based on the x position of the point being drawn, or even create a sphere that has the image as a texture wrapped around it.

When clicking "Modify Depth Function", a text editor will appear allowing you to edit the Lua. There are three pre-defined variables: x, y, and z, corresponding to the initial x position, y position, and z position (depth) of the image. The most simple script, return { x, y, z } will apply no effect and return the same position and depth as default.

3D perspective

Some example depth functions in Lua:

-- Vary the depth of the image based on the x position

return {
  -- x-position
  x,
  -- y-position
  y,
  -- z-position
  z + 0.1 * math.sin(10 * x),
}
y = 0.4 * y

-- Equirectangular projection to wrap the image onto a sphere

return {
  -- x-position
  math.sin(math.pi * x) * math.cos(math.pi * y),
  -- y-position
  math.sin(math.pi * -y),
  -- z-position
  z + math.cos(math.pi * x) * math.cos(math.pi * y),
}

Trace max and trace min

Trace max/min control how much of the image is currently being drawn. The value of trace max controls the proportion of the image that is drawn starting from the start of the image draw path and ending at the value of trace max as a proportion of the entire draw path. Trace min is slightly different since it starts at the end of the image and ends at the value of trace min as a proportion of the draw path in reverse.

This means that the only difference between trace max and trace min is the direction that the trace effect is applied.

trace max

trace min

Frequency slider

image

The frequency slider controls how quickly the image is drawn, which in turn controls the frequency of the audio. A target frequency of 400Hz, for example, would draw the image 400 times per second, and the loudest real frequency is usually some multiple of 400Hz. This is named "Target frequency" as it is not necessarily the actual frequency you will hear. Any audio effects applied will have an impact on the current frequency, meaning the L/R frequencies in the Main settings panel could be vastly different to the frequency specified on this slider.

Text editor

image

The text editor is used to edit files in osci-render. While it is currently quite barebones, it provides syntax highlighting and other standard features of a text editor, including undo/redo, and find and replace. Any changes made to a file are immediately reflected in the audio/visuals.

For more specific documentation on the general features of the text editor, it's best to look at CodeMirror's documentation as this is the library I am using.

Currently, there are two ways of opening the text editor. The most common way is by pressing the "Edit File" button in the Main settings panel, which allows you to modify the file you currently have open. The other place this is used is for the 3D perspective effect to define a custom program using Lua live-coding to transform the 3D coordinates given as an input.

You can only have one text editor window open at once, which means that any previous window will close if you open the text editor again. This currently causes a few issues since the same text editor is reused, such as undoing/redoing carrying over between different files.

MIDI control

todo

Microphone input

Microphone input in osci-render allows you to fluctuate the value of a slider using the volume of your microphone. This can be useful if you are using osci-render for visuals and want some audio-reactive visuals that change depending on the volume of the surroundings.

Next to most sliders, you will see a microphone icon. When you click on the icon, it will turn red indicating that the microphone is being used to change the slider value. If you speak into your microphone, you should see the slider move slightly, increasing the value of the slider from wherever it was.

microphone button

When this is active, the slider is locked in place and cannot be changed from the value set before enabling microphone control.

To change the sensitivity of the microphone input, you can use the "Mic Volume" slider in the Main settings panel. If you change the range of this slider using the Sliders menu item, you can also make the microphone input decrease a slider's value.

If osci-render doesn't detect a microphone when you start the program (your default microphone), the icons will have a line through them indicating they are disabled. Clicking on the icons in this case will do nothing.

Animation

Almost everything in osci-render that can be controlled using a slider can also be animated. Animation works by changing the slider values automatically over the slider's range. Therefore, changing the range of the slider will also change the range of the animation for that slider.

By default, every slider has a 'static' animation, which just means there is no animation at all and the effect's value is the same as the value displayed by the slider. To change the animation type, just use the dropdown to the right of most sliders in osci-render:

animation types

When you choose an animation other than Static, it will change the colour of the knob of the effect you are now animating to green. This clearly highlights which effects or sliders are static and which are being animated.

There are currently seven animation types: Static, Sine, Square, Seesaw, Triangle, Sawtooth, and Reverse Sawtooth. For all non-static animations, the speed of the animation is controlled with the slider that replaces the original slider, now with a green knob. The slider now controls the frequency in Hz of the animation. This can range from 0Hz to 100Hz as labelled on the slider.

Below are details of each non-static animation type:

Sine

Sine animates along a sine wave. It has smooth motion, like Seesaw, but spends less time at the minimum and maximum values.

Square

Square animates along a square wave. Half of the time it is at the minimum value of the effect, and the rest of the time it's at the maximum value. This flickers between the min and max values.

Seesaw

The Seesaw animation type moves more quickly depending on how far away the current value of the effect is from the minimum and maximum values. This has the effect of moving very slowly at the start, and then quickly accelerating to the mid-point, where it will quickly slow down again at the end.

Once it reaches the end, the direction of the animation is reversed and it returns back to the original position.

seesaw

Triangle

The Triangle animation type animates along a triangle wave. It has a constant speed throughout the animation from minimum to maximum effect value, and then back to the minimum. This makes the animation abruptly change direction when the effect's value reaches the maximum. In older versions of osci-render, this was called 'Linear'.

triangle

Sawtooth

Sawtooth animates along a sawtooth wave. It is the same as Triangle in that the speed is constant, however, it does not change direction and instead increases from the minimum effect value to the maximum and then instantly snaps back to the minimum afterwards. In older versions of osci-render, this was called 'Forward'.

sawtooth

Reverse Sawtooth

Reverse Sawtooth is the same as Sawtooth, except it moves in the opposite direction. It starts at the maximum effect value and decreases to the minimum before it snaps back to the maximum. In older versions of osci-render, this was called 'Reverse'.

reverse sawtooth

Blender

Osci-render has a Blender plugin that allows you to visualise a Blender scene in osci-render using Grease Pencil Line Art.

This video explains how to install and use osci-render with Blender, with an overview of the process below:

  • Download the latest Blender add-on from Releases named osci-render-blender-addon.zip
  • Install and enable the add-on in Blender
  • "osci-render settings" menu will now appear under "Render Properties"
  • Open osci-render
  • Click "Connect to osci-render" in Blender

image

  • If the text next to "Choose File" in the Main settings panel changes to "Rendering from external input" you have successfully connected
  • Add a camera to the scene in Blender (if there isn't one already)
  • Add a Scene Line Art object to the scene
  • Press Shift+A and navigate to Grease Pencil > Scene Line Art
  • Go to "Modifier Properties" of the newly created Line Art object
  • Click "Bake Line Art" under the the "Bake" settings to generate line art for the current animation/scene/camera
  • You should now see the scene on your oscilloscope!

Projects

todo