Scripting in Studio One
-
- KVRAF
- Topic Starter
- 6159 posts since 4 Dec, 2004
For anyone trying this stuff, here's a Windows app that does the initial work, creates basic working script outlines, makes the zipping of code changes to packages easier, and also optionally adds a collection of useful JS functions.
*** Please read the README!!.rtf and the in-application help before using it.***
Much better than doing it all manually...
*** Please read the README!!.rtf and the in-application help before using it.***
Much better than doing it all manually...
You do not have the required permissions to view the files attached to this post.
- KVRian
- 1277 posts since 10 Oct, 2002 from Barcelona
Thanks! I created something similar for hardware devicesv in studio one but failed in the id generation...
Now I've got some Jokers to spend on.
Now I've got some Jokers to spend on.
- KVRist
- 33 posts since 19 Jan, 2017
LawrenceF, thank you for sharing your instructions, tools and scripts, very helpful, I appreciate that. S1 scripting tutorials on Youtube not available anymore?
Anto
MeldaProduction
MeldaProduction
- KVRian
- 1277 posts since 10 Oct, 2002 from Barcelona
Never used studio one in my Mac Pro... Maybe it is the time to switch...
-
- KVRer
- 10 posts since 4 Apr, 2014
Can you please re-upload the video from the first post?
Question, these package files, are they json-files?
The "Hello World-Readme" says: " Zip up the files with a *.package extender".
Thanks for any help!
Edit
I tried the tool from this post, but I cannot make packages.
Did I do anything wrong?
Edit 2
Ok I created a package (manually) and it worked.
It gets shown in the track section (not in the toolbar).
Thanks anyway
Question, these package files, are they json-files?
The "Hello World-Readme" says: " Zip up the files with a *.package extender".
Thanks for any help!
Edit
I tried the tool from this post, but I cannot make packages.
Did I do anything wrong?
Edit 2
Ok I created a package (manually) and it worked.
It gets shown in the track section (not in the toolbar).
Thanks anyway
You do not have the required permissions to view the files attached to this post.
-
- KVRer
- 10 posts since 4 Apr, 2014
Hello,
I would like to ask something basic.
I checked the source code of Studio One X.
Inside of the file code.js there is this line:
include_file("functions.js");
Later in this same code such a line:
this.functions.renameEvent(track, newname.toString());
I calculated 1 and 1 and was thinking, "Ok, the function renameEvent must be inside of the file functions.js".
I checked that file, but there is no sign of such function.
That confuses me pretty much!
Why does it still work??
Edit
I meant the source code of trackactions.package
I would like to ask something basic.
I checked the source code of Studio One X.
Inside of the file code.js there is this line:
include_file("functions.js");
Later in this same code such a line:
this.functions.renameEvent(track, newname.toString());
I calculated 1 and 1 and was thinking, "Ok, the function renameEvent must be inside of the file functions.js".
I checked that file, but there is no sign of such function.
That confuses me pretty much!
Why does it still work??
Edit
I meant the source code of trackactions.package
-
crossovercable crossovercable https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=329708
- KVRian
- 576 posts since 26 May, 2014
I think Lawrence has retired so maybe someone else here could help or knows someone ?
I need to get the chords from Studio One into the Band In A Box VST.
The BiabVST will allow pasting of text chords
or
If you have same bar of the same chord
|%| or | / / / / |
a chord on beat 2
| / Gm / /|
beat 3
| / / Gm /|
beat 4
| / / /Gm|
There is a ChordsToMarkers.package (.zip) see .js below
If someone with javascript & S1 know how could mod this to write the chords to the BiabVST format and send it to clipboard or save as text in song folder then open, it would be much appreciated.
The other script gets the chords from the Biab Plugin to Studio One but I need from Studio One to Biab Plugin
BiabPluginChords.package see .js below
I need to get the chords from Studio One into the Band In A Box VST.
The BiabVST will allow pasting of text chords
Code: Select all
[Chords]
|F|C|Bb|C|F|C|Bb|C|
|Dm|C|Bb|Gm|Dm|Bb|F|C|
|F|%|%|%|Gm|%|%|%|
|Bb|%|%|%|F|%|Gm|%|
|F|%|%|%|
[ChordsEnd]Code: Select all
[Chords]
|F / / / |C / / / |Bb / / / |C / / / |F / / / |C / / / |Bb / / / |C / / / |
|Dm / / / |C / / / |Bb / / / |Gm / / / |Dm / / / |Bb / / / |F / / / |C / / / |
|F / / / | / / / / | / / / / | / / / / |Gm / / / | / / / / | / / / / | / / / / |
|Bb / / / | / / / / | / / / / | / / / / |F / / / | / / / / | Gm / / /| / / / / |
|F| / / / / | / / / / | / / / / |
[ChordsEnd]|%| or | / / / / |
a chord on beat 2
| / Gm / /|
beat 3
| / / Gm /|
beat 4
| / / /Gm|
There is a ChordsToMarkers.package (.zip) see .js below
If someone with javascript & S1 know how could mod this to write the chords to the BiabVST format and send it to clipboard or save as text in song folder then open, it would be much appreciated.
The other script gets the chords from the Biab Plugin to Studio One but I need from Studio One to Biab Plugin
BiabPluginChords.package see .js below
Code: Select all
function chordsToMarkers()
{
this.interfaces = [ Host.Interfaces.IEditTask ];
// ---------------------------------------------------------------------
this.prepareEdit = function (context)
{
return Host.Results.kResultOk;
}
// ---------------------------------------------------------------------
// select all chord events
Host.GUI.Commands.interpretCommand("Edit", "Select All")
this.performEdit = function (context)
{
var chords = [];
// collect selected chords into an array
var iterator = context.iterator;
while (!iterator.done())
{
var event = iterator.next();
// error trap ---------------------------------
if (event.mediaType != undefined)
{
Host.GUI.alert("Please select the first chord on timeline.")
return;
}
// --------------------------------------------
chords.push(event)
}
// deselect all chord events
Host.GUI.Commands.interpretCommand("Edit", "Deselect All")
// move to the first chord event
Host.GUI.Commands.interpretCommand("Navigation", "First Event")
// iterate the array
for (i = 0; i < chords.length; i++)
{
// get the current chord name
var chord = Host.Objects.getObjectByUrl
('://hostapp/DocumentManager/ActiveDocument/EventInspector/EventInfo/ChordSelector')
.findParameter('chord').string;
// locate to the current chord position
Host.GUI.Commands.interpretCommand('Transport', 'Locate Selection')
// create a new marker named after the current chord
Host.GUI.Commands.interpretCommand('Marker', 'Insert Named',
false, Host.Attributes(["Name", chord]))
// move to the next chord event
Host.GUI.Commands.interpretCommand("Navigation", "Right")
}
return Host.Results.kResultOk;
}
}
function createInstance()
{
return new ChordsToMarkers;
}Code: Select all
function BiabPluginChords()
{
this.interfaces = [ Host.Interfaces.IEditTask ];
// ---------------------------------------------------------------------
this.prepareEdit = function (context)
{
return Host.Results.kResultOk;
}
// ---------------------------------------------------------------------
this.performEdit = function (context)
{
// set Cursor follows Edit Position
Host.GUI.Commands.interpretCommand('Transport', 'Cursor follows Edit Position',
false, Host.Attributes(["State", "1"]))
// get the current tempo
var bpm = Host.Objects.getObjectByUrl
('://hostapp/DocumentManager/ActiveDocument/Environment/TransportPanel')
.findParameter('tempo').string;
// play cursor
var cursor = Host.Objects.getObjectByUrl
('://hostapp/DocumentManager/ActiveDocument/Environment/TransportPanel')
.findParameter('primaryTime');
// host command shortcut
var cmd = Host.GUI.Commands;
///////////////////////////////////////////////////////////////////////////////
////////////////////// OPEN / READ BIAB TEXT FILE ////////////////////////////
///////////////////////////////////////////////////////////////////////////////
var fileSelector = Host.Classes.createInstance("CCL:FileSelector");
var textType = {filename: ("Song.txt"),description: ("Song.txt"), extension: "txt", mimetype: "text"};
fileSelector.addFilter(textType);
fileSelector.runOpen();
var path = fileSelector.getPath()
// array to hold the chord names
var chordNames = [];
context.editor.selection.showHideSuspended = true;
// cut the manually created event to the clipboard
cmd.interpretCommand("Edit", "Cut")
var file = Host.IO.openTextFile(path);
if (file)
{
while (!file.endOfStream)
{
var text = file.readLine()
if (text.indexOf("StyleTimeSig=") > -1 )
{
if (text == 'StyleTimeSig=4')
{
var beat_per_measure1 = '4'
}
if (text == 'StyleTimeSig=3')
{
var beat_per_measure1 = '3'
}
}
}
}
// read the file and paste events, and build the name array
var file = Host.IO.openTextFile(path);
if (file)
{
while (!file.endOfStream)
{
var text = file.readLine()
// only read the lines with Chord=
if (text.indexOf("Chord=") > -1)
{
// strip unnecessary text
text = text.replace("Chord=", "")
text = text.toLowerCase( )
// split the delimited text and get the data
data = text.split(',')
var bar1 = data[0];
var beat = data[1];
var bar = Number(bar1) + 1
var beat_per_measure = Number(beat_per_measure1)
// push name to a reference array for the chord names
chordNames.push (data[2])
// move the play cursor and paste a new event
//var beat_per_measure = 4
// get the current tempo
//var bpm = Host.Objects.getObjectByUrl
//('://hostapp/DocumentManager/ActiveDocument/Environment/TransportPanel')
//.findParameter('tempo').string;
var position = (bar * (((((beat_per_measure) / bpm) * 60))))
var beat = data[1]
//if (beat > 1) {position = (position + (beat * .5))}
if (beat > 1) {position = (position + (((((beat - 1) / bpm) * 60))))}
cursor.setValue(position, true)
// paste the new event
cmd.interpretCommand("Edit", "Paste")
}
}
file.close();
}
// select and name all of the new chord events
var chordSelector = Host.Objects.getObjectByUrl
('object://hostapp/DocumentManager/ActiveDocument/TrackList/CurrentChord/EventInfo/ChordSelector')
.findParameter('chord')
// select the first event
cmd.interpretCommand('Navigation', 'First Event')
// iterate the names array and name each event
for (i = 0; i < chordNames.length; i++)
{
chordSelector.setValue(chordNames[i], true)
cmd.interpretCommand('Navigation', 'Next Event')
}
context.editor.selection.showHideSuspended = false;
cmd.interpretCommand("Transport", "Return to Zero")
//Host.GUI.alert(beat_per_measure)
return Host.Results.kResultOk;
}
}
function createInstance()
{
return new BiabPluginChords;
}
- KVRAF
- 1722 posts since 21 Sep, 2007 from USA
Ok, I quickly hacked something together based on the script examples you shared; the lack of documentation on scripting in Studio One makes it a daunting challenge. What I came up with is flawed in a number of ways (e.g. it assumes 4 beats per bar; chords need to align to a beat boundary; etc.), and it may fail on edge cases, but overall, it may do what you need for typical use cases. [This script package is provided as-is with no implied warranty of fitness for its purpose]
The new script installs itself under the Event menu item as "Chords to Biab Text File":

The Chords track needs to be visible and have chords in it, and the first chord in the chord track should be selected before invoking the script:

The new script installs itself under the Event menu item as "Chords to Biab Text File":

The Chords track needs to be visible and have chords in it, and the first chord in the chord track should be selected before invoking the script:

crossovercable wrote: Fri Jun 04, 2021 10:22 pm I think Lawrence has retired so maybe someone else here could help or knows someone ?
I need to get the chords from Studio One into the Band In A Box VST.
The BiabVST will allow pasting of text chordsorCode: Select all
[Chords] |F|C|Bb|C|F|C|Bb|C| |Dm|C|Bb|Gm|Dm|Bb|F|C| |F|%|%|%|Gm|%|%|%| |Bb|%|%|%|F|%|Gm|%| |F|%|%|%| [ChordsEnd]If you have same bar of the same chordCode: Select all
[Chords] |F / / / |C / / / |Bb / / / |C / / / |F / / / |C / / / |Bb / / / |C / / / | |Dm / / / |C / / / |Bb / / / |Gm / / / |Dm / / / |Bb / / / |F / / / |C / / / | |F / / / | / / / / | / / / / | / / / / |Gm / / / | / / / / | / / / / | / / / / | |Bb / / / | / / / / | / / / / | / / / / |F / / / | / / / / | Gm / / /| / / / / | |F| / / / / | / / / / | / / / / | [ChordsEnd]
|%| or | / / / / |
a chord on beat 2
| / Gm / /|
beat 3
| / / Gm /|
beat 4
| / / /Gm|
You do not have the required permissions to view the files attached to this post.
Last edited by tonedef71 on Thu Jun 10, 2021 4:48 am, edited 2 times in total.
[Core i7 8700 | 32GB DDR4 | Win11 x64 | Studio One 7 Pro | WASAPI ]
-
crossovercable crossovercable https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=329708
- KVRian
- 576 posts since 26 May, 2014
Thanks.
I get an error line 135 "file.writeString" is not a function
It saves the text file and writes "[Chords]" then has the error.
This is the only other info I have from the sos0008.zip above and
https://github.com/aminya/studioone_fun ... nctions.js
I get an error line 135 "file.writeString" is not a function
It saves the text file and writes "[Chords]" then has the error.
This is the only other info I have from the sos0008.zip above and
https://github.com/aminya/studioone_fun ... nctions.js
Reference: functions.js
include_file "functions.js";
EVENTS ================================================== =================
getEvents (context)
Returns an array of all selected events such as clips or musical notes.
name clip [string]
color integer
isMuted mute state [bool]
length
startTime .musical
endtime
transpose
tune
velocity
pitch
getTrack() returns track object
ARRANGE TRACKS ================================================== =======
getTracks (context)
Returns an array of all arrange tracks, hidden or otherwise.
name` track name [string]
mute mute state [bool]
layers number of layers [integer]
mediaType Audio, Music, etc, [string]
isMuted() returns bool
color integer
getSelectedTracks (context)
Returns an array of all selected arrange tracks.
MIXER CHANNELS ================================================== ======
getChannels (context)
Returns an array of all selected normal mixer channels
canMuteSolo can mute/solo (read-only) [bool]
mute mute state [bool]
solo solo state [bool]
soloSave solo save state [bool]
maxVolume maximum volume scaler (read-only) [float]
volume volume scaler (0..max) [float]
pan stereo pan position (0 = R, 0.5 = C, 1.0 = L) [float]
isSubChannel channel is part of a structure and is usually routed to a parent bus
canDisable can disable (read-only) [bool]
disabled disable state [bool]
label channel label [string]
channelType string: Audio, AudioInput, AudioOutput, AudioTrack, AudioSynth,
AudioGroup, AudioEffect, AudioSynthBus, AudioVCA, Music, MusicTrack
mediaType string: None, Audio, Music, ...
editGroup string: edit group id
speaker integer bitfield, only for audio channel
channel.findParameter("color").value
getSelectedChannels (context)
Returns an array of all selected normal mixer channels
getMasterBus (context)
Returns the master bus channel object.
resetFaders (context)
Reset all selected faders to unity gain, ignores channel grouping
faderLevel (context,value)
Change the gain of a fader.
faderLevel(context,-2)
dbToFloat (value)
Convert a decible value to floating point for fader settings. Number.
floatToDb (value)
Convert a floating point value to decible for fader settings. Number.
FILE I/O ================================================== ================
getSongFolder (fileName)
Used to get the song folder to write a file there.
var path = getSongFolder(fileName);
let textFile = Host.IO.createTextFile(path);
writeTextFile (folder, filename, text)
Write all text to a simple text file in the user data folder. Folder is your custom folder there.
readTextFile (folder, filename)
Reads a text file line by line from the user data folder, returns an array of the lines.
saveNewVersion (name)
Stores a new version of the song with the name, for backup.
HELPER FUNCTIONS ================================================== ======
getAllPropertyNames(obj)
Used to parse the object model, returns message box list
command (cat, action, arg, val, arg2, val2)
Fire a command action with optional arguments
command("Event", "Rename Events", "My Event", "1")
alert (msg)
Simple message box, formats all to string.
ask (msg)
Simple question message box.
if(Host.GUI.ask ("Are you sure you want to do this?")
!= Host.GUI.Constants.kYes) {return;}
getColorVal (hexcolor)
Converts web color to interger for setting color
Studio One Scripts Help
This appication is designed to facilitate writing script packages for Presonus Studio One, making it easier for users to create script outlines as they write new command actions and functions for that audio workstation. Scripting in Studio One assumes a basic working knowledge of the JavaScript language to continue coding whatever functions you intend to add to Studio One after the basic outline is created by this application.
Legal Notice: There is no warranty of any kind, implied or otherwise, associated with this application. It's perfectly safe but by using it you directly agree to use it at your own risk and that the author will not be held responsible or liable for any perceived damages including loss of time, work, etc, etc.
Initial Setup
Click the Setup menu and Set Studio One Scripts Folder menu and select the \Documents\Studio One #\Scripts folder that you copied on installation.
Click the Setup menu and Set Default Code Editor to see your default code editor for *.js and *.xml files. Visual Studio Code is highly recommended. If you don't have it, you can download it here: https://code.visualstudio.com/download
General Operation
.
Fill out the text fields, and click Create New Script to generate a script package outline in a new folder. The new folder will list in the listbox. Click Make Package to push it to the Studio One\Scripts\user folder as a *.package file.
To make it a *.package file for Studio One select a folder in the list and click the Make Package button which will zip the folder up into a package file and copy it to the Studio One \Scripts folder. Restart Studio One to see your action.
UI Controls
Include functions.js
This also adds the functions.js file to your source code script folder, which is a collection of useful JS functions to get your started scripting in Studio One. To view a reference of the included functions click the Show Functions button for in application help.
Include skin files
This includes the files and folders for a basic skin and GUI to get your started. If you include skin files your new script will automatically launch a simple GUI with an edit box on it.
Show tooltip help
Turn this on to get more detailed help on all GUI parts.
Create New Script
Create a new script and folder or update an existing script folder.
Open Code Editor
Launch the code editor as set in the menu Setup > Set Default Code Editor.
Open Studio One
This launches Studio One and keeps a reference to the process so that you can close (toggle, "Close Studio One") and restart it from the same buttton when necessary to refresh class files.
Add New Class
When a folder is selected in the list, clicking this button adds a new class to the classfactory.xml file.
Make Package
When a folder is selected in the list, clicking this button zips up the folder into a *.package file and writes it to the Studio One\Scripts\user folder. The \user folder is created automatically there to keep user scripts separated from scripts the application installs.
Source Code List
The list box contains all of the raw source code from this application's \source folder. To open any of it in your default editor double click an folder item in the list.
Last edited by crossovercable on Tue Jun 08, 2021 2:28 am, edited 1 time in total.
-
crossovercable crossovercable https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=329708
- KVRian
- 576 posts since 26 May, 2014
I might be doing something wrong at my end ?
if the writeString don't work maybe it could use insert string or concat to keep adding each event to a string then just use file.writeLine(string); ?
If there is no way to get S1 time signature then I can have 2 scripts 1 for 4/4 and 1 for 3/4. The Biab Plugin still uses |/ / / /| for 3/4 pasting chords so it would just insert "/|" instead of "|"
if the writeString don't work maybe it could use insert string or concat to keep adding each event to a string then just use file.writeLine(string); ?
Code: Select all
[Chords]|F / / / |C / / / |Bb / / / |C / / / |F / / / |C / / / |Bb / / / |C / / / |Dm / / / |C / / / |Bb / / / |Gm / / / |Dm / / / |Bb / / / |F / / / |C / / / |F / / / | / / / / | / / / / | / / / / |Gm / / / | / / / / | / / / / | / / / / |Bb / / / | / / / / | / / / / | / / / / |F / / / | / / / / | Gm / / /| / / / / |F| / / / / | / / / / | / / / / |[ChordsEnd]-
crossovercable crossovercable https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=329708
- KVRian
- 576 posts since 26 May, 2014
I got it to work with a single file.writeLine but it's messed up a bit, I will have a break from it now and get back to it later, if you see where the problem is please let me know thanks.


Code: Select all
// TARGET:
//[Chords]
//|F|C|Bb|C|F|C|Bb|C|
//|Dm|C|Bb|Gm|Dm|Bb|F|C|
//|F|%|%|%|Gm|%|%|%|
//|Bb|%|%|%|F|%|Gm|%|
//|F|%|%|%|
//[ChordsEnd]
// or
//[Chords]
//|F / / / |C / / / |Bb / / / |C / / / |F / / / |C / / / |Bb / / / |C / / / |
//|Dm / / / |C / / / |Bb / / / |Gm / / / |Dm / / / |Bb / / / |F / / / |C / / / |
//|F / / / | / / / / | / / / / | / / / / |Gm / / / | / / / / | / / / / | / / / / |
//|Bb / / / | / / / / | / / / / | / / / / |F / / / | / / / / | Gm / / /| / / / / |
//|F| / / / / | / / / / | / / / / |
//[ChordsEnd]
function ChordsToBiabTextFile()
{
// Setup
this.interfaces = [Host.Interfaces.IEditTask];
this.prepareEdit = function(context) {
return Host.Results.kResultOk;
}
// Host command shortcut
var cmd = Host.GUI.Commands;
// Select all chord events
cmd.interpretCommand("Edit", "Select All");
this.performEdit = function(context) {
// Array to hold the chord events
var chords = [];
// Collect selected chords into an array
var iterator = context.iterator;
while (!iterator.done()) {
var chordEvent = iterator.next();
var it = chordEvent.createIterator();
// Ensure that first chord was selected...
if (chordEvent.mediaType != undefined) {
Host.GUI.alert("Please select the first chord on timeline.")
return;
}
var chordName = chordEvent.name; // Why always empty?
var startTime = chordEvent.startTime.string; // "0001.01.01.00" BAR.BEAT.TICK.FRAME
var endTime = chordEvent.endTime.string; // "0001.01.01.00" BAR.BEAT.TICK.FRAME
var timeParts = {"startTime": startTime.split("."), "endTime": endTime.split(".")};
var data = {
"event": chordEvent,
"name": chordName,
"startTime": { "time": startTime, "bar": Number(timeParts["startTime"][0]), "beat": Number(timeParts["startTime"][1]), "subBeat": Number(timeParts["startTime"][2]), "hundredths": Number(timeParts["startTime"][3]) },
"endTime": { "time": endTime, "bar": Number(timeParts["endTime"][0]), "beat": Number(timeParts["endTime"][1]), "subBeat": Number(timeParts["endTime"][2]), "hundredths": Number(timeParts["endTime"][3]) }
};
chords.push(data);
}
// Sort chords by start time
chords.sort(function(a, b){
var comp1 = a.startTime.time;
var comp2 = b.startTime.time;
return (comp1 < comp2) ? -1 : ((comp1 > comp2) ? 1 : 0);
});
// De-select all chord events
cmd.interpretCommand("Edit", "Deselect All");
// Select the first event
cmd.interpretCommand('Navigation', 'First Event');
var fileSelector = Host.Classes.createInstance("CCL:FileSelector");
var textType = {
filename: ("*.txt"),
description: ("Song.txt"),
extension: "txt",
mimetype: "text"
};
fileSelector.addFilter(textType);
fileSelector.runSave();
// Store the user selected path
var path = fileSelector.getPath();
var file = Host.IO.createTextFile(path);
if (file) {
//file.writeLine("[Chords]");
var textchords = "";
textchords += "[Chords]";
var previousBar = -99999;
var previousBeat = 0;
var previousChordName = "";
// Iterate over the array of chords and examine each event
var i;
for (i = 0; i < chords.length; i++) {
var chordData = chords[i];
var previousChordData = (i > 0) ? chords[i - 1] : chords[i];
var chordSelector = Host.Objects.getObjectByUrl('object://hostapp/DocumentManager/ActiveDocument/EventInspector/EventInfo/ChordSelector');
//var chordSelector = Host.Objects.getObjectByUrl('object://hostapp/DocumentManager/ActiveDocument/TrackList/CurrentChord/EventInfo/ChordSelector');
// Get the current chord name
var chordName = chordSelector.findParameter('chord').string;
var bar = chordData.startTime.bar;
var beat = chordData.startTime.beat;
var subBeat = chordData.startTime.subBeat;
var beatsPerBar = 4; // How to determine this dynamically???
var beatPosition = (bar - 1) * beatsPerBar + beat;
var previousBeatPosition = (previousChordData.startTime.bar - 1) * beatsPerBar + previousChordData.startTime.beat;
var beatsSinceLastChord = beatPosition - previousBeatPosition;
// Add any intervening repeated chords
if (subBeat < 2) {
var n;
for (n = 0; n < beatsSinceLastChord - 1; ++n) {
//file.writeLine(" /");
textchords += "/ ";
}
}
var newBar = false;
if (bar > previousBar) {
if (bar % 8 == 0) {
// Close previous bar and start a new line
//file.writeLine("|");
//textchords += "|";
}
// Start a new bar
newBar = true;
//file.writeLine("|");
textchords += "|";
previousBar = bar;
}
if (subBeat < 2) {
if (!newBar) {
// Add whitespace between chords
//file.writeLine(" ");
//textchords += " ";
}
if (chordName != previousChordName) {
//file.writeLine(chordName);
textchords += chordName + " ";
previousChordName = chordName;
}
else {
//file.writeLine("/");
textchords += "/ ";
}
}
cmd.interpretCommand('Navigation', 'Next Event');
}
if (previousBar % 8 != 0) {
// Close final bar
//file.writeLine("|");
textchords += "|";
}
textchords += "[ChordsEnd]";
file.writeLine(textchords);
//file.writeLine("[ChordsEnd]");
file.close();
}
Host.GUI.alert("Chords Copied to txt file");
cmd.interpretCommand("Transport", "Return to Zero");
return Host.Results.kResultOk;
}
}
function createInstance()
{
return new ChordsToBiabTextFile;
}- KVRAF
- 1722 posts since 21 Sep, 2007 from USA
Hmm... I wonder why TextFile.writeString() was not available to you. What version of Studio One are you running? I am running Studio One 5 Pro (v5.2.1 build 64495).
Regarding the number of chords per par, I wonder if there is a way to set up the script so that it would accept a value from the user as input. Hmm...
Regarding the number of chords per par, I wonder if there is a way to set up the script so that it would accept a value from the user as input. Hmm...
You're on the right track. Try this code instead, and let me know if it works (I won't be able to test these changes myself until later this evening):crossovercable wrote: Mon Jun 07, 2021 8:43 am I got it to work with a single file.writeLine but it's messed up a bit, I will have a break from it now and get back to it later, if you see where the problem is please let me know thanks.
Code: Select all
// TARGET:
//[Chords]
//|F|C|Bb|C|F|C|Bb|C|
//|Dm|C|Bb|Gm|Dm|Bb|F|C|
//|F|%|%|%|Gm|%|%|%|
//|Bb|%|%|%|F|%|Gm|%|
//|F|%|%|%|
//[ChordsEnd]
// or
//[Chords]
//|F / / / |C / / / |Bb / / / |C / / / |F / / / |C / / / |Bb / / / |C / / / |
//|Dm / / / |C / / / |Bb / / / |Gm / / / |Dm / / / |Bb / / / |F / / / |C / / / |
//|F / / / | / / / / | / / / / | / / / / |Gm / / / | / / / / | / / / / | / / / / |
//|Bb / / / | / / / / | / / / / | / / / / |F / / / | / / / / | Gm / / /| / / / / |
//|F| / / / / | / / / / | / / / / |
//[ChordsEnd]
function ChordsToBiabTextFile()
{
// Setup
this.interfaces = [Host.Interfaces.IEditTask];
this.prepareEdit = function(context) {
return Host.Results.kResultOk;
}
// Host command shortcut
var cmd = Host.GUI.Commands;
// Select all chord events
cmd.interpretCommand("Edit", "Select All");
this.performEdit = function(context) {
// Array to hold the chord events
var chords = [];
// Collect selected chords into an array
var iterator = context.iterator;
while (!iterator.done()) {
var chordEvent = iterator.next();
var it = chordEvent.createIterator();
// Ensure that first chord was selected...
if (chordEvent.mediaType != undefined) {
Host.GUI.alert("Please select the first chord on timeline.")
return;
}
var chordName = chordEvent.name; // Why always empty?
var startTime = chordEvent.startTime.string; // "0001.01.01.00" BAR.BEAT.SUBBEAT.SUBSUBBEAT
var endTime = chordEvent.endTime.string; // "0001.01.01.00" BAR.BEAT.SUBBEAT.SUBSUBBEAT
var timeParts = {"startTime": startTime.split("."), "endTime": endTime.split(".")};
var data = {
"event": chordEvent,
"name": chordName,
"startTime": { "time": startTime, "bar": Number(timeParts["startTime"][0]), "beat": Number(timeParts["startTime"][1]), "subBeat": Number(timeParts["startTime"][2]), "hundredths": Number(timeParts["startTime"][3]) },
"endTime": { "time": endTime, "bar": Number(timeParts["endTime"][0]), "beat": Number(timeParts["endTime"][1]), "subBeat": Number(timeParts["endTime"][2]), "hundredths": Number(timeParts["endTime"][3]) }
};
chords.push(data);
}
// Sort chords by start time
chords.sort(function(a, b) {
var comp1 = a.startTime.time;
var comp2 = b.startTime.time;
return (comp1 < comp2) ? -1 : ((comp1 > comp2) ? 1 : 0);
});
// De-select all chord events
cmd.interpretCommand("Edit", "Deselect All");
// Select the first event
cmd.interpretCommand('Navigation', 'First Event');
var fileSelector = Host.Classes.createInstance("CCL:FileSelector");
var textType = {
filename: ("*.txt"),
description: ("Song.txt"),
extension: "txt",
mimetype: "text"
};
fileSelector.addFilter(textType);
fileSelector.runSave();
// Store the user selected path
var path = fileSelector.getPath();
var file = Host.IO.createTextFile(path);
if (file) {
var textBuffer = [];
textBuffer.push("[Chords]\r\n");
var previousBar = -99999;
var previousBeat = 0;
var previousChordName = "";
// Iterate over the array of chords and examine each event
var i;
for (i = 0; i < chords.length; i++) {
var chordData = chords[i];
var previousChordData = (i > 0) ? chords[i - 1] : chords[i];
var chordSelector = Host.Objects.getObjectByUrl('object://hostapp/DocumentManager/ActiveDocument/EventInspector/EventInfo/ChordSelector');
//var chordSelector = Host.Objects.getObjectByUrl('object://hostapp/DocumentManager/ActiveDocument/TrackList/CurrentChord/EventInfo/ChordSelector');
// Get the current chord name
var chordName = chordSelector.findParameter('chord').string;
var bar = chordData.startTime.bar;
var beat = chordData.startTime.beat;
var subBeat = chordData.startTime.subBeat;
var beatsPerBar = 4; // How to determine this dynamically???
var beatPosition = (bar - 1) * beatsPerBar + beat;
var previousBeatPosition = (previousChordData.startTime.bar - 1) * beatsPerBar + previousChordData.startTime.beat;
var beatsSinceLastChord = beatPosition - previousBeatPosition;
// Add any intervening repeated chords
if (subBeat < 2) {
var n;
for (n = 0; n < beatsSinceLastChord - 1; ++n) {
textBuffer.push(" /");
}
}
var newBar = false;
if (bar > previousBar) {
if (bar % 8 == 0) {
// Close previous bar and start a new line
textBuffer.push("|\r\n");
}
// Start a new bar
newBar = true;
textBuffer.push("|");
previousBar = bar;
}
if (subBeat < 2) {
if (!newBar) {
// Add whitespace between chords
textBuffer.push(" ");
}
if (chordName != previousChordName) {
textBuffer.push(chordName);
previousChordName = chordName;
}
else {
textBuffer.push("/");
}
}
cmd.interpretCommand('Navigation', 'Next Event');
}
if (previousBar % 8 != 0) {
// Close final bar
textBuffer.push("|\r\n");
}
textBuffer.push("[ChordsEnd]\r\n");
var text = textBuffer.join("");
file.writeLine(text);
file.close();
}
Host.GUI.alert("Chords copied to txt file");
cmd.interpretCommand("Transport", "Return to Zero");
return Host.Results.kResultOk;
}
}
function createInstance()
{
return new ChordsToBiabTextFile;
}
[Core i7 8700 | 32GB DDR4 | Win11 x64 | Studio One 7 Pro | WASAPI ]
-
crossovercable crossovercable https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=329708
- KVRian
- 576 posts since 26 May, 2014
It's 4.5 I'm testing on, best to have it backward compatible I suppose.
Maybe:
Unless there is some way to read the time signature numerator/denominator events ?
It's still much the same but but get's the chords instantly without the long loop I had.
Found more here https://github.com/aminya/studioone_fun ... nctions.js

Maybe:
Code: Select all
//ask (msg)
//Simple question message box.
//if(Host.GUI.ask ("Are you sure you want to do this?")
//!= Host.GUI.Constants.kYes) {return;}
if(Host.GUI.ask ("4/4 yes 3/4 no")
!= Host.GUI.Constants.kYes) {return;}It's still much the same but but get's the chords instantly without the long loop I had.
Found more here https://github.com/aminya/studioone_fun ... nctions.js

Last edited by crossovercable on Tue Jun 08, 2021 2:15 am, edited 1 time in total.
-
crossovercable crossovercable https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=329708
- KVRian
- 576 posts since 26 May, 2014
Also I made a script in Reaper to fit pre recorded audio to the chord track (region track),
The audio file has a csv with the same name with it, the file is imported then start time and end time is adjusted to fit the chord region. The color are for different song sections verse, chorus, ending etc.. Users/musicians create the source tracks with a variety of popular chords and share them. With S1 using Melodyne any unavailable chords can be created from another chord.
If S1 can import media via script, set the start end time and read the color integer of the chords this would be great.
Guitar, Strum, Ev8 4-4 120bpm.wav
Guitar, Strum, Ev8 4-4 120bpm.csv
The audio file has a csv with the same name with it, the file is imported then start time and end time is adjusted to fit the chord region. The color are for different song sections verse, chorus, ending etc.. Users/musicians create the source tracks with a variety of popular chords and share them. With S1 using Melodyne any unavailable chords can be created from another chord.
If S1 can import media via script, set the start end time and read the color integer of the chords this would be great.
Guitar, Strum, Ev8 4-4 120bpm.wav
Guitar, Strum, Ev8 4-4 120bpm.csv
Code: Select all
#,Name,Start,End,Length,Color
R1,,1.1.00,3.1.00,2.0.00,FF80C0
R2,A,3.1.00,5.1.00,2.0.00,E41A27
R3,A#,5.1.00,7.1.00,2.0.00,E41A27
R4,B,7.1.00,9.1.00,2.0.00,E41A27
R5,C,9.1.00,11.1.00,2.0.00,E41A27
R6,C#,11.1.00,13.1.00,2.0.00,E41A27
R7,D,13.1.00,15.1.00,2.0.00,E41A27