Beispiel #1
0
void GlissandoSegment::layout()
      {
      QRectF r = QRectF(0.0, 0.0, pos2().x(), pos2().y()).normalized();
      qreal lw = spatium() * glissando()->lineWidth().val() * .5;
      setbbox(r.adjusted(-lw, -lw, lw, lw));
      adjustReadPos();
      }
Beispiel #2
0
void GlissandoSegment::draw(QPainter* painter) const
      {
      painter->save();
      qreal _spatium = spatium();

      QPen pen(glissando()->curColor());
      pen.setWidthF(glissando()->lineWidth().val() * spatium());
      pen.setCapStyle(Qt::RoundCap);
      painter->setPen(pen);
//      painter->drawLine(QPointF(), pos2());               // DEBUG

      // rotate painter so that the line become horizontal
      qreal w     = pos2().x();
      qreal h     = pos2().y();
      qreal l     = sqrt(w * w + h * h);
      qreal wi = asin(-h / l) * 180.0 / M_PI;
      qreal scale = painter->worldTransform().m11();
      painter->rotate(-wi);

      if (glissando()->glissandoType() == Glissando::Type::STRAIGHT) {
            painter->drawLine(QLineF(0.0, 0.0, l, 0.0));
            }
      else if (glissando()->glissandoType() == Glissando::Type::WAVY) {
            QRectF b = symBbox(SymId::wiggleTrill);
            qreal w  = symAdvance(SymId::wiggleTrill);
            int n    = (int)(l / w);      // always round down (truncate) to avoid overlap
            qreal x  = (l - n*w) * 0.5;   // centre line in available space
            std::vector<SymId> ids;
            for (int i = 0; i < n; ++i)
                  ids.push_back(SymId::wiggleTrill);
            // this is very ugly but fix #68846 for now
//            bool tmp = MScore::pdfPrinting;
//            MScore::pdfPrinting = true;
            score()->scoreFont()->draw(ids, painter, magS(), QPointF(x, -(b.y() + b.height()*0.5) ), scale);
//            MScore::pdfPrinting = tmp;
            }
      if (glissando()->showText()) {
            const TextStyle& st = score()->textStyle(TextStyleType::GLISSANDO);
            QRectF r = st.fontMetrics(_spatium).boundingRect(glissando()->text());
            // if text longer than available space, skip it
            if (r.width() < l) {
                  qreal yOffset = r.height() + r.y();       // find text descender height
                  // raise text slightly above line and slightly more with WAVY than with STRAIGHT
                  yOffset += _spatium * (glissando()->glissandoType() == Glissando::Type::WAVY ? 0.4 : 0.1);
                  painter->setFont(st.font(_spatium * MScore::pixelRatio));
                  qreal x = (l - r.width()) * 0.5;
                  painter->drawText(QPointF(x, -yOffset), glissando()->text());
                  }
            }
      painter->restore();
      }
Beispiel #3
0
QVariant GlissandoSegment::propertyDefault(P_ID id) const
      {
      switch (id) {
            case P_ID::GLISS_TYPE:
            case P_ID::GLISS_TEXT:
            case P_ID::GLISS_SHOW_TEXT:
            case P_ID::GLISSANDO_STYLE:
            case P_ID::PLAY:
                  return glissando()->propertyDefault(id);
            default:
                  return LineSegment::propertyDefault(id);
            }
      }
Beispiel #4
0
bool GlissandoSegment::setProperty(P_ID id, const QVariant& v)
      {
      switch (id) {
            case P_ID::GLISS_TYPE:
            case P_ID::GLISS_TEXT:
            case P_ID::GLISS_SHOW_TEXT:
            case P_ID::GLISSANDO_STYLE:
            case P_ID::PLAY:
                  return glissando()->setProperty(id, v);
            default:
                  return LineSegment::setProperty(id, v);
            }
      }
Beispiel #5
0
QVariant GlissandoSegment::getProperty(P_ID id) const
      {
      switch (id) {
            // route properties of the whole Glissando element to it
            case P_ID::GLISS_TYPE:
            case P_ID::GLISS_TEXT:
            case P_ID::GLISS_SHOW_TEXT:
            case P_ID::GLISSANDO_STYLE:
            case P_ID::PLAY:
                  return glissando()->getProperty(id);
            default:
                  return LineSegment::getProperty(id);
            }
      }
Beispiel #6
0
void GlissandoSegment::draw(QPainter* painter) const
      {
      painter->save();
      qreal _spatium = spatium();

      QPen pen(glissando()->curColor());
      pen.setWidthF(glissando()->lineWidth().val() * spatium());
      pen.setCapStyle(Qt::RoundCap);
      painter->setPen(pen);
//      painter->drawLine(QPointF(), pos2());               // DEBUG

      // rotate painter so that the line become horizontal
      qreal w     = pos2().x();
      qreal h     = pos2().y();
      qreal l     = sqrt(w * w + h * h);
      qreal wi = asin(-h / l) * 180.0 / M_PI;
      painter->rotate(-wi);

      if (glissando()->glissandoType() == Glissando::Type::STRAIGHT) {
            painter->drawLine(QLineF(0.0, 0.0, l, 0.0));
            }
      else if (glissando()->glissandoType() == Glissando::Type::WAVY) {
            QRectF b = symBbox(SymId::wiggleTrill);
//            qreal h  = symHeight(SymId::wiggleTrill);     // DEBUG
            qreal w  = symWidth(SymId::wiggleTrill);
            int n    = (int)(l / w);      // always round down (truncate) to avoid overlap
            qreal x  = (l - n*w) * 0.5;   // centre line in available space
            drawSymbol(SymId::wiggleTrill, painter, QPointF(x, b.height()*.70), n);
            }
      if (glissando()->showText()) {
            const TextStyle& st = score()->textStyle(TextStyleType::GLISSANDO);
            QFont f = st.fontPx(_spatium);
            QRectF r = QFontMetricsF(f).boundingRect(glissando()->text());
            // if text longer than available space, skip it
            if (r.width() < l) {
                  qreal yOffset = r.height() + r.y();       // find text descender height
                  // raise text slightly above line and slightly more with WAVY than with STRAIGHT
                  yOffset += _spatium * (glissando()->glissandoType() == Glissando::Type::WAVY ? 0.5 : 0.1);
                  painter->setFont(f);
                  qreal x = (l - r.width()) * 0.5;
                  painter->drawText(QPointF(x, -yOffset), glissando()->text());
                  }
            }
      painter->restore();
      }
// Progress module by one tick
static void play_module() {
  uint8_t  ch, fx, fxp;
  uint8_t  temp_b;
  uint16_t temp_w;
  fxm_t   *p_fxm;
  dma_t   *p_dma;
  bool     pattern_jump = false;
  uint8_t  ix_period;
  uint8_t  ix_sample;
  uint8_t *p_ptn;

  // Advance tick
  if( ++tick == speed ) tick = 0;

  // Handle row delay
  if( delay ) {
    if( tick == 0 ) delay--;
    return;
  }

  // Advance playback
  if( tick == 0 ) {
    if( ++ix_row == 64 ) {
      ix_row = 0;
      if( ++ix_order == ROM_READB( &p_mod->order_count ) ) ix_order = 0;
    }
    // Forced order/row
    if( ix_nextorder != 0xFF ) {
      ix_order = ix_nextorder;
      ix_nextorder = 0xFF;
    }
    if( ix_nextrow != 0xFF ) {
      ix_row = ix_nextrow;
      ix_nextrow = 0xFF;
    }

  }

  // Set up pointers
  p_ptn = ( ( uint8_t* )p_mod )
        + sizeof( ptm_t )
        + ( ROM_READB( &p_mod->order[ ix_order ] ) << 10 )
        + ( ix_row << 4 );

  p_fxm = fxm;
  p_dma = dma;

  for( ch = 0; ch != 4; ch++ ) {

    // Deconstruct cell (what the hell were they smoking?)
    temp_b     = ROM_READB( p_ptn++ );                // sample.msb and period.msb
    temp_w     = ( temp_b & 0x0F ) << 8;
    ix_sample  = temp_b & 0xF0;
    temp_w    |= ROM_READB( p_ptn++ );                // period.lsb
    temp_b     = ROM_READB( p_ptn++ );                // sample.lsb and effect
    ix_sample |= HI4( temp_b );
    fx         = LO4( temp_b ) << 4;
    fxp        = ROM_READB( p_ptn++ );                // parameters
    if( fx == 0xE0 ) {
      fx |= HI4( fxp );                   // extended parameters
      fxp  &= 0x0F;
    }
    ix_period = 0x7F;                     // period index
    if( temp_w ) {
      for( temp_b = 0; temp_b != 36; temp_b++ ) {
        if( ROM_READW( &period_tbl[ 0 ][ temp_b ] ) == temp_w ) {
          ix_period = temp_b;
          break;
        }
      }
    }

    // General effect parameter memory
    // NOTE: Unsure if this is true to the original ProTracker, but alot of
    //       modern players and trackers do implement this functionality.
    if( fx == 0x10 || fx == 0x20 || fx == 0xE1 || fx == 0xE2 || fx == 0x50 || fx == 0x60 || fx == 0xA0 ) {
      if( fxp ) {
        p_fxm->param = fxp;
      } else {
        fxp = p_fxm->param;
      }
    }

    if( tick == ( fx == 0xED ? fxp : 0 ) ) {
      if( ix_sample != 0 ) {
        // Cell has sample
        temp_b = ix_sample - 1;
        p_fxm->sample = temp_b;
        p_fxm->volume = sample[ temp_b ].volume;
        // Reset volume
        p_dma->volume = sample[ temp_b ].volume;
      }

      // Set tuning
      if( fx == 0xE5 ) sample[ p_fxm->sample ].tuning = fxp;
      // Reset oscillators
      if( ( p_fxm->vibr.mode & 0x4 ) == 0x0 ) p_fxm->vibr.offset = 0;
      if( ( p_fxm->trem.mode & 0x4 ) == 0x0 ) p_fxm->trem.offset = 0;

      if( ix_period != 0x7F ) {
        // Cell has note
        if( fx == 0x30 || fx == 0x50 ) {
          // Tone-portamento effect setup
          p_fxm->port_target = ROM_READW( &period_tbl[ sample[ ix_sample ].tuning ][ ix_period ] );
        } else {
          // Start note
          temp_b = p_fxm->sample;
          note_start( p_dma, temp_b, ix_period, ( fx == 0x90 ? fxp : 0 ) );
          // Set required effect memory parameters
          p_fxm->period = ROM_READW( &period_tbl[ sample[ temp_b ].tuning ][ ix_period ] );
        }
      }

      // Effects processed when tick = 0
      switch( fx ) {
        case 0x30: // Portamento
          if( fxp ) p_fxm->port_speed = fxp;
          break;
        case 0xB0: // Jump to pattern
          ix_nextorder = ( fxp >= ROM_READB( &p_mod->order_count ) ? 0x00 : fxp );
          ix_nextrow = 0;
          pattern_jump = true;
          break;
        case 0xC0: // Set volume
          p_fxm->volume = MIN( fxp, 0x40 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xD0: // Jump to row
          fxp = HI4( fxp ) * 10 + LO4( fxp );
          if( !pattern_jump ) ix_nextorder = ( ( ix_order + 1 ) >= ROM_READB( &p_mod->order_count ) ? 0x00 : ix_order + 1 );
          pattern_jump = true;
          ix_nextrow = ( fxp > 63 ? 0 : fxp );
          break;
        case 0xF0: // Set speed
          if( fxp > 0x20 ) {
            cia = SAMPLE_RATE / ( ( 24 * fxp ) / 60 );
          } else {
            speed = fxp;
          }
          break;
        case 0x40: // Vibrato
          if( fxp ) p_fxm->vibr.fxp = fxp;
          break;
        case 0x70: // Tremolo
          if( fxp ) p_fxm->trem.fxp = fxp;
          break;
        case 0xE1: // Fine slide up
          p_fxm->period = MAX( p_fxm->period - fxp, PERIOD_MIN );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE2: // Fine slide down
          p_fxm->period = MIN( p_fxm->period + fxp, PERIOD_MAX );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE3: // Glissando control
          p_fxm->glissando = ( fxp != 0 );
          break;
        case 0xE4: // Set vibrato waveform
          p_fxm->vibr.mode = fxp;
          break;
        case 0xE6: // Loop-back (advanced looping)
          if( fxp == 0x0 ) {
            p_fxm->loop_order = ix_order;
            p_fxm->loop_row   = ix_row;
          } else {
            p_fxm->loop_count = ( p_fxm->loop_count ? p_fxm->loop_count - 1 : fxp );
            if( p_fxm->loop_count ) {
              ix_nextorder = p_fxm->loop_order;
              ix_nextrow   = p_fxm->loop_row;
            }
          }
          break;
        case 0xE7: // Set tremolo waveform
          p_fxm->trem.mode = fxp;
          break;
        case 0xEA: // Fine volume slide up
          p_fxm->volume = MIN( p_fxm->volume + fxp, 0x40 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xEB: // Fine volume slide down
          p_fxm->volume = MAX( p_fxm->volume - fxp, 0 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xEE: // Delay
          delay = fxp;
          break;
      }

    } else {
      // Effects processed when tick > 0
      switch( fx ) {
        case 0x10: // Slide up
          p_fxm->period = MAX( p_fxm->period - fxp, PERIOD_MIN );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0x20: // Slide down
          p_fxm->period = MIN( p_fxm->period + fxp, PERIOD_MAX );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE9: // Retrigger note
          temp_b = tick; while( temp_b >= fxp ) temp_b -= fxp;
          if( temp_b == 0 ) note_start( p_dma, p_fxm->sample, ix_period, ( fx == 0x90 ? fxp : 0 ) );
          break;
        case 0xEC: // Note cut
          if( fxp == tick ) p_dma->volume = 0x00;
          break;
        default:   // Multi-effect processing
          // Portamento
          if( fx == 0x30 || fx == 0x50 ) {
            if( p_fxm->period < p_fxm->port_target ) p_fxm->period = MIN( p_fxm->period + p_fxm->port_speed,  p_fxm->port_target );
            else                                     p_fxm->period = MAX( p_fxm->period - p_fxm->port_speed,  p_fxm->port_target );
            if( p_fxm->glissando ) p_dma->rate = SYS_FREQ / glissando( ch );
            else                   p_dma->rate = SYS_FREQ / p_fxm->period;
          }
          // Volume slide
          if( fx == 0x50 || fx == 0x60 || fx == 0xA0 ) {
            if( ( fxp & 0xF0 ) == 0 ) p_fxm->volume -= ( LO4( fxp ) );
            if( ( fxp & 0x0F ) == 0 ) p_fxm->volume += ( HI4( fxp ) );
            p_fxm->volume = MAX( MIN( p_fxm->volume, 0x40 ), 0 );
            p_dma->volume = p_fxm->volume;
          }
      }
    }

    // Normal play and arpeggio
    if( fx == 0x00 ) {
      temp_b = tick; while( temp_b > 2 ) temp_b -= 2;
      if( temp_b == 0 ) {
        // Reset
        p_dma->rate = SYS_FREQ / p_fxm->period;
      } else if( fxp ) {
        // Arpeggio
        p_dma->rate = SYS_FREQ / arpeggio( ch, ( temp_b == 1 ? HI4( fxp ) : LO4( fxp ) ) );
      }
    } else if( fx == 0x40 || fx == 0x60 ) {
      // Vibrato
      p_dma->rate = SYS_FREQ / ( p_fxm->period + do_osc( &p_fxm->vibr ) );
    } else if( fx == 0x70 ) {
      // Tremolo
      temp_b = p_fxm->volume + do_osc( &p_fxm->trem );
      p_dma->volume = MAX( MIN( temp_b, 0x40 ), 0 );
    }

    p_fxm++;
    p_dma++;
  }
}