<commit_before>#include "unisparks/player.h"
#include "unisparks/log.h"
#include "unisparks/math.h"
#include "unisparks/timer.h"
#include <stdlib.h>

namespace unisparks {

/** 
 * Add two conceptually unsigned integers handling
 * wrap/overflow.
 */
inline int32_t addwrap(int32_t a, int32_t b) {
  int32_t s = a + b;
  return s >= 0 ? s : s - INT32_MIN;
}

// --------------------------------------------------------------------
// Player
// --------------------------------------------------------------------
Player::Player(Pixels& pixels, const Playlist& playlist) : playlist_(playlist), pixels_(pixels) {
  renderBufSize_ = 0;
  for(int i=0; i<playlist_.size(); ++i) {
    if (renderBufSize_ < playlist_[i]->renderBufSize(pixels_)) {
      renderBufSize_ = playlist_[i]->renderBufSize(pixels_);
    }
  }
  renderBuf_ = new uint8_t[renderBufSize_];
  play(playlist_[0], LOW_PRIORITY);
}

Player::~Player() { 
  delete[] renderBuf_;
}

void Player::play(int i) {
  track_ = i % playlist_.size();
  if (track_ < 0) {
    track_ += playlist_.size();
  }
  play(playlist_[track_], HIGH_PRIORITY);
}

void Player::next() { 
  track_ = track_ < playlist_.size() - 1 ? track_ + 1 : 0; 
  play(playlist_[track_], HIGH_PRIORITY);
}

void Player::prev() { 
  track_ = track_ > 0 ? track_ - 1 : playlist_.size() - 1;
  play(playlist_[track_], HIGH_PRIORITY);
}

void Player::render() {
  if (!renderer_) {
    return;
  }
  int32_t currTs = timeMillis();
  int32_t dt = addwrap(currTs, -frameTs_);
  frameTs_ = currTs;
  frame_.timeElapsed = addwrap(frame_.timeElapsed, dt);
  frame_.timeSinceBeat = addwrap(frame_.timeSinceBeat, dt);
  if (mode_ != play_forever) {
    frame_.timeRemaining -= dt;
  }
  if (frame_.timeRemaining <= 0) {
    advance();
  }
  renderer_->render(frame_);
}

void Player::play(const Effect *ef, int priority) {
  assert(ef);
  if (priority_ > priority) {
    return;
  }
  if (renderer_) {
    renderer_->~Renderer();
  }
  if (!renderer_ || &renderer_->effect() != ef) {
    renderer_ = ef->start(pixels_, renderBuf_, renderBufSize_);
    priority_ = priority;
    frame_.timeElapsed = 0;
    frame_.timeRemaining = ef->preferredDuration();
    info("player %p selected effect %s", this, effectName());
  }
}

void Player::advance() {
    switch(mode_) {
      case cycle_one:
        play(playlist_[track_], LOW_PRIORITY);
        break;
      case cycle_all:
        track_ = track_ < playlist_.size() - 1 ? track_ + 1 : 0; <commit_msg>Fix crash on ESP8266<commit_after>#include "unisparks/player.h"
#include "unisparks/log.h"
#include "unisparks/math.h"
#include "unisparks/timer.h"
#include <stdlib.h>

namespace unisparks {

/** 
 * Add two conceptually unsigned integers handling
 * wrap/overflow.
 */
inline int32_t addwrap(int32_t a, int32_t b) {
  int32_t s = a + b;
  return s >= 0 ? s : s - INT32_MIN;
}

// --------------------------------------------------------------------
// Player
// --------------------------------------------------------------------
Player::Player(Pixels& pixels, const Playlist& playlist) : playlist_(playlist), pixels_(pixels) {
  renderBufSize_ = 0;
  for(int i=0; i<playlist_.size(); ++i) {
    if (renderBufSize_ < playlist_[i]->renderBufSize(pixels_)) {
      renderBufSize_ = playlist_[i]->renderBufSize(pixels_);
    }
  }
  renderBuf_ = new uint8_t[renderBufSize_];
  play(playlist_[0], LOW_PRIORITY);
}

Player::~Player() { 
  delete[] renderBuf_;
}

void Player::play(int i) {
  track_ = i % playlist_.size();
  if (track_ < 0) {
    track_ += playlist_.size();
  }
  play(playlist_[track_], HIGH_PRIORITY);
}

void Player::next() { 
  track_ = track_ < playlist_.size() - 1 ? track_ + 1 : 0; 
  play(playlist_[track_], HIGH_PRIORITY);
}

void Player::prev() { 
  track_ = track_ > 0 ? track_ - 1 : playlist_.size() - 1;
  play(playlist_[track_], HIGH_PRIORITY);
}

void Player::render() {
  if (!renderer_) {
    return;
  }
  int32_t currTs = timeMillis();
  int32_t dt = addwrap(currTs, -frameTs_);
  frameTs_ = currTs;
  frame_.timeElapsed = addwrap(frame_.timeElapsed, dt);
  frame_.timeSinceBeat = addwrap(frame_.timeSinceBeat, dt);
  if (mode_ != play_forever) {
    frame_.timeRemaining -= dt;
  }
  if (frame_.timeRemaining <= 0) {
    advance();
  }
  renderer_->render(frame_);
}

void Player::play(const Effect *ef, int priority) {
  assert(ef);
  if (priority_ > priority) {
    return;
  }
  if (renderer_) {
    renderer_->~Renderer();
    renderer_ = nullptr;
  }
  if (!renderer_ || &renderer_->effect() != ef) {
    renderer_ = ef->start(pixels_, renderBuf_, renderBufSize_);
    priority_ = priority;
    frame_.timeElapsed = 0;
    frame_.timeRemaining = ef->preferredDuration();
    info("player %p selected effect %s", this, effectName());
  }
}

void Player::advance() {
    switch(mode_) {
      case cycle_one:
        play(playlist_[track_], LOW_PRIORITY);
        break;
      case cycle_all:
        track_ = track_ < playlist_.size() - 1 ? track_ + 1 : 0; 
{'fraction_non_alphanumeric': 0.2008874546187979, 'fraction_numerical': 0.013311819281968536, 'mean_word_length': 2.8293436293436294, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4299593', 'n_tokens_mistral': 1795, 'n_tokens_neox': 1744, 'n_words': 363}