X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fsurfaces%2Fosc%2Fosc.cc;h=282873053e46808025f6ee7432af6af11f0675f9;hb=c784f7096611da43db0604a7641253773d5f1515;hp=d7e86d86b0d4bccb7c0b0a4b436f4cdb21b7b77b;hpb=19e62735022768134da1ac7141312be78523e003;p=ardour.git diff --git a/libs/surfaces/osc/osc.cc b/libs/surfaces/osc/osc.cc index d7e86d86b0..282873053e 100644 --- a/libs/surfaces/osc/osc.cc +++ b/libs/surfaces/osc/osc.cc @@ -100,6 +100,7 @@ OSC::OSC (Session& s, uint32_t port) , default_gainmode (0) , tick (true) , bank_dirty (false) + , scrub_speed (0) , gui (0) { _instance = this; @@ -421,6 +422,9 @@ OSC::register_callbacks() REGISTER_CALLBACK (serv, "/goto_start", "f", goto_start); REGISTER_CALLBACK (serv, "/goto_end", "", goto_end); REGISTER_CALLBACK (serv, "/goto_end", "f", goto_end); + REGISTER_CALLBACK (serv, "/scrub", "f", scrub); + REGISTER_CALLBACK (serv, "/jog", "f", jog); + REGISTER_CALLBACK (serv, "/jog/mode", "f", jog_mode); REGISTER_CALLBACK (serv, "/rewind", "", rewind); REGISTER_CALLBACK (serv, "/rewind", "f", rewind); REGISTER_CALLBACK (serv, "/ffwd", "", ffwd); @@ -478,7 +482,6 @@ OSC::register_callbacks() REGISTER_CALLBACK (serv, "/set_loop_range", "f", set_loop_range); REGISTER_CALLBACK (serv, "/set_session_range", "", set_session_range); REGISTER_CALLBACK (serv, "/set_session_range", "f", set_session_range); - // /toggle_monitor_* not working (comented out) REGISTER_CALLBACK (serv, "/toggle_monitor_mute", "", toggle_monitor_mute); REGISTER_CALLBACK (serv, "/toggle_monitor_mute", "f", toggle_monitor_mute); REGISTER_CALLBACK (serv, "/toggle_monitor_dim", "", toggle_monitor_dim); @@ -542,6 +545,9 @@ OSC::register_callbacks() REGISTER_CALLBACK (serv, "/master/pan_stereo_position", "f", master_set_pan_stereo_position); REGISTER_CALLBACK (serv, "/monitor/gain", "f", monitor_set_gain); REGISTER_CALLBACK (serv, "/monitor/fader", "f", monitor_set_fader); + REGISTER_CALLBACK (serv, "/monitor/mute", "i", monitor_set_mute); + REGISTER_CALLBACK (serv, "/monitor/dim", "i", monitor_set_dim); + REGISTER_CALLBACK (serv, "/monitor/mono", "i", monitor_set_mono); // Controls for the Selected strip REGISTER_CALLBACK (serv, "/select/recenable", "i", sel_recenable); @@ -700,7 +706,7 @@ OSC::listen_to_route (boost::shared_ptr strip, lo_address addr) OSCSurface *s = get_surface(addr); uint32_t ssid = get_sid (strip, addr); - OSCRouteObserver* o = new OSCRouteObserver (strip, addr, ssid, s->gainmode, s->feedback); + OSCRouteObserver* o = new OSCRouteObserver (strip, addr, ssid, s); route_observers.push_back (o); strip->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::route_lost, this, boost::weak_ptr (strip)), this); @@ -867,6 +873,16 @@ OSC::catchall (const char *path, const char* types, lo_arg **argv, int argc, lo_ ret = 0; } else + if (!strncmp (path, "/access_action/", 15)) { + if (!(argc && !argv[0]->i)) { + std::string action_path = path; + + access_action (action_path.substr(15)); + std::cout << "access_action path = " << action_path.substr(15) << "\n"; + } + + ret = 0; + } else if (strcmp (path, "/strip/listen") == 0) { cerr << "set up listener\n"; @@ -1009,9 +1025,9 @@ OSC::catchall (const char *path, const char* types, lo_arg **argv, int argc, lo_ ret = 0; } - if ((ret && _debugmode == Unhandled)) { + if ((ret && _debugmode != Off)) { debugmsg (_("Unhandled OSC message"), path, types, argv, argc); - } else if ((!ret && _debugmode == All)) { + } else if (!ret && _debugmode == All) { debugmsg (_("OSC"), path, types, argv, argc); } @@ -1162,41 +1178,65 @@ OSC::routes_list (lo_message msg) if (!session) { return; } - for (int n = 0; n < (int) session->nroutes(); ++n) { + OSCSurface *sur = get_surface(get_address (msg)); + sur->no_clear = true; - boost::shared_ptr r = session->get_remote_nth_route (n); + for (int n = 0; n < (int) sur->nstrips; ++n) { - if (r) { + boost::shared_ptr s = get_strip (n + 1, get_address (msg)); + + if (s) { + // some things need the route + boost::shared_ptr r = boost::dynamic_pointer_cast (s); lo_message reply = lo_message_new (); - if (boost::dynamic_pointer_cast(r)) { + if (s->presentation_info().flags() & PresentationInfo::AudioTrack) { lo_message_add_string (reply, "AT"); - } else if (boost::dynamic_pointer_cast(r)) { + } else if (s->presentation_info().flags() & PresentationInfo::MidiTrack) { lo_message_add_string (reply, "MT"); - } else { - lo_message_add_string (reply, "B"); + } else if (s->presentation_info().flags() & PresentationInfo::AudioBus) { + // r->feeds (session->master_out()) may make more sense + if (r->direct_feeds_according_to_reality (session->master_out())) { + // this is a bus + lo_message_add_string (reply, "B"); + } else { + // this is an Aux out + lo_message_add_string (reply, "AX"); + } + } else if (s->presentation_info().flags() & PresentationInfo::MidiBus) { + lo_message_add_string (reply, "MB"); + } else if (s->presentation_info().flags() & PresentationInfo::VCA) { + lo_message_add_string (reply, "V"); } - lo_message_add_string (reply, r->name().c_str()); - lo_message_add_int32 (reply, r->n_inputs().n_audio()); - lo_message_add_int32 (reply, r->n_outputs().n_audio()); - lo_message_add_int32 (reply, r->muted()); - lo_message_add_int32 (reply, r->soloed()); - /* XXX Can only use order at this point */ - //lo_message_add_int32 (reply, r->presentation_info().order()); - // try this instead. - lo_message_add_int32 (reply, get_sid (r, get_address (msg))); - - if (boost::dynamic_pointer_cast(r) - || boost::dynamic_pointer_cast(r)) { - - boost::shared_ptr t = boost::dynamic_pointer_cast(r); - lo_message_add_int32 (reply, (int32_t) t->rec_enable_control()->get_value()); + lo_message_add_string (reply, s->name().c_str()); + if (r) { + // routes have inputs and outputs + lo_message_add_int32 (reply, r->n_inputs().n_audio()); + lo_message_add_int32 (reply, r->n_outputs().n_audio()); + } else { + // non-routes like VCAs don't + lo_message_add_int32 (reply, 0); + lo_message_add_int32 (reply, 0); + } + if (s->mute_control()) { + lo_message_add_int32 (reply, s->mute_control()->get_value()); + } else { + lo_message_add_int32 (reply, 0); + } + if (s->solo_control()) { + lo_message_add_int32 (reply, s->solo_control()->get_value()); + } else { + lo_message_add_int32 (reply, 0); + } + lo_message_add_int32 (reply, n + 1); + if (s->rec_enable_control()) { + lo_message_add_int32 (reply, s->rec_enable_control()->get_value()); } - //Automatically listen to routes listed - listen_to_route(r, get_address (msg)); + //Automatically listen to stripables listed + listen_to_route(s, get_address (msg)); lo_send_message (get_address (msg), "#reply", reply); lo_message_free (reply); @@ -1209,6 +1249,12 @@ OSC::routes_list (lo_message msg) lo_message_add_string (reply, "end_route_list"); lo_message_add_int64 (reply, session->frame_rate()); lo_message_add_int64 (reply, session->current_end_frame()); + if (session->monitor_out()) { + // this session has a monitor section + lo_message_add_int32 (reply, 1); + } else { + lo_message_add_int32 (reply, 0); + } lo_send_message (get_address (msg), "#reply", reply); @@ -1240,6 +1286,7 @@ OSC::refresh_surface (lo_message msg) { if (address_only) { // get rid of all surfaces and observers. + // needs change to only clear those for this address on all ports clear_devices(); } OSCSurface *s = get_surface(get_address (msg)); @@ -1284,6 +1331,16 @@ OSC::clear_devices () delete so; } } + // delete cue observers + for (CueObservers::iterator x = cue_observers.begin(); x != cue_observers.end();) { + OSCCueObserver* co; + if ((co = dynamic_cast(*x)) != 0) { + delete co; + } else { + ++x; + } + } + // clear out surfaces _surface.clear(); } @@ -1386,7 +1443,8 @@ OSC::get_surface (lo_address addr) s.sel_obs = 0; s.expand = 0; s.expand_enable = false; - s.strips = get_sorted_stripables(s.strip_types); + s.cue = false; + s.strips = get_sorted_stripables(s.strip_types, s.cue); s.nstrips = s.strips.size(); _surface.push_back (s); @@ -1463,6 +1521,13 @@ OSC::_recalcbanks () } else { _set_bank (sur->bank, addr); } + if (sur->no_clear) { + // This surface uses /strip/list tell it routes have changed + lo_message reply; + reply = lo_message_new (); + lo_send_message (addr, "/strip/list", reply); + lo_message_free (reply); + } } } @@ -1514,7 +1579,7 @@ OSC::_set_bank (uint32_t bank_start, lo_address addr) usleep ((uint32_t) 10); } - s->strips = get_sorted_stripables(s->strip_types); + s->strips = get_sorted_stripables(s->strip_types, s->cue); s->nstrips = s->strips.size(); uint32_t b_size; @@ -1533,7 +1598,7 @@ OSC::_set_bank (uint32_t bank_start, lo_address addr) // top bank is always filled if there are enough strips for at least one bank bank_start = (uint32_t)((s->nstrips - b_size) + 1); } - //save bank in case we have had to change it + //save bank after bank limit checks s->bank = bank_start; if (s->feedback[0] || s->feedback[1]) { @@ -1551,8 +1616,7 @@ OSC::_set_bank (uint32_t bank_start, lo_address addr) } } // light bankup or bankdown buttons if it is possible to bank in that direction - if (s->feedback[4]) { - // these two messages could be bundled + if (s->feedback[4] && !s->no_clear) { lo_message reply; reply = lo_message_new (); if ((s->bank > (s->nstrips - s->bank_size)) || (s->nstrips < s->bank_size)) { @@ -1689,6 +1753,176 @@ OSC::record_enabled (lo_message msg) lo_message_free (reply); } +int +OSC::scrub (float delta, lo_message msg) +{ + if (!session) return -1; + + scrub_place = session->transport_frame (); + + float speed; + + int64_t now = ARDOUR::get_microseconds (); + int64_t diff = now - scrub_time; + if (diff > 35000) { + // speed 1 (or 0 if jog wheel supports touch) + speed = delta; + } else if ((diff > 20000) && (fabs(scrub_speed) == 1)) { + // add some hysteresis to stop excess speed jumps + speed = delta; + } else { + speed = (int)(delta * 2); + } + scrub_time = now; + if (scrub_speed == speed) { + // Already at that speed no change + return 0; + } + scrub_speed = speed; + + if (speed > 0) { + if (speed == 1) { + session->request_transport_speed (.5); + } else { + session->request_transport_speed (1); + } + } else if (speed < 0) { + if (speed == -1) { + session->request_transport_speed (-.5); + } else { + session->request_transport_speed (-1); + } + } else { + session->request_transport_speed (0); + } + + return 0; +} + +int +OSC::jog (float delta, lo_message msg) +{ + if (!session) return -1; + + OSCSurface *s = get_surface(get_address (msg)); + + string path = "/jog/mode/name"; + switch(s->jogmode) + { + case JOG : + text_message (path, "Jog", get_address (msg)); + if (delta) { + jump_by_seconds (delta / 5); + } + break; + case SCRUB: + text_message (path, "Scrub", get_address (msg)); + scrub (delta, msg); + break; + case SHUTTLE: + text_message (path, "Shuttle", get_address (msg)); + if (delta) { + double speed = get_transport_speed (); + set_transport_speed (speed + (delta / 8)); + } else { + set_transport_speed (0); + } + break; + case SCROLL: + text_message (path, "Scroll", get_address (msg)); + if (delta > 0) { + access_action ("Editor/scroll-forward"); + } else if (delta < 0) { + access_action ("Editor/scroll-backward"); + } + break; + case TRACK: + text_message (path, "Track", get_address (msg)); + if (delta > 0) { + set_bank (s->bank + 1, msg); + } else if (delta < 0) { + set_bank (s->bank - 1, msg); + } + break; + case BANK: + text_message (path, "Bank", get_address (msg)); + if (delta > 0) { + bank_up (msg); + } else if (delta < 0) { + bank_down (msg); + } + break; + case NUDGE: + text_message (path, "Nudge", get_address (msg)); + if (delta > 0) { + access_action ("Common/nudge-playhead-forward"); + } else if (delta < 0) { + access_action ("Common/nudge-playhead-backward"); + } + break; + case MARKER: + text_message (path, "Marker", get_address (msg)); + if (delta > 0) { + next_marker (); + } else if (delta < 0) { + prev_marker (); + } + break; + default: + break; + + } + return 0; + +} + +int +OSC::jog_mode (float mode, lo_message msg) +{ + if (!session) return -1; + + OSCSurface *s = get_surface(get_address (msg)); + + switch((uint32_t)mode) + { + case JOG : + s->jogmode = JOG; + break; + case SCRUB: + s->jogmode = SCRUB; + break; + case SHUTTLE: + s->jogmode = SHUTTLE; + break; + case SCROLL: + s->jogmode = SCROLL; + break; + case TRACK: + s->jogmode = TRACK; + break; + case BANK: + s->jogmode = BANK; + break; + case NUDGE: + s->jogmode = NUDGE; + break; + case MARKER: + s->jogmode = MARKER; + break; + default: + PBD::warning << "Jog Mode: " << mode << " is not valid." << endmsg; + break; + lo_message reply = lo_message_new (); + lo_message_add_int32 (reply, s->jogmode); + lo_send_message (get_address(msg), "/jog/mode", reply); + lo_message_free (reply); + + } + jog (0, msg); + return 0; + +} + // master and monitor calls int OSC::master_set_gain (float dB) @@ -1797,6 +2031,42 @@ OSC::monitor_set_fader (float position) return 0; } +int +OSC::monitor_set_mute (uint32_t state) +{ + if (!session) return -1; + + if (session->monitor_out()) { + boost::shared_ptr mon = session->monitor_out()->monitor_control(); + mon->set_cut_all (state); + } + return 0; +} + +int +OSC::monitor_set_dim (uint32_t state) +{ + if (!session) return -1; + + if (session->monitor_out()) { + boost::shared_ptr mon = session->monitor_out()->monitor_control(); + mon->set_dim_all (state); + } + return 0; +} + +int +OSC::monitor_set_mono (uint32_t state) +{ + if (!session) return -1; + + if (session->monitor_out()) { + boost::shared_ptr mon = session->monitor_out()->monitor_control(); + mon->set_mono (state); + } + return 0; +} + int OSC::route_get_sends(lo_message msg) { if (!session) { @@ -1838,7 +2108,8 @@ OSC::route_get_sends(lo_message msg) { lo_message_add_int32(reply, p->active() ? 1 : 0); } } - // if used dedicated message path to identify this reply in async operation. Naming it #reply wont help the client to identify the content. + // if used dedicated message path to identify this reply in async operation. + // Naming it #reply wont help the client to identify the content. lo_send_message(get_address (msg), "/strip/sends", reply); lo_message_free(reply); @@ -1900,7 +2171,8 @@ OSC::route_get_receives(lo_message msg) { } } - // I have used a dedicated message path to identify this reply in async operation. Naming it #reply wont help the client to identify the content. + // I have used a dedicated message path to identify this reply in async operation. + // Naming it #reply wont help the client to identify the content. lo_send_message(get_address (msg), "/strip/receives", reply); lo_message_free(reply); return 0; @@ -1951,7 +2223,6 @@ OSC::route_solo (int ssid, int yn, lo_message msg) if (s) { if (s->solo_control()) { s->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup); - return route_send_fail ("solo", ssid, (float) s->solo_control()->get_value(), get_address (msg)); } } @@ -2002,8 +2273,7 @@ OSC::sel_solo (uint32_t yn, lo_message msg) } if (s) { if (s->solo_control()) { - s->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup); - return sel_fail ("solo", (float) s->solo_control()->get_value(), get_address (msg)); + session->set_control (s->solo_control(), yn ? 1.0 : 0.0, PBD::Controllable::NoGroup); } } return sel_fail ("solo", 0, get_address (msg)); @@ -2546,7 +2816,6 @@ OSC::sel_pan_position (float val, lo_message msg) if (s) { if(s->pan_azimuth_control()) { s->pan_azimuth_control()->set_value (s->pan_azimuth_control()->interface_to_internal (val), PBD::Controllable::NoGroup); - return sel_fail ("pan_stereo_position", s->pan_azimuth_control()->internal_to_interface (s->pan_azimuth_control()->get_value ()), get_address (msg)); return 0; } } @@ -2581,7 +2850,7 @@ OSC::route_set_pan_stereo_position (int ssid, float pos, lo_message msg) if (s) { if(s->pan_azimuth_control()) { s->pan_azimuth_control()->set_value (s->pan_azimuth_control()->interface_to_internal (pos), PBD::Controllable::NoGroup); - return route_send_fail ("pan_stereo_position", ssid, s->pan_azimuth_control()->internal_to_interface (s->pan_azimuth_control()->get_value ()), get_address (msg)); + return 0; } } @@ -3469,6 +3738,18 @@ OSC::periodic (void) } } + if (scrub_speed != 0) { + // for those jog wheels that don't have 0 on release (touch), time out. + int64_t now = ARDOUR::get_microseconds (); + int64_t diff = now - scrub_time; + if (diff > 120000) { + scrub_speed = 0; + session->request_transport_speed (0); + // locate to the place PH was at last tick + session->request_locate (scrub_place, false); + } + } + for (GlobalObservers::iterator x = global_observers.begin(); x != global_observers.end(); x++) { OSCGlobalObserver* go; @@ -3579,23 +3860,23 @@ XMLNode& OSC::get_state () { XMLNode& node (ControlProtocol::get_state()); - node.add_property("debugmode", (int) _debugmode); // TODO: enum2str - node.add_property ("address-only", address_only); - node.add_property ("remote-port", remote_port); - node.add_property ("banksize", default_banksize); - node.add_property ("striptypes", default_strip); - node.add_property ("feedback", default_feedback); - node.add_property ("gainmode", default_gainmode); + node.set_property ("debugmode", (int32_t) _debugmode); // TODO: enum2str + node.set_property ("address-only", address_only); + node.set_property ("remote-port", remote_port); + node.set_property ("banksize", default_banksize); + node.set_property ("striptypes", default_strip); + node.set_property ("feedback", default_feedback); + node.set_property ("gainmode", default_gainmode); if (_surface.size()) { XMLNode* config = new XMLNode (X_("Configurations")); for (uint32_t it = 0; it < _surface.size(); ++it) { OSCSurface* sur = &_surface[it]; XMLNode* devnode = new XMLNode (X_("Configuration")); - devnode->add_property (X_("url"), sur->remote_url); - devnode->add_property (X_("bank-size"), sur->bank_size); - devnode->add_property (X_("strip-types"), sur->strip_types.to_ulong()); - devnode->add_property (X_("feedback"), sur->feedback.to_ulong()); - devnode->add_property (X_("gainmode"), sur->gainmode); + devnode->set_property (X_("url"), sur->remote_url); + devnode->set_property (X_("bank-size"), sur->bank_size); + devnode->set_property (X_("strip-types"), (uint64_t)sur->strip_types.to_ulong()); + devnode->set_property (X_("feedback"), (uint64_t)sur->feedback.to_ulong()); + devnode->set_property (X_("gainmode"), sur->gainmode); config->add_child_nocopy (*devnode); } node.add_child_nocopy (*config); @@ -3609,68 +3890,48 @@ OSC::set_state (const XMLNode& node, int version) if (ControlProtocol::set_state (node, version)) { return -1; } - XMLProperty const * p = node.property (X_("debugmode")); - if (p) { - _debugmode = OSCDebugMode (PBD::atoi(p->value ())); - } - p = node.property (X_("address-only")); - if (p) { - address_only = OSCDebugMode (PBD::atoi(p->value ())); - } - p = node.property (X_("remote-port")); - if (p) { - remote_port = p->value (); - } - p = node.property (X_("banksize")); - if (p) { - default_banksize = OSCDebugMode (PBD::atoi(p->value ())); - } - p = node.property (X_("striptypes")); - if (p) { - default_strip = OSCDebugMode (PBD::atoi(p->value ())); - } - p = node.property (X_("feedback")); - if (p) { - default_feedback = OSCDebugMode (PBD::atoi(p->value ())); - } - p = node.property (X_("gainmode")); - if (p) { - default_gainmode = OSCDebugMode (PBD::atoi(p->value ())); + int32_t debugmode; + if (node.get_property (X_("debugmode"), debugmode)) { + _debugmode = OSCDebugMode (debugmode); } + + node.get_property (X_("address-only"), address_only); + node.get_property (X_("remote-port"), remote_port); + node.get_property (X_("banksize"), default_banksize); + node.get_property (X_("striptypes"), default_strip); + node.get_property (X_("feedback"), default_feedback); + node.get_property (X_("gainmode"), default_gainmode); + XMLNode* cnode = node.child (X_("Configurations")); if (cnode) { XMLNodeList const& devices = cnode->children(); for (XMLNodeList::const_iterator d = devices.begin(); d != devices.end(); ++d) { - XMLProperty const * prop = (*d)->property (X_("url")); - if (prop) { - OSCSurface s; - bank_dirty = true; - s.remote_url = prop->value(); - prop = (*d)->property (X_("bank-size")); - if (prop) { - s.bank_size = atoi (prop->value().c_str()); - } - prop = (*d)->property (X_("strip-types")); - if (prop) { - s.strip_types = atoi (prop->value().c_str()); - } - prop = (*d)->property (X_("feedback")); - if (prop) { - s.feedback = atoi (prop->value().c_str()); - } - prop = (*d)->property (X_("gainmode")); - if (prop) { - s.gainmode = atoi (prop->value().c_str()); - } - s.bank = 1; - s.sel_obs = 0; - s.expand = 0; - s.expand_enable = false; - s.strips = get_sorted_stripables(s.strip_types); - s.nstrips = s.strips.size(); - _surface.push_back (s); + OSCSurface s; + if (!(*d)->get_property (X_("url"), s.remote_url)) { + continue; + } + + bank_dirty = true; + + (*d)->get_property (X_("bank-size"), s.bank_size); + + uint64_t bits; + if ((*d)->get_property (X_ ("strip-types"), bits)) { + s.strip_types = bits; } + if ((*d)->get_property (X_("feedback"), bits)) { + s.feedback = bits; + } + (*d)->get_property (X_("gainmode"), s.gainmode); + + s.bank = 1; + s.sel_obs = 0; + s.expand = 0; + s.expand_enable = false; + s.strips = get_sorted_stripables (s.strip_types, s.cue); + s.nstrips = s.strips.size (); + _surface.push_back (s); } } global_init = true; @@ -3699,7 +3960,7 @@ struct StripableByPresentationOrder }; OSC::Sorted -OSC::get_sorted_stripables(std::bitset<32> types) +OSC::get_sorted_stripables(std::bitset<32> types, bool cue) { Sorted sorted; @@ -3712,7 +3973,7 @@ OSC::get_sorted_stripables(std::bitset<32> types) for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) { boost::shared_ptr s = *it; - if ((!types[9]) && (s->presentation_info().flags() & PresentationInfo::Hidden)) { + if ((!cue) && (!types[9]) && (s->presentation_info().flags() & PresentationInfo::Hidden)) { // do nothing... skip it } else { @@ -3831,7 +4092,7 @@ OSC::_cue_set (uint32_t aux, lo_address addr) s->gainmode = 1; s->cue = true; s->aux = aux; - s->strips = get_sorted_stripables(s->strip_types); + s->strips = get_sorted_stripables(s->strip_types, s->cue); s->nstrips = s->strips.size(); // get rid of any old CueObsevers for this address