Skip to content
This repository was archived by the owner on Nov 23, 2023. It is now read-only.

Commit 660bcc4

Browse files
add NotoDAWOutput; prep for release
1 parent d4c3138 commit 660bcc4

File tree

14 files changed

+886
-1103
lines changed

14 files changed

+886
-1103
lines changed

examples/notochord/analysis.scd

Lines changed: 0 additions & 73 deletions
This file was deleted.

examples/notochord/autopitch-demo.scd

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
Quarks.install("API")
2-
31
// in this example the Linnstrument displays an interface to perform pitches
42
// by their likelihood under the NotePredictor model instead of by MIDI number
53

@@ -11,11 +9,13 @@ Quarks.install("API")
119

1210
// model predictions are conditioned on performed timing and velocity.
1311

12+
Quarks.install("API")
13+
//depends: IILinnstrument https://github.com/Intelligent-Instruments-Lab/IILinnstrument
14+
1415
(
1516
~noto = Notochord();
1617

1718
// ~noto.notochordCmd; // show the current notochord terminal command
18-
// ~noto.notochordPath = "/Users/victor/Downloads/1368.ckpt";
1919
~noto.notochordPath = "/Users/victor/Downloads/notochord_lakh_20G.ckpt";
2020

2121
~noto.startNotochord; // runs notochord for you in a terminal
@@ -113,8 +113,8 @@ s.waitForBoot{
113113
~synths.add(key -> Synth(\pluck, [\vel, vel/127]));
114114
// query for pitch
115115
~noto.queryFeed(
116-
\fix_instrument, ~instrument,
117-
\fix_vel, vel, \fix_time, dt,
116+
\next_inst, ~instrument,
117+
\next_vel, vel, \next_time, dt,
118118
\handle, key, *(~noto.globalArgs++pitch_args)
119119
)
120120
}

examples/notochord/classes/notochord.sc

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
NotoOutput {
44
var <port, <sema, <nAnon;
5-
*new { | deviceName=nil, portName=nil, anonInstruments=8 |
5+
*new { | deviceName=nil, portName=nil, anonInstruments=32 |
66
^super.new.init(deviceName, portName, anonInstruments)
77
}
88

@@ -13,8 +13,8 @@ NotoOutput {
1313
deviceName = deviceName?"IAC Driver";
1414
portName = portName?"Bus 1";
1515
},
16-
\linux, { "Notochord: TODO: default MIDI device on Linux".postln },
17-
\windows, { "Notochord: TODO: default MIDI device on Windows".postln }
16+
\linux, { "Notochord: TODO: default MIDI output device on Linux".postln },
17+
\windows, { "Notochord: TODO: default MIDI output device on Windows".postln }
1818
);
1919
nAnon = anonInstruments;
2020
port = MIDIOut.newByName(deviceName, portName).latency_(0);
@@ -25,10 +25,37 @@ NotoOutput {
2525
128.do{arg note; 16.do{arg chan;
2626
port.noteOff(chan, note, vel)}}
2727
}
28+
29+
isDrum { | inst |
30+
inst;
31+
^ ((inst>128)&&(inst<=256)) || (inst>(256+nAnon))
32+
}
2833
}
2934

30-
NotoDAWOutput : NotoOutput {
31-
//TODO
35+
NotoMappingOutput : NotoOutput {
36+
var <>instrumentMap, <>drumMap;
37+
38+
init { | deviceName, portName, anonInstruments |
39+
super.init(deviceName, portName, anonInstruments);
40+
instrumentMap = Dictionary.new;
41+
drumMap = Dictionary.new;
42+
}
43+
44+
send { | inst, pitch, vel |
45+
var channel;
46+
channel = instrumentMap.at(inst);
47+
(isDrum(inst) && drumMap.includesKey(pitch)).if{
48+
pitch = drumMap.at(pitch)};
49+
channel.isNil.if{
50+
"WARNING: unmapped instrument in NotoDAWOutput.send".postln; ^nil};
51+
// pitch.isNil.if{
52+
// "WARNING: unmapped drum in NotoDAWOutput.send".postln; ^nil};
53+
(vel>0).if{
54+
port.noteOn(channel, pitch, vel);
55+
}{
56+
port.noteOff(channel, pitch);
57+
};
58+
}
3259
}
3360

3461
NotoFluidOutput : NotoOutput {
@@ -42,15 +69,9 @@ NotoFluidOutput : NotoOutput {
4269
instChannels = TwoWayIdentityDictionary.new;
4370
}
4471

45-
isDrum { | inst |
46-
inst;
47-
^ ((inst>128)&&(inst<=256)) || (inst>(256+nAnon))
48-
}
49-
5072
send { | inst, pitch, vel |
5173
var channel;
5274
sema.wait;
53-
inst;
5475
// check if this instrument has a channel
5576
channel = instChannels.at(inst);
5677
channel.isNil.if{
@@ -99,27 +120,44 @@ NotoFluidOutput : NotoOutput {
99120

100121
// MIDI input API
101122
NotoInput {
102-
var <device;
123+
var <deviceUID;
103124

104-
*new { | deviceName |
105-
^super.new.init(deviceName)
125+
*new { | deviceName, portName |
126+
^super.new.init(deviceName, portName)
106127
}
107128

108-
init { | deviceName |
129+
init { | deviceName, portName |
130+
var device;
109131
MIDIClient.initialized.not.if{MIDIClient.init};
110132
MIDIIn.connectAll;
111133

134+
Platform.case(
135+
\osx, {
136+
deviceName = deviceName?"IAC Driver";
137+
},
138+
\linux, { "Notochord: TODO: default MIDI input device on Linux".postln },
139+
\windows, { "Notochord: TODO: default MIDI input device on Windows".postln }
140+
);
141+
112142
device = MIDIClient.sources.detect{
113-
|e| e.device.containsi(deviceName)
114-
}.uid;
143+
|e| e.device.containsi(deviceName) && portName.isNil.if{true}{e.device.containsi(portName)}
144+
};
145+
device.isNil.if{
146+
"WARNING: NotoInput: MIDI input device not found".postln;
147+
("available sources are: "++MIDIClient.sources).postln;
148+
deviceUID=0;
149+
}{
150+
("NotoInput: using MIDI input device \""++deviceName++"\"").postln;
151+
deviceUID=device.uid;
152+
}
115153
}
116154

117155
noteOn { |fn|
118-
MIDIdef.noteOn(\input_on++device, fn, srcID:device);
156+
MIDIdef.noteOn(\input_on++deviceUID, fn, srcID:deviceUID).permanent_(true);
119157
}
120158

121159
noteOff { |fn|
122-
MIDIdef.noteOff(\input_off++device, fn, srcID:device);
160+
MIDIdef.noteOff(\input_off++deviceUID, fn, srcID:deviceUID).permanent_(true);
123161
}
124162
}
125163

@@ -149,7 +187,7 @@ Notochord {
149187
pendingQueries = 0;
150188
};
151189

152-
}, "notochord/query_return");
190+
}, "notochord/query_return").permanent_(true);
153191

154192
// initial handler which just prints the argument dict
155193
handler = _.postln;
@@ -162,7 +200,8 @@ Notochord {
162200
argKeys = [
163201
\allow_end,
164202
\min_time, \max_time, \min_vel, \max_vel,
165-
\include_instrument, \exclude_instrument,
203+
\include_inst, \exclude_inst,
204+
\allow_anon,
166205
\include_pitch, \exclude_pitch, \include_drum,
167206
\instrument_temp, \pitch_temp,
168207
\rhythm_temp, \timing_temp, \velocity_temp,
@@ -251,8 +290,8 @@ Notochord {
251290
// C. forecasted events which may not play
252291
// A requires: schedule, once locked in: feed, finally play
253292
// B requires: schedule, once locked in: query_feed, finally play
254-
// C requires: schedule, if locked in: feed/lay (treat as A),
255-
// -- if anything is scheduled between this event and the source event, cancel
293+
// C requires: schedule, once locked in: as A
294+
// -- but if anything else gets scheduled before it, cancel
256295

257296
// alternate view:
258297
//
@@ -276,16 +315,4 @@ Notochord {
276315
// this would feed an event and then query *only* delta to next event
277316
// a separate query would complete the event just-in-time, *only* if it isn't
278317
// first pre-empted, which prevents wasting time on other attributes
279-
// gets hairy when there are other constraints though
280-
281-
282-
/*(
283-
~noto = Notochord();
284-
~input = NotoInput();
285-
~output = NotoOutput();
286-
287-
288-
~input.callback = {};
289-
~noto.callback = {};
290-
291-
)*/
318+
// gets hairy when there are other constraints though

0 commit comments

Comments
 (0)