Example #1
0
// ----------------------------------------------------------------------------
//
void HttpRestServices::venue_create_quickscene(Venue* venue, DMXHttpSession* session, CString& response, LPCSTR data, DWORD size, LPCSTR content_type)
{
	SimpleJsonParser parser;

	UIDArray fixtures;
	RGBWA color;
	QuickSceneEffect effect;
	unsigned color_speed_ms, move_speed_ms;
	QuickSceneMovement movement;
    bool multi_color;

	try {
		parser.parse( data );
		fixtures = parser.getArrayAsVector<UID>( "fixtures" );
		effect = (QuickSceneEffect)parser.get<unsigned>( "effect" );
		color_speed_ms = parser.get<unsigned>( "color_speed_ms" );
        move_speed_ms = parser.get<unsigned>( "move_speed_ms" );
		movement = (QuickSceneMovement)parser.get<unsigned>( "movement" );
		color = parser.get<RGBWA>( "color" );
        multi_color = parser.get<bool>( "multi_color" );
	}
	catch ( std::exception& e ) {
		throw RestServiceException( "JSON parser error (%s) data (%s)", e.what(), data );
	}

	venue->createQuickScene( fixtures, effect, color, color_speed_ms, movement, move_speed_ms, multi_color );
}
Example #2
0
// ----------------------------------------------------------------------------
//
void HttpRestServices::control_beatsampler_start( Venue* venue, DMXHttpSession* session, CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;

    session->getBeatDetector().removeAllFrequencyEvents();
    session->getBeats().clear();

    session->getBeatDetector().attach( venue->getAudio(), 64 );

    try {
        parser.parse( data );

        JsonNodePtrArray bins = parser.getObjects();

        for ( JsonNode* bin : bins ) {
            unsigned start_freq = bin->get<unsigned>( "start_freq" );
            unsigned end_freq = bin->get<unsigned>( "end_freq" );

            session->getBeats().emplace_back( start_freq, end_freq );
        }
    }
    catch ( std::exception& e ) {
        throw RestServiceException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    for ( BeatBinArray::iterator it=session->getBeats().begin(); it != session->getBeats().end(); ++it )
        session->getBeatDetector().addFrequencyEvent( (*it).getEvent(), (*it).getStartFreq(),  (*it).getEndFreq() );
}
Example #3
0
// ----------------------------------------------------------------------------
//
bool HttpRestServices::edit_scene_copy_fixtures( CString& response, LPCSTR data, DWORD size, LPCSTR content_type ) {

    if ( !studio.getVenue() || !studio.getVenue()->isRunning() )
        return false;

    SimpleJsonParser parser;
    bool clear;
    bool keep_groups;
    ULONG scene_id;
    UIDArray actors;

    try {
        parser.parse( data );

        clear = parser.get<bool>( "clear" );
        scene_id = parser.get<unsigned long>( "scene_id" );
        keep_groups = parser.get<bool>( "keep_groups" );
        actors = parser.get<UIDArray>( "fixture_ids" );
    }
    catch ( std::exception& e ) {
        DMXStudio::log( StudioException( "JSON parser error (%s) data (%s)", e.what(), data ) );
        return false;
    }

    studio.getVenue()->moveDefaultFixturesToScene(scene_id, actors, keep_groups, clear );

    return true;
}
Example #4
0
// ----------------------------------------------------------------------------
//
bool HttpRestServices::edit_venue_new( CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;
    CString reset_what;

    try {
        parser.parse( data );
        reset_what = parser.get<CString>( "reset_what" );
    }
    catch ( std::exception& e ) {
        throw StudioException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    if ( reset_what == "new" ) {
        studio.newVenue();
    }
    else if ( reset_what == "chases" ) {
        studio.getVenue()->deleteAllChases();
    }
    else if ( reset_what == "groups" ) {
        studio.getVenue()->deleteAllFixtureGroups();
    }
    else if ( reset_what == "scenes" ) {
        studio.getVenue()->deleteAllScenes();
    }
    else
        return false;

    return true;
}
Example #5
0
// ----------------------------------------------------------------------------
//
static bool music_matcher_load( Venue* venue, LPCSTR data, boolean clearFirst ) {
    SimpleJsonParser parser;

    std::vector<MusicSceneSelector> selections;

    try {
        parser.parse( data );

        JsonNodePtrArray selection_parsers = parser.getObjects();

        for ( JsonNode* selection : selection_parsers ) {
            UID selection_id = selection->get<UID>( "id" );
            CString selection_name = selection->get<CString>( "track" );
            CString selection_link = selection->get<CString>( "link" );
            MusicSelectorType selection_type = (MusicSelectorType)selection->get<int>( "type" );

            selections.push_back( MusicSceneSelector( selection_name, selection_link, selection_type, selection_id ) );
        }
    }
    catch ( std::exception& e ) {
        throw StudioException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    // Reload the selection map
    if ( clearFirst )
        venue->clearMusicMappings();

    venue->addMusicMappings( selections );

    return true;
}
Example #6
0
// ----------------------------------------------------------------------------
//
bool HttpRestServices::player_login( Venue* venue, DMXHttpSession* session, CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;
    CString username;
    CString password;

    try {
        parser.parse( data );

        username = parser.get<CString>( "username" );
        password = parser.get<CString>( "password" );
    }
    catch ( std::exception& e ) {
        throw StudioException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    JsonBuilder json( response );
    json.startObject();

    if ( studio.getMusicPlayer()->signon( username, password ) ) {
        json.add( "logged_in", true );
    }
    else {
        CString login_error = studio.getMusicPlayer()->getLastPlayerError();

        if ( login_error.IsEmpty() )
            login_error = "Login failed";

        json.add( "logged_in", false );
        json.add( "login_error", login_error );
    }

    json.endObject();
    return true;
}
Example #7
0
// ----------------------------------------------------------------------------
//
void HttpRestServices::edit_venue_new( Venue* venue, DMXHttpSession* session, CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;
    CString reset_what;

    try {
        parser.parse( data );
        reset_what = parser.get<CString>( "reset_what" );
    }
    catch ( std::exception& e ) {
        throw RestServiceException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    if ( reset_what == "new" ) {
        studio.newVenue();
    }
    else if ( reset_what == "chases" ) {
        venue->deleteAllChases();
    }
    else if ( reset_what == "groups" ) {
        venue->deleteAllFixtureGroups();
    }
    else if ( reset_what == "scenes" ) {
		venue->deleteAllChases();
        venue->deleteAllScenes();
		venue->deleteAllAnimations();
    }
    else
        throw RestServiceException( "Invalid venue reset object" );
}
Example #8
0
// ----------------------------------------------------------------------------
//
void HttpRestServices::control_venue_whiteout_palette( Venue* venue, DMXHttpSession* session, CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;

    try {
        parser.parse( data );

        RGBWAArray palette_colors = parser.getArrayAsVector<RGBWA>( "palette" );
        ColorWeights palette_weights;

        if ( parser.has_key( "weights" ) )
            palette_weights = parser.getArrayAsVector<double>( "weights" );

        UINT duration = parser.get<UINT>( "duration_ms" );

        venue->setVideoPalette( palette_colors, palette_weights );

        venue->setWhiteoutColor( SYSTEM_PALETTE_4 );
        venue->setWhiteoutStrobeMS( duration, 0 );
        venue->setWhiteout( WhiteoutMode::WHITEOUT_ON );
    }
    catch ( std::exception& e ) {
        throw RestServiceException( "JSON parser error (%s) data (%s)", e.what(), data );
    }
}
Example #9
0
// ----------------------------------------------------------------------------
//
AnalyzeInfo* SpotifyEngine::loadTrackAnalysis( LPCSTR spotify_id )
{
    TrackAnalysisCache::iterator it = m_track_analysis_cache.find( spotify_id );
    if ( it != m_track_analysis_cache.end() )
        return (it)->second;

    // See if it existing on disk - if available, load into the cache and return
    CString filename = makeTrackAnalysisFileName( m_trackAnalysisContainer, spotify_id );

    if ( GetFileAttributes( filename ) == INVALID_FILE_ATTRIBUTES )
        return NULL;

    FILE* hFile = _fsopen( filename, "rt", _SH_DENYWR );
    if ( hFile == NULL ) {
        log( "Unable to read track analysis from %s", filename );
        return NULL;
    }

    // Get file size
    fseek( hFile, 0L, SEEK_END );
    size_t size = ftell( hFile );
    rewind( hFile );

    CString data;
    fread( data.GetBufferSetLength(size), 1, size, hFile );
    fclose( hFile );
        
    SimpleJsonParser parser;

    try {
        parser.parse( data );

        CString spotify_id = parser.get<CString>( "link" );

        SimpleJsonParser amplitute_parser = parser.get<SimpleJsonParser>( "amplitude" );

        size_t data_count = amplitute_parser.get<size_t>( "data_count" );
        UINT duration_ms = amplitute_parser.get<size_t>( "duration_ms" );
        std::vector<uint16_t> amplitude_data = amplitute_parser.getArray<uint16_t>( "data" );

        AnalyzeInfo* info = (AnalyzeInfo*)calloc( sizeof(AnalyzeInfo) + (sizeof(uint16_t) * data_count), 1 );
        for ( size_t i=0; i < data_count; i++ )
            info->data[i] = amplitude_data[i];

        strncpy_s( info->link, spotify_id, sizeof(info->link) );
        info->data_count = data_count;
        info->duration_ms = duration_ms;
        m_track_analysis_cache[info->link] = info;

        return info;
    }
    catch ( std::exception& e ) {
        log( StudioException( "JSON parser error (%s) data (%s)", e.what(), data ) );
        return NULL;
    }
}
Example #10
0
bool parseJsonLite(const QByteArray& json, QVariantMap& result)
{
	SimpleJsonParser parser;
	if (!parser.parse(json)) {
		return false;
	}

	result = parser.result();
	return true;
}
Example #11
0
// ----------------------------------------------------------------------------
//
bool IniFile::read( )
{
    FILE* fp;

    errno_t err = fopen_s( &fp, m_ini_filename, "r" );
    if ( err || !fp )   // Assume it does not exist
        return false;
        
    SimpleJsonParser parser;

    try {
        parser.parse( fp );

        fclose( fp );
    }
    catch ( std::exception& e ) {
        fclose( fp );
        throw e;
    }
    
    m_dmx_required = parser.get<bool>( "dmx_required", true );
    m_debug = parser.get<bool>( "debug", false );
    m_venue_filename = parser.get<CString>( "venue_filename", "" );
    m_venue_container = parser.get<CString>( "venue_container", "" );

    if ( parser.has_key( "remote" ) ) {
        JsonNode remote = parser.get<JsonNode>( "remote" );
        m_http_port = parser.get<unsigned>( "http_port", 80 );
        m_http_enabled = parser.get<bool>( "enable", true );
    }

    if ( parser.has_key( "whiteout_slow" ) ) {
        JsonNode whiteout_slow = parser.get<JsonNode>( "whiteout_slow" );
        m_whiteout_strobe_slow.m_on_ms = whiteout_slow.get<unsigned>( "on_ms" );
        m_whiteout_strobe_slow.m_off_ms = whiteout_slow.get<unsigned>( "off_ms" );
    }

    if ( parser.has_key( "whiteout_fast" ) ) {
        JsonNode whiteout_fast = parser.get<JsonNode>( "whiteout_fast" );
        m_whiteout_strobe_fast.m_on_ms = whiteout_fast.get<unsigned>( "on_ms" );
        m_whiteout_strobe_fast.m_off_ms = whiteout_fast.get<unsigned>( "off_ms" );
    }

    if ( parser.has_key( "music_player" ) ) {
        JsonNode music_player = parser.get<JsonNode>( "music_player" );
        m_music_player_ddl = music_player.get<CString>( "library" );
        m_music_player_username = music_player.get<CString>( "username" );

        m_music_player_enabled = true;
    }

    return true;
}
Example #12
0
// ----------------------------------------------------------------------------
//
bool HttpRestServices::edit_venue_load( CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;
    CString venue_filename;

    try {
        parser.parse( data );
        venue_filename = parser.get<CString>( "venue_filename" );
        venue_filename.Replace( "\\\\", "\\" );
    }
    catch ( std::exception& e ) {
        throw StudioException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    return studio.loadVenueFromFile( (LPCSTR)venue_filename );
}
Example #13
0
// ----------------------------------------------------------------------------
//
bool HttpRestServices::edit_venue_update( CString& response, LPCSTR data, DWORD size, LPCSTR content_type ) {

    Venue* venue = studio.getVenue();
    if ( !venue )
        return false;

    SimpleJsonParser parser;

    try {
        parser.parse( data );

        CString name = parser.get<CString>( "name" );
        CString description = parser.get<CString>( "description" );
        CString dmx_port = parser.get<CString>( "dmx_port" );
        CString audio_capture_device = parser.get<CString>( "audio_capture_device" );
        int dmx_packet_delay_ms = parser.get<int>( "dmx_packet_delay_ms" );
        int dmx_minimum_delay_ms = parser.get<int>( "dmx_minimum_delay_ms" );
        int audio_sample_size = parser.get<int>( "audio_sample_size" );
        float audio_boost = parser.get<float>( "audio_boost" );
        float audio_boost_floor = parser.get<float>( "audio_boost_floor" );
        int auto_blackout = parser.get<int>( "auto_blackout" );

        // There may be a better solution for this, but we need to kill all attached sound devices before the reset
        m_sound_sampler.detach();

        venue->close();

        venue->setName( name );
        venue->setDescription( description );
        venue->setDmxPort( dmx_port );
        venue->setDmxPacketDelayMS( dmx_packet_delay_ms );
        venue->setDmxMinimumDelayMS( dmx_minimum_delay_ms );
        venue->setAudioCaptureDevice( audio_capture_device );
        venue->setAudioBoost( audio_boost );
        venue->setAudioBoostFloor( audio_boost_floor );
        venue->setAudioSampleSize( audio_sample_size );
        venue->setAutoBlackout( auto_blackout );

        venue->open();
    }
    catch ( std::exception& e ) {
        throw StudioException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    return true;
}
Example #14
0
// ----------------------------------------------------------------------------
//
void HttpRestServices::edit_venue_load( Venue* venue, DMXHttpSession* session, CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;
    CString venue_filename;

    try {
        parser.parse( data );
        venue_filename = parser.get<CString>( "venue_filename" );
        venue_filename.Replace( "\\\\", "\\" );
    }
    catch ( std::exception& e ) {
        throw RestServiceException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    if ( !studio.loadVenueFromFile( (LPCSTR)venue_filename ) ) 
        throw RestServiceException( "Unable to load venue file '%s'", venue_filename );
}
Example #15
0
// ----------------------------------------------------------------------------
//
void HttpRestServices::edit_venue_update( Venue* venue, DMXHttpSession* session, CString& response, LPCSTR data, DWORD size, LPCSTR content_type )
{
    SimpleJsonParser parser;

    try {
        parser.parse( data );

        CString name = parser.get<CString>( "name" );
        CString description = parser.get<CString>( "description" );
        CString audio_capture_device = parser.get<CString>( "audio_capture_device" );
        float audio_boost = parser.get<float>( "audio_boost" );
        float audio_boost_floor = parser.get<float>( "audio_boost_floor" );
        int audio_sample_size = parser.get<int>( "audio_sample_size" );
        int auto_blackout = parser.get<int>( "auto_blackout" );
        bool track_fixtures = parser.get<bool>( "track_fixtures" );
        JsonNodePtrArray universeParsers = parser.getObjects("universes");

        std::vector<Universe> universes;

        for (  JsonNode* univ : universeParsers ) {
            unsigned id = univ->get<unsigned>( "id" );
            UniverseType type = (UniverseType)univ->get<unsigned>( "type" );
            CString dmx_config = univ->get<CString>( "dmx_config" );
            unsigned dmx_packet_delay_ms = univ->get<unsigned>( "packet_delay_ms" );
            unsigned dmx_minimum_delay_ms = univ->get<unsigned>( "minimum_delay_ms" );

            universes.emplace_back( id, type, dmx_config, dmx_packet_delay_ms, dmx_minimum_delay_ms );
        }

        venue->configure( name, description, audio_capture_device, audio_boost, audio_boost_floor, audio_sample_size, 
                          auto_blackout, track_fixtures, universes );
    }
    catch ( std::exception& e ) {
        throw RestServiceException( "JSON parser error (%s) data (%s)", e.what(), data );
    }
}
Example #16
0
// ----------------------------------------------------------------------------
//
bool IniFile::read( LPCSTR filename )
{
    FILE* fp;

    errno_t err = fopen_s( &fp, filename, "r" );
    if ( err || !fp )   // Assume it does not exist
        return false;
        
    SimpleJsonParser parser;

    try {
        parser.parse( fp );

        fclose( fp );
    }
    catch ( std::exception& e ) {
        fclose( fp );
        throw e;
    }
    
    m_dmx_required = parser.get<bool>( "dmx_required", true );
    m_debug = parser.get<bool>( "debug", false );
    m_venue_filename = parser.get<CString>( "venue_filename", "" );
    m_venue_container = parser.get<CString>( "venue_container", "" );
    m_google_api_key = parser.get<CString>( "google_api_key", "" );

    if ( parser.has_key( "remote" ) ) {
        JsonNode remote = parser.get<JsonNode>( "remote" );
        m_http_port = remote.get<unsigned>( "http_port", 80 );
        m_http_enabled = remote.get<bool>( "enable", true );
     }

    if ( parser.has_key( "videos" ) ) {
        JsonNode videos = parser.get<JsonNode>( "videos" );
        m_videos_per_track = videos.get<unsigned>( "videos_per_track", 12 );
        m_video_palette_size = videos.get<unsigned>( "video_palette_size", 12 );
    }

    if ( parser.has_key( "whiteout_slow" ) ) {
        JsonNode whiteout_slow = parser.get<JsonNode>( "whiteout_slow" );
        m_whiteout_strobe_slow.setOnMS( whiteout_slow.get<unsigned>( "on_ms" ) );
        m_whiteout_strobe_slow.setOffMS( whiteout_slow.get<unsigned>( "off_ms" ) );
        m_whiteout_strobe_slow.setFadeInMS( whiteout_slow.get<unsigned>( "fade_in_ms", 0 ) );
        m_whiteout_strobe_slow.setFadeOutMS( whiteout_slow.get<unsigned>( "fade_out_ms", 0 ) );
		m_whiteout_strobe_slow.setFlashes( whiteout_slow.get<unsigned>( "flashes", 1 ) );
    }

    if ( parser.has_key( "whiteout_fast" ) ) {
        JsonNode whiteout_fast = parser.get<JsonNode>( "whiteout_fast" );
        m_whiteout_strobe_fast.setOnMS( whiteout_fast.get<unsigned>( "on_ms" ) );
        m_whiteout_strobe_fast.setOffMS( whiteout_fast.get<unsigned>( "off_ms" ) );
        m_whiteout_strobe_fast.setFadeInMS( whiteout_fast.get<unsigned>( "fade_in_ms", 0 ) );
        m_whiteout_strobe_fast.setFadeOutMS( whiteout_fast.get<unsigned>( "fade_out_ms", 0 ) );
        m_whiteout_strobe_fast.setFlashes( whiteout_fast.get<unsigned>( "flashes", 1 ) );
    }

    if ( parser.has_key( "whiteout_manual" ) ) {
        JsonNode whiteout_manual = parser.get<JsonNode>( "whiteout_manual" );
        m_whiteout_strobe_manual.setOnMS( whiteout_manual.get<unsigned>( "on_ms" ) );
        m_whiteout_strobe_manual.setOffMS( 0 );
        m_whiteout_strobe_manual.setFadeInMS( whiteout_manual.get<unsigned>( "fade_in_ms", 0 ) );
        m_whiteout_strobe_manual.setFadeOutMS( whiteout_manual.get<unsigned>( "fade_out_ms", 0 ) );
        m_whiteout_strobe_manual.setFlashes( whiteout_manual.get<unsigned>( "flashes", 1 ) );
    }

    if ( parser.has_key( "music_player" ) ) {
        JsonNode music_player = parser.get<JsonNode>( "music_player" );
        m_music_player_ddl = music_player.get<CString>( "library" );
        m_music_player_username = music_player.get<CString>( "username" );

        m_music_player_enabled = true;
    }

    if ( parser.has_key( "hue" ) ) {
        JsonNode hue = parser.get<JsonNode>( "hue" );
        m_hue_bridge_ip = hue.get<CString>( "bridge_ip", "" );
        m_hue_auto_setup = hue.get<bool>( "auto_setup", true );

        if ( hue.has_key( "ignored_lights" ) ) {
            for ( UINT light_number : hue.getArrayAsVector<UINT>( "ignored_lights" ) ) {
                m_hue_ignored_lights.insert( light_number );
            }
        }

        if ( hue.has_key( "allowed_groups" ) ) {
            for ( CString& group_name : hue.getArrayAsVector<CString>( "allowed_groups" ) ) {
                m_hue_allowed_groups.insert( group_name );
            }
        }
    }

    return true;
}
Example #17
0
// ----------------------------------------------------------------------------
//
bool HttpRestServices::edit_scene( CString& response, LPCSTR data, EditMode mode ) {
    if ( !studio.getVenue() || !studio.getVenue()->isRunning() )
        return false;

    SimpleJsonParser parser;
    UID scene_id;
    CString name, description;
    SceneNumber number;
    BPMRating bpm_rating;
    bool keep_groups;
    Scene* scene = NULL;
    UIDArray actors;
    PARSER_LIST animationParsers;
    std::vector<AbstractAnimation*> animations;
    Acts acts;

    try {
        parser.parse( data );

        scene_id = parser.get<ULONG>( "id" );
        name = parser.get<CString>( "name" );
        description = parser.get<CString>( "description" );
        number = parser.get<ULONG>( "number" );
        bpm_rating = (BPMRating)parser.get<UINT>( "bpm_rating" );
        keep_groups = parser.get<bool>( "keep_groups" );
        actors = parser.get<UIDArray>( "actors" );
        animationParsers = parser.get<PARSER_LIST>("animations");
        acts = parser.get<Acts>( "acts" );

        for ( PARSER_LIST::iterator it=animationParsers.begin(); it != animationParsers.end(); ++it ) {
            CString class_name = (*it).get<CString>( "class_name" );
            UIDArray animation_actors = (*it).get<UIDArray>( "actors" );
            SimpleJsonParser signalParser = (*it).get<SimpleJsonParser>( "signal" );
            SimpleJsonParser animationParser = (*it).get<SimpleJsonParser>( class_name );
            AnimationSignal signal = parseAnimationSignal( signalParser );

            ANIMATION_PARSER_FUNC anim_parser_func = animation_parsers[ class_name ];
            if ( anim_parser_func == NULL )
                throw std::exception( "Unknown animation class name from client" );

            animations.push_back( anim_parser_func( animationParser, signal, animation_actors ) );
        }
    }
    catch ( std::exception& e ) {
        throw StudioException( "JSON parser error (%s) data (%s)", e.what(), data );
    }

    if ( scene_id != 0 ) {
        scene = studio.getVenue()->getScene( scene_id );
        if ( !scene )
            return false;
    }

    // Make sure number is unique
    if ( mode != UPDATE || (scene && number != scene->getNumber()) ) {
        if ( studio.getVenue()->getSceneByNumber( number ) != NULL )
            return false;
    }

    switch ( mode ) {
    case NEW: {
        scene_id = studio.getVenue()->allocUID();
        Scene new_scene;
        new_scene.setUID( scene_id );
        studio.getVenue()->addScene( new_scene );
        scene = studio.getVenue()->getScene( scene_id );
        studio.getVenue()->moveDefaultFixturesToScene( scene_id, actors, keep_groups, true );
        break;
    }

    case COPY: {
        scene_id = studio.getVenue()->allocUID();
        Scene new_scene( *scene );
        new_scene.setUID( scene_id );
        studio.getVenue()->addScene( new_scene );
        scene = studio.getVenue()->getScene( scene_id );
    }

    // Fall through

    case UPDATE:
        // Verify actors - remove any that have been deselected
        UIDArray active_actors = scene->getActorUIDs();
        for ( UIDArray::iterator it=active_actors.begin(); it != active_actors.end(); ++it ) {
            if ( std::find( actors.begin(), actors.end(), *it ) == actors.end() )
                scene->removeActor( *it );
        }
        break;
    }

    scene->setName( name );
    scene->setSceneNumber( number );
    scene->setBPMRating( bpm_rating );
    scene->setDescription( description );
    scene->setActs( acts );

    scene->clearAnimations();
    for ( std::vector<AbstractAnimation*>::iterator it=animations.begin(); it != animations.end(); ++it )
        scene->addAnimation( *it );

    if ( mode != UPDATE )            // Switch to new scene
        studio.getVenue()->selectScene( scene->getUID() );
    else if ( studio.getVenue()->getCurrentSceneUID() == scene->getUID() )
        studio.getVenue()->loadScene( );

    return true;
}