//--------------------------------------------------------------
void ofxGranularSynth::setDuration(float duration){
    if(duration>0){
        float oldDuration = mDuration;
        mDuration = duration*14000;
        setOverlap((float)mOverlap/(float)oldDuration);
    }
}
void InspectorLayerTreeAgent::reasonsForCompositingLayer(ErrorString& errorString, const String& layerId, RefPtr<Inspector::Protocol::LayerTree::CompositingReasons>& compositingReasonsResult)
{
    const RenderLayer* renderLayer = m_idToLayer.get(layerId);

    if (!renderLayer) {
        errorString = ASCIILiteral("Could not find a bound layer for the provided id");
        return;
    }

    CompositingReasons reasonsBitmask = renderLayer->compositor().reasonsForCompositing(*renderLayer);
    auto compositingReasons = Inspector::Protocol::LayerTree::CompositingReasons::create().release();

    if (reasonsBitmask & CompositingReason3DTransform)
        compositingReasons->setTransform3D(true);

    if (reasonsBitmask & CompositingReasonVideo)
        compositingReasons->setVideo(true);
    else if (reasonsBitmask & CompositingReasonCanvas)
        compositingReasons->setCanvas(true);
    else if (reasonsBitmask & CompositingReasonPlugin)
        compositingReasons->setPlugin(true);
    else if (reasonsBitmask & CompositingReasonIFrame)
        compositingReasons->setIFrame(true);
    
    if (reasonsBitmask & CompositingReasonBackfaceVisibilityHidden)
        compositingReasons->setBackfaceVisibilityHidden(true);

    if (reasonsBitmask & CompositingReasonClipsCompositingDescendants)
        compositingReasons->setClipsCompositingDescendants(true);

    if (reasonsBitmask & CompositingReasonAnimation)
        compositingReasons->setAnimation(true);

    if (reasonsBitmask & CompositingReasonFilters)
        compositingReasons->setFilters(true);

    if (reasonsBitmask & CompositingReasonPositionFixed)
        compositingReasons->setPositionFixed(true);

    if (reasonsBitmask & CompositingReasonPositionSticky)
        compositingReasons->setPositionSticky(true);

    if (reasonsBitmask & CompositingReasonOverflowScrollingTouch)
        compositingReasons->setOverflowScrollingTouch(true);

    if (reasonsBitmask & CompositingReasonStacking)
        compositingReasons->setStacking(true);

    if (reasonsBitmask & CompositingReasonOverlap)
        compositingReasons->setOverlap(true);

    if (reasonsBitmask & CompositingReasonNegativeZIndexChildren)
        compositingReasons->setNegativeZIndexChildren(true);

    if (reasonsBitmask & CompositingReasonTransformWithCompositedDescendants)
        compositingReasons->setTransformWithCompositedDescendants(true);

    if (reasonsBitmask & CompositingReasonOpacityWithCompositedDescendants)
        compositingReasons->setOpacityWithCompositedDescendants(true);

    if (reasonsBitmask & CompositingReasonMaskWithCompositedDescendants)
        compositingReasons->setMaskWithCompositedDescendants(true);

    if (reasonsBitmask & CompositingReasonReflectionWithCompositedDescendants)
        compositingReasons->setReflectionWithCompositedDescendants(true);

    if (reasonsBitmask & CompositingReasonFilterWithCompositedDescendants)
        compositingReasons->setFilterWithCompositedDescendants(true);

    if (reasonsBitmask & CompositingReasonBlendingWithCompositedDescendants)
        compositingReasons->setBlendingWithCompositedDescendants(true);

    if (reasonsBitmask & CompositingReasonIsolatesCompositedBlendingDescendants)
        compositingReasons->setIsolatesCompositedBlendingDescendants(true);

    if (reasonsBitmask & CompositingReasonPerspective)
        compositingReasons->setPerspective(true);

    if (reasonsBitmask & CompositingReasonPreserve3D)
        compositingReasons->setPreserve3D(true);

    if (reasonsBitmask & CompositingReasonWillChange)
        compositingReasons->setWillChange(true);

    if (reasonsBitmask & CompositingReasonRoot)
        compositingReasons->setRoot(true);
    
    compositingReasonsResult = WTF::move(compositingReasons);
}
//compute audio
void GrainCluster::nextBuffer(double * accumBuff,unsigned int numFrames)
{
    
    if (addFlag == true){
        addFlag = false;
        myGrains->push_back(new GrainVoice(theSounds,duration,pitch));
        int idx = myGrains->size()-1;
        myGrains->at(idx)->setWindow(windowType);
        switch (myDirMode) {
            case FORWARD:
                myGrains->at(idx)->setDirection(1.0);
                break;
            case BACKWARD:
                myGrains->at(idx)->setDirection(-1.0);
                break;
            case RANDOM_DIR:
                if (randf()>0.5)
                    myGrains->at(idx)->setDirection(1.0);
                else
                    myGrains->at(idx)->setDirection(-1.0);
                break;

            default:
                break;
        }
        
        myGrains->at(idx)->setVolume(normedVol);
        numVoices += 1;
        setOverlap(overlapNorm);
    }
    
    if (removeFlag == true){
        myLock->lock();
        if (myGrains->size() > 1){
             if (nextGrain >= myGrains->size()-1){
                 nextGrain = 0;
             }
            myGrains->pop_back();
            setOverlap(overlapNorm);
        }
        removeFlag = false;
        myLock->unlock();

        
    }
    
    if (isActive == true){
        
        
                //initialize play positions array
        double playPositions[theSounds->size()];
        double playVols[theSounds->size()];
        
        //buffer variables
        unsigned int nextFrame = 0;
        
        //compute sub_buffers for reduced function calls
        int frameSkip = 256;
        
        
        //fill buffer
        for (int j = 0; j < (numFrames/(frameSkip)); j++){
            
            //check for bang
            if ((local_time > bang_time) || (awaitingPlay)){
                
                //debug
                //cout << "bang " << nextGrain << endl;
                //reset local
                if (!awaitingPlay){
                    local_time = 0;
                    //clear play and volume buffs
                    for (int i = 0; i < theSounds->size(); i++){
                        playPositions[i] = (double)(-1.0);
                        playVols[i] = (double) 0.0;
                    }
                    //TODO:  get position vector for grain with idx nextGrain from controller
                    //udate positions vector (currently randomized)q
                    if (myVis)
                        myVis->getTriggerPos(nextGrain,playPositions,playVols,duration);
                    
                }
                
                //get next pitch (using LFO) -  eventually generalize to an applyLFOs method (if LFO control will be exerted over multiple params)
                if ((pitchLFOAmount > 0.0f) && (pitchLFOFreq > 0.0f)){
                    float nextPitch = fabs(pitch + pitchLFOAmount * sin(2*PI*pitchLFOFreq*GTime::instance().sec));
                    myGrains->at(nextGrain)->setPitch(nextPitch);
                }
                
                
                //update spatialization/get new channel multiplier set
                updateSpatialization();
                myGrains->at(nextGrain)->setChannelMultipliers(channelMults);
                
                //trigger grain
                awaitingPlay =  myGrains->at(nextGrain)->playMe(playPositions,playVols);
                
                //only advance if next grain is playable.  otherwise, cycle through again
                //to wait for playback
                if (!awaitingPlay){
                    //queue next grain for trigger
                    nextGrain++;
                    //wrap grain idx
                    if (nextGrain >= myGrains->size())
                        nextGrain = 0;
                }else{
                    //debug
                    //cout << "playback delayed "<< endl;
                }
            }
            //advance time
            local_time+=frameSkip;
            
            //sample offset (1 sample at a time for now)
            nextFrame = j*frameSkip;
            //iterate over all grains
            for (int k = 0; k < myGrains->size(); k++){
                myGrains->at(k)->nextBuffer(accumBuff,frameSkip, nextFrame,k);
            }
        }
    }
}
//Constructor
GrainCluster::GrainCluster(vector<AudioFile*> * soundSet, float theNumVoices)
{
  //initialize mutext
    myLock = new Mutex();
    //cluster id
    myId = ++clusterId;
    
    //playback bool to make sure we precisely time grain triggers
    awaitingPlay = false;
    
    //number of voices
    numVoices = theNumVoices;
    //initialize random number generator (for random motion)
    srand(time(NULL));
    
    //initialize interfacing flags
    addFlag = false;
    removeFlag = false;
    
    //keep pointer to the sound set
    theSounds = soundSet;
    
    //trigger idx
    nextGrain = 0;
    
    //intialize timer
    local_time = 0;

    //default duration (ms)
    duration = 500.0;

    //default pitch 
    pitch = 1.0f;
    
    //default window type
    windowType = HANNING;
    
    //initialize pitch LFO
    pitchLFOFreq = 0.01f;
    pitchLFOAmount = 0.0f;
    
    //initialize channel multiplier array
    channelMults = new double[MY_CHANNELS];
    for (int i = 0; i < MY_CHANNELS; i++){
        channelMults[i] = 0.999f;
    }
    
    currentAroundChan = 1;
    stereoSide = 0; 
    side = 1;

    
    spatialMode = UNITY;
    channelLocation = -1;
    
    myDirMode = RANDOM_DIR;
 
    //create grain voice vector
    myGrains = new vector<GrainVoice *>;
    
    //populate grain cloud
    for (int i = 0; i < numVoices; i++)
    {
        myGrains->push_back(new GrainVoice( theSounds, duration, pitch));
    }

    //set volume of cloud to unity
    setVolumeDb(0.0);
    
    //set overlap (default to full overlap)
    setOverlap(1.0f);
    
//    //direction 
//    setDirection(RANDOM_DIR);
    
    //initialize trigger time (samples)
    bang_time = duration * MY_SRATE * (double) 0.001 / overlap;    

    //load grains
    for (int i = 0; i < myGrains->size(); i++){
        myGrains->at(i)->setDurationMs(duration);
    }
    
    //state - (user can remove cloud from "play" for editing)
    isActive = true;
    

    
}
int fei::Vector_core::scatterToOverlap()
{
  if (fei::numProcs(comm_) == 1 || haveFEVector()) {
    return(0);
  }

#ifndef FEI_SER
  if (!overlapAlreadySet_) {
    setOverlap();
  }

  //...and now the overlap is whatever is in our remotelyOwned_ vectors.

  //first find out which procs we'll be receiving from.
  std::vector<int> recvProcs;
  for(unsigned i=0; i<remotelyOwned_.size(); ++i) {
    if ((int)i == fei::localProc(comm_)) continue;
    if (remotelyOwned_[i]->size() == 0) continue;

    recvProcs.push_back((int)i);
  }

  //find out the send-procs.
  std::vector<int> sendProcs;
  fei::mirrorProcs(comm_, recvProcs, sendProcs);

  //declare arrays to send from, and corresponding sizes
  std::vector<std::vector<int> > send_ints(sendProcs.size());
  std::vector<std::vector<double> > send_doubles(sendProcs.size());
  std::vector<int> send_sizes(sendProcs.size());

  std::vector<MPI_Request> mpiReqs(sendProcs.size()+recvProcs.size());
  std::vector<MPI_Status> mpiStatuses(sendProcs.size()+recvProcs.size());
  int tag1 = 11111;
  int tag2 = 11112;

  //first, the procs we're going to send to, have to let us know
  //how much data we're supposed to send. So we have to receive
  //sizes and then indices from the "send"-procs.
  for(unsigned i=0; i<sendProcs.size(); ++i) {
    MPI_Irecv(&send_sizes[i], 1, MPI_INT, sendProcs[i],
              tag1, comm_, &mpiReqs[i]);
  }

  //now we'll send the sizes of our remotely-owned data to the
  //procs that we will be receiving the data from, and also the
  //indices that we want to receive.
  for(unsigned i=0; i<recvProcs.size(); ++i) {
    int proc = recvProcs[i];

    int size = remotelyOwned_[proc]->size();
    MPI_Send(&size, 1, MPI_INT, proc, tag1, comm_);
  }
 
  MPI_Waitall(sendProcs.size(), &mpiReqs[0], &mpiStatuses[0]);

  //now resize our send_ints and send_doubles arrays, and post the recvs
  //for indices that we're supposed to pack.
  for(unsigned i=0; i<sendProcs.size(); ++i) {
    int proc = sendProcs[i];
    int size = send_sizes[i];
    send_ints[i].resize(size);
    MPI_Irecv(&(send_ints[i][0]), size, MPI_INT, proc, tag1,
              comm_, &mpiReqs[i]);
    send_doubles[i].resize(size);
  }

  //now send the indices that we want to receive data for.
  for(unsigned i=0; i<recvProcs.size(); ++i) {
    int proc = recvProcs[i];
    int size = remotelyOwned_[proc]->size();
    int* indices = &(remotelyOwned_[proc]->indices())[0];
    MPI_Send(indices, size, MPI_INT, proc, tag1, comm_);
  }

  MPI_Waitall(sendProcs.size(), &mpiReqs[0], &mpiStatuses[0]);

  //now post our recvs.
  for(unsigned i=0; i<recvProcs.size(); ++i) {
    int proc = recvProcs[i];
    int size = remotelyOwned_[proc]->size();
    double* coefs = &(remotelyOwned_[proc]->coefs())[0];
    MPI_Irecv(coefs, size, MPI_DOUBLE, proc, tag2, comm_, &mpiReqs[i]);
  }

  //now pack and send the coefs that the other procs need from us.
  for(unsigned i=0; i<sendProcs.size(); ++i) {
    int proc = sendProcs[i];

    int num = send_sizes[i];
    int err = copyOutOfUnderlyingVector(num, &(send_ints[i][0]),
                                        &(send_doubles[i][0]), 0);
    if (err != 0) {
      FEI_COUT << "fei::Vector_core::scatterToOverlap ERROR getting data to send."<<FEI_ENDL;
      return(err);
    }

    MPI_Send(&(send_doubles[i][0]), num, MPI_DOUBLE, proc,
             tag2, comm_);
  }

  MPI_Waitall(recvProcs.size(), &mpiReqs[0], &mpiStatuses[0]);

#endif  //#ifndef FEI_SER

  return(0);
}