public void testReflectVibratoPitch()
        {
            var tempoTable = new TempoVector();
            var pitchBend = new VsqBPList( CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum() );
            var pitchBendSensitivity = new VsqBPList( CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum() );

            pitchBend.add( 0, 8191 );
            pitchBendSensitivity.add( 0, 2 );

            var generator = new AquesTone2WaveGeneratorStub();
            var item = new VsqEvent( 0, new VsqID() );
            item.ID.type = VsqIDType.Anote;
            item.ID.VibratoHandle = new VibratoHandle();
            item.ID.VibratoHandle.StartRate = 0x40;
            item.ID.VibratoHandle.RateBP.clear();
            item.ID.VibratoHandle.StartDepth = 0x40;
            item.ID.VibratoHandle.DepthBP.clear();
            item.ID.setLength( 480 );
            item.ID.VibratoDelay = 430;
            item.ID.VibratoHandle.setLength( 50 );
            generator.reflectVibratoPitch( item, pitchBend, pitchBendSensitivity, tempoTable );

            {
                var expectedPit = new Dictionary<int, int> {
                    { 0, 8191 },
                    { 430, 5461 }, { 431, 5467 }, { 432, 5484 }, { 433, 5514 }, { 434, 5555 },
                    { 435, 5608 }, { 436, 5672 }, { 437, 5748 }, { 438, 5835 }, { 439, 5932 },
                    { 440, 6041 }, { 441, 6096 }, { 442, 6151 }, { 443, 6205 }, { 444, 6257 },
                    { 445, 6309 }, { 446, 6360 }, { 447, 6410 }, { 448, 6459 }, { 449, 6507 },
                    { 450, 6553 }, { 451, 6598 }, { 452, 6642 }, { 453, 6684 }, { 454, 6725 },
                    { 455, 6764 }, { 456, 6802 }, { 457, 6838 }, { 458, 6873 }, { 459, 6906 },
                    { 460, 6937 }, { 461, 6967 }, { 462, 6994 }, { 463, 7020 }, { 464, 7044 },
                    { 465, 7066 }, { 466, 7087 }, { 467, 7105 }, { 468, 7121 }, { 469, 7136 },
                    { 470, 7148 }, { 471, 6989 }, { 472, 6826 }, { 473, 6660 }, { 474, 6491 },
                    { 475, 6320 }, { 476, 6149 }, { 477, 5976 }, { 478, 5804 }, { 479, 5632 },
                    { 480, 8191 }
                };
                Assert.AreEqual( expectedPit.Count, pitchBend.size() );
                int i = 0;
                foreach ( var pitInfo in expectedPit ) {
                    Assert.AreEqual( pitInfo.Key, pitchBend.getKeyClock( i ) );
                    Assert.AreEqual( pitInfo.Value, pitchBend.getElementA( i ) );
                    ++i;
                }
            }

            {
                var expectedPbs = new Dictionary<int, int> {
                    { 0, 2 }, { 430, 3 }, { 480, 2 }
                };
                Assert.AreEqual( expectedPbs.Count, pitchBendSensitivity.size() );
                int i = 0;
                foreach ( var pbsInfo in expectedPbs ) {
                    Assert.AreEqual( pbsInfo.Key, pitchBendSensitivity.getKeyClock( i ) );
                    Assert.AreEqual( pbsInfo.Value, pitchBendSensitivity.getElementA( i ) );
                    ++i;
                }
            }
        }
Ejemplo n.º 2
0
 /// <summary>
 /// コンストラクタ。trackはcloneされないが、tempoはcloneされる。
 /// </summary>
 /// <param name="track"></param>
 /// <param name="tempo"></param>
 public RenderedStatus(VsqTrack track, TempoVector tempo, SequenceConfig config)
 {
     this.track = track;
     this.tempo = new TempoVector();
     foreach (var entry in tempo)
     {
         this.tempo.Add((TempoTableEntry)entry.clone());
     }
     this.config = config;
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Initialize by VsqEvent object.
 /// </summary>
 /// <param name="item"></param>
 /// <param name="timesig_table"></param>
 public TiedEvent(VsqEvent item, TimesigVector timesig_table, TempoVector tempo_table)
 {
     Init(timesig_table, tempo_table, item.Clock, item.ID.getLength(), item.ID.Note, false);
     if (notes_.Count > 0 && item.ID.LyricHandle != null && item.ID.LyricHandle.getCount() > 0)
     {
         var lyric = new lyric();
         lyric.text.Add(new textelementdata());
         lyric.text.First.Value = item.ID.LyricHandle.getLyricAt(0).Phrase;
         notes_[0].lyric        = new lyric[] { lyric };
     }
 }
Ejemplo n.º 4
0
 /// <summary>
 /// このWAVE描画コンテキストが保持しているWAVEデータを、ゲートタイム基準でグラフィクスに描画します。
 /// 縦軸は最大振幅がちょうど描画範囲に収まるよう調節されます。
 /// </summary>
 /// <param name="g">描画に使用するグラフィクスオブジェクト</param>
 /// <param name="pen">描画に使用するペン</param>
 /// <param name="rect">描画範囲</param>
 /// <param name="clock_start">描画開始位置のゲートタイム</param>
 /// <param name="clock_end">描画終了位置のゲートタイム</param>
 /// <param name="tempo_table">ゲートタイムから秒数を調べる際使用するテンポ・テーブル</param>
 /// <param name="pixel_per_clock">ゲートタイムあたりの秒数</param>
 public void draw(
     Graphics2D g,
     Color pen,
     Rectangle rect,
     int clock_start,
     int clock_end,
     TempoVector tempo_table,
     float pixel_per_clock)
 {
     drawCore(g, pen, rect, clock_start, clock_end, tempo_table, pixel_per_clock, 1.0f, true);
 }
Ejemplo n.º 5
0
 /// <summary>
 /// このWAVE描画コンテキストが保持しているWAVEデータを、ゲートタイム基準でグラフィクスに描画します。
 /// </summary>
 /// <param name="g">描画に使用するグラフィクスオブジェクト</param>
 /// <param name="pen">描画に使用するペン</param>
 /// <param name="rect">描画範囲</param>
 /// <param name="clock_start">描画開始位置のゲートタイム</param>
 /// <param name="clock_end">描画終了位置のゲートタイム</param>
 /// <param name="tempo_table">ゲートタイムから秒数を調べる際使用するテンポ・テーブル</param>
 /// <param name="pixel_per_clock">ゲートタイムあたりの秒数</param>
 /// <param name="scale_y">Y軸方向の描画スケール。デフォルトは1.0</param>
 /// <param name="auto_maximize">自動で最大化するかどうか</param>
 private void drawCore(
     Graphics2D g,
     Color pen,
     Rectangle rect,
     int clock_start,
     int clock_end,
     TempoVector tempo_table,
     float pixel_per_clock,
     float scale_y,
     bool auto_maximize)
 {
 }
Ejemplo n.º 6
0
        public VibratoPointIteratorByClock(TempoVector tempo_table,
                                           VibratoBPList rate,
                                           int start_rate,
                                           VibratoBPList depth,
                                           int start_depth,
                                           int clock_start,
                                           int clock_width)
        {
            this.mTempoTable = tempo_table;
            this.mRate       = rate;
            this.mStartRate  = start_rate;
            this.mDepth      = depth;
            this.mStartDepth = start_depth;
            this.mClockStart = clock_start;
            this.mClockWidth = clock_width;

            rewind();
        }
Ejemplo n.º 7
0
        private TempoVector quantizeTempoTable(TempoVector tempo_table)
        {
            var copy = new TempoVector();

            copy.AddRange(
                tempo_table
                .Select((tempo) => {
                int clock = quantize(tempo.Clock);
                return(new TempoTableEntry(clock, tempo.Tempo, 0.0));
            }));
            for (int i = copy.Count - 1; i > 0; i--)
            {
                if (copy[i].Clock == copy[i - 1].Clock)
                {
                    copy.RemoveAt(i);
                }
            }
            copy.updateTempoInfo();
            return(copy);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Create MusicXML.scorepartwisePart object by VsqTrack instance.
        /// </summary>
        /// <param name="track"></param>
        /// <param name="timesig_table"></param>
        /// <returns></returns>
        private scorepartwisePart createScorePart(VsqTrack track, TimesigVector timesig_table, TempoVector tempo_table)
        {
            var     part      = new scorepartwisePart();
            var     note_list = quantizeTrack(track, timesig_table, tempo_table);
            var     measures  = new List <scorepartwisePartMeasure>();
            int     measure   = 0;
            Timesig timesig   = new Timesig(0, 0);

            while (0 < note_list.Count)
            {
                int measure_start_clock = timesig_table.getClockFromBarCount(measure);
                int measure_end_clock   = timesig_table.getClockFromBarCount(measure + 1);

                var tempo_change_in_measure = new TempoVector();
                tempo_change_in_measure.AddRange(
                    tempo_table
                    .Where((tempo) => measure_start_clock <= tempo.Clock && tempo.Clock < measure_end_clock)
                    .Select((tempo) => (TempoTableEntry)tempo.Clone()));

                // get the list of TiedEvent, contained in target measure.
                var in_measure_tied_note_list =
                    note_list
                    .Where((tied_event) => {
                    int tied_event_start = tied_event.Clock;
                    int tied_event_end   = tied_event.Clock + tied_event.Length;
                    return
                    ((measure_start_clock <= tied_event_start && tied_event_start < measure_end_clock) ||
                     (measure_start_clock <= tied_event_end && tied_event_end < measure_end_clock) ||
                     (tied_event_start <= measure_start_clock && measure_end_clock <= tied_event_end));
                });

                // get the list of MusicXML.note.
                var in_measure_note_list =
                    in_measure_tied_note_list
                    .SelectMany((tied_event) => {
                    var result = new List <object>();
                    int clock  = tied_event.Clock;
                    foreach (var note in tied_event)
                    {
                        int length = (int)note.duration.First;
                        if (measure_start_clock <= clock && clock + length <= measure_end_clock)
                        {
                            var tempo_change =
                                tempo_change_in_measure
                                .FirstOrDefault((tempo) => tempo.Clock == clock);
                            if (tempo_change != null)
                            {
                                var direction                = new direction();
                                direction.placement          = abovebelow.above;
                                direction.placementSpecified = true;
                                direction.directiontype      = new directiontype[] { new directiontype() };
                                direction.directiontype[0].metronome.Add(new metronome());
                                var perminute   = new perminute();
                                perminute.Value = getTempo(tempo_change).ToString();
                                direction.directiontype[0].metronome[0].Items = new object[] { notetypevalue.quarter, perminute };
                                direction.sound                = new sound();
                                direction.sound.tempo          = getTempo(tempo_change);
                                direction.sound.tempoSpecified = true;
                                result.Add(direction);
                            }
                            result.Add(note);
                        }
                        clock += length;
                    }
                    return(result);
                });

                var partwise_measure = new scorepartwisePartMeasure();
                partwise_measure.number = (measure + 1).ToString();
                var items = new List <object>();

                var measure_timesig = timesig_table.getTimesigAt(measure_start_clock);
                if (!measure_timesig.Equals(timesig))
                {
                    var attributes = new MusicXML.attributes();
                    attributes.divisions          = 480;
                    attributes.divisionsSpecified = true;
                    attributes.time = new time[] { new time() };
                    attributes.time[0].beats.Add(measure_timesig.numerator.ToString());
                    attributes.time[0].beattype.Add(measure_timesig.denominator.ToString());
                    attributes.time[0].symbol          = timesymbol.common;
                    attributes.time[0].symbolSpecified = true;
                    items.Add(attributes);
                }
                timesig = measure_timesig;

                items.AddRange(in_measure_note_list);
                partwise_measure.Items = items.ToArray();
                measures.Add(partwise_measure);

                note_list.RemoveAll((tied_event) => tied_event.Clock + tied_event.Length <= measure_end_clock);

                measure++;
            }

            part.measure = measures.ToArray();
            return(part);
        }
Ejemplo n.º 9
0
            private void Init(TimesigVector timesig_table, TempoVector tempo_table, int clock_start, int length, int note_number, bool create_rest)
            {
                clock_  = clock_start;
                length_ = length;

                // 着目している範囲内のテンポのみを取り出す
                var small_tempo_table = new TempoVector();

                small_tempo_table.AddRange(
                    tempo_table
                    .Where((tempo) => clock_start <= tempo.Clock && tempo.Clock < clock_start + length)
                    .Select((tempo) => (TempoTableEntry)tempo.Clone()));

                // <pitch> エレメントのテンプレートを作成
                MusicXML.pitch pitch = null;
                if (!create_rest)
                {
                    pitch = new pitch();
                    int  octave = VsqNote.getNoteOctave(note_number) + 1;
                    step step;
                    if (Enum.TryParse <step>(VsqNote.getNoteStringBase(note_number), out step))
                    {
                        pitch.step = step;
                    }
                    pitch.octave = octave.ToString();
                    int alter = VsqNote.getNoteAlter(note_number);
                    if (alter != 0)
                    {
                        pitch.alter          = alter;
                        pitch.alterSpecified = true;
                    }
                }

                int clock_end     = clock_start + length;
                int current_clock = clock_start;

                while (current_clock < clock_start + length)
                {
                    int next_bar_clock    = timesig_table.getClockFromBarCount(timesig_table.getBarCountFromClock(current_clock) + 1);
                    int next_tempo_change = clock_end;
                    if (small_tempo_table.Count > 0)
                    {
                        try {
                            next_tempo_change =
                                small_tempo_table
                                .First((tempo) => {
                                return(current_clock < tempo.Clock && tempo.Clock < clock_end);
                            })
                                .Clock;
                        } catch (InvalidOperationException) { }
                    }

                    int next_separation_point = Math.Min(Math.Min(clock_end, next_bar_clock), next_tempo_change);

                    int remain   = next_separation_point - current_clock;
                    var template =
                        templates_
                        .OrderByDescending((note) => note.duration.First)
                        .FirstOrDefault((note) => note.duration.First <= remain);
                    if (template == null)
                    {
                        break;
                    }
                    else
                    {
                        var note = template.Clone();
                        if (create_rest)
                        {
                            note.rest.Add(new rest());
                        }
                        else
                        {
                            note.pitch.Add(pitch.Clone());
                            note.stem       = new stem();
                            note.stem.Value = stemvalue.up;
                        }
                        notes_.Add(note);
                        current_clock += (int)note.duration.First;
                    }
                }

                // connect note with tie
                if (!create_rest && notes_.Count >= 2)
                {
                    for (int i = 0; i < notes_.Count; ++i)
                    {
                        var note      = notes_[i];
                        var tied_list = new List <tied>();
                        if (i < notes_.Count - 1)
                        {
                            var start_tie = new tie();
                            start_tie.type = startstop.start;
                            note.tie.Add(start_tie);

                            var tied = new tied();
                            tied.type = startstopcontinue.start;
                            tied_list.Add(tied);
                        }
                        if (0 < i)
                        {
                            var stop_tie = new tie();
                            stop_tie.type = startstop.stop;
                            note.tie.Add(stop_tie);

                            var tied = new tied();
                            tied.type = startstopcontinue.stop;
                            tied_list.Add(tied);
                        }
                        var notations = new notations();
                        notations.Items = tied_list.ToArray();
                        note.notations  = new MusicXML.notations[] { notations };
                    }
                }
            }
Ejemplo n.º 10
0
 /// <summary>
 /// Initialize by start clock and length. This constructor creates a 'rest'.
 /// </summary>
 /// <param name="clock_start"></param>
 /// <param name="length"></param>
 /// <param name="timesig_table"></param>
 public TiedEvent(int clock_start, int length, TimesigVector timesig_table, TempoVector tempo_table)
 {
     Init(timesig_table, tempo_table, clock_start, length, 0, true);
 }
 public void reflectVibratoPitch( VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable )
 {
     base.reflectNoteEventPitch( item, pitchBend, pitchBendSensitivity, tempoTable );
 }
Ejemplo n.º 12
0
        /// <summary>
        /// 音符に付随するピッチベンドの情報を、PIT・PBS カーブに反映する
        /// </summary>
        /// <param name="item">音符</param>
        /// <param name="pitchBend">PIT カーブ</param>
        /// <param name="pitchBendSensitivity">PBS カーブ</param>
        /// <param name="tempoTable">テンポ情報</param>
        protected void reflectNoteEventPitch( VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable )
        {
            if ( item.ID.type != VsqIDType.Anote ) return;
            
            // AquesTone2 では、note on と同 clock にピッチベンドイベントを送らないと音程が反映されないので、必ずピッチイベントが送られるようにする
            pitchBend.add( item.Clock, pitchBend.getValue( item.Clock ) );

            if ( item.ID.VibratoHandle == null ) {
                return;
            }

            int startClock = item.Clock + item.ID.VibratoDelay;
            int vibratoLength = item.ID.Length - item.ID.VibratoDelay;

            var iterator = new VibratoPointIteratorByClock( tempoTable,
                                                            item.ID.VibratoHandle.RateBP, item.ID.VibratoHandle.StartRate,
                                                            item.ID.VibratoHandle.DepthBP, item.ID.VibratoHandle.StartDepth,
                                                            startClock, vibratoLength );
            var pitContext = new ByRef<int>( 0 );
            var pbsContext = new ByRef<int>( 0 );

            int pitAtEnd = pitchBend.getValue( startClock + vibratoLength );
            int pbsAtEnd = pitchBendSensitivity.getValue( startClock + vibratoLength );
            var pitBackup = (VsqBPList)pitchBend.Clone();
            var pbsBackup = (VsqBPList)pitchBendSensitivity.Clone();

            bool resetPBS = false;
            double maxNetPitchBendInCent = 0.0;
            for ( int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock ) {
                double vibratoPitchBendInCent = iterator.next() * 100.0;
                int pit = pitchBend.getValue( clock, pitContext );
                int pbs = pitchBendSensitivity.getValue( clock, pbsContext );
                const double pow2_13 = 8192;
                double netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max( maxNetPitchBendInCent, Math.Abs( netPitchBendInCent ) );
                int draftPitchBend = (int)Math.Round( (netPitchBendInCent / 100.0) * pow2_13 / pbs );

                if ( draftPitchBend < pitchBend.Minimum || pitchBend.Maximum < draftPitchBend ) {
                    // pbs を変更せずにビブラートによるピッチベンドを反映しようとすると、
                    // pit が範囲を超えてしまう。
                    resetPBS = true;
                } else {
                    if ( draftPitchBend != pit ) {
                        pitchBend.add( clock, draftPitchBend );
                    }
                }
            }

            if ( !resetPBS ) {
                return;
            }

            pitchBend.Data = pitBackup.Data;

            // ピッチベンドの最大値を実現するのに必要なPBS
            int requiredPitchbendSensitivity = (int)Math.Ceiling( maxNetPitchBendInCent / 100.0 );
            int pseudoMaxPitchbendSensitivity = 12; // AquesTone2 は最大 12 半音までベンドできる。
            if ( requiredPitchbendSensitivity < pitchBendSensitivity.Minimum ) requiredPitchbendSensitivity = pitchBendSensitivity.Minimum;
            if ( pseudoMaxPitchbendSensitivity < requiredPitchbendSensitivity ) requiredPitchbendSensitivity = pseudoMaxPitchbendSensitivity;

            {
                int i = 0;
                while ( i < pitchBend.size() ) {
                    var clock = pitchBend.getKeyClock( i );
                    if ( startClock <= clock && clock < startClock + vibratoLength ) {
                        pitchBend.removeElementAt( i );
                    } else {
                        ++i;
                    }
                }
            }
            {
                int i = 0;
                while ( i < pitchBendSensitivity.size() ) {
                    var clock = pitchBendSensitivity.getKeyClock( i );
                    if ( startClock <= clock && clock < startClock + vibratoLength ) {
                        pitchBendSensitivity.removeElementAt( i );
                    } else {
                        ++i;
                    }
                }
            }
            if ( pitchBendSensitivity.getValue( startClock ) != requiredPitchbendSensitivity ) {
                pitchBendSensitivity.add( startClock, requiredPitchbendSensitivity );
            }
            pitchBend.add( startClock + vibratoLength, pitAtEnd );
            pitchBendSensitivity.add( startClock + vibratoLength, pbsAtEnd );

            iterator.rewind();
            pitContext.value = 0;
            pbsContext.value = 0;
            int lastPitchBend = pitchBend.getValue( startClock );
            for ( int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock ) {
                double vibratoPitchBendInCent = iterator.next() * 100.0;
                int pit = pitBackup.getValue( clock, pitContext );
                int pbs = pbsBackup.getValue( clock, pbsContext );

                const double pow2_13 = 8192;
                double netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max( maxNetPitchBendInCent, Math.Abs( netPitchBendInCent ) );
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / requiredPitchbendSensitivity);
                if ( draftPitchBend < pitchBend.Minimum ) draftPitchBend = pitchBend.Minimum;
                if ( pitchBend.Maximum < draftPitchBend ) draftPitchBend = pitchBend.Maximum;
                if ( draftPitchBend != lastPitchBend ) {
                    pitchBend.add( clock, draftPitchBend );
                    lastPitchBend = draftPitchBend;
                }
            }
        }
        public void testReflectVibratoPitch()
        {
            var tempoTable           = new TempoVector();
            var pitchBend            = new VsqBPList(CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum());
            var pitchBendSensitivity = new VsqBPList(CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum());

            pitchBend.add(0, 8191);
            pitchBendSensitivity.add(0, 2);

            var generator = new AquesTone2WaveGeneratorStub();
            var item      = new VsqEvent(0, new VsqID());

            item.ID.type                    = VsqIDType.Anote;
            item.ID.VibratoHandle           = new VibratoHandle();
            item.ID.VibratoHandle.StartRate = 0x40;
            item.ID.VibratoHandle.RateBP.clear();
            item.ID.VibratoHandle.StartDepth = 0x40;
            item.ID.VibratoHandle.DepthBP.clear();
            item.ID.setLength(480);
            item.ID.VibratoDelay = 430;
            item.ID.VibratoHandle.setLength(50);
            generator.reflectVibratoPitch(item, pitchBend, pitchBendSensitivity, tempoTable);

            {
                var expectedPit = new Dictionary <int, int> {
                    { 0, 8191 },
                    { 430, 5461 }, { 431, 5467 }, { 432, 5484 }, { 433, 5514 }, { 434, 5555 },
                    { 435, 5608 }, { 436, 5672 }, { 437, 5748 }, { 438, 5835 }, { 439, 5932 },
                    { 440, 6041 }, { 441, 6096 }, { 442, 6151 }, { 443, 6205 }, { 444, 6257 },
                    { 445, 6309 }, { 446, 6360 }, { 447, 6410 }, { 448, 6459 }, { 449, 6507 },
                    { 450, 6553 }, { 451, 6598 }, { 452, 6642 }, { 453, 6684 }, { 454, 6725 },
                    { 455, 6764 }, { 456, 6802 }, { 457, 6838 }, { 458, 6873 }, { 459, 6906 },
                    { 460, 6937 }, { 461, 6967 }, { 462, 6994 }, { 463, 7020 }, { 464, 7044 },
                    { 465, 7066 }, { 466, 7087 }, { 467, 7105 }, { 468, 7121 }, { 469, 7136 },
                    { 470, 7148 }, { 471, 6989 }, { 472, 6826 }, { 473, 6660 }, { 474, 6491 },
                    { 475, 6320 }, { 476, 6149 }, { 477, 5976 }, { 478, 5804 }, { 479, 5632 },
                    { 480, 8191 }
                };
                Assert.AreEqual(expectedPit.Count, pitchBend.size());
                int i = 0;
                foreach (var pitInfo in expectedPit)
                {
                    Assert.AreEqual(pitInfo.Key, pitchBend.getKeyClock(i));
                    Assert.AreEqual(pitInfo.Value, pitchBend.getElementA(i));
                    ++i;
                }
            }

            {
                var expectedPbs = new Dictionary <int, int> {
                    { 0, 2 }, { 430, 3 }, { 480, 2 }
                };
                Assert.AreEqual(expectedPbs.Count, pitchBendSensitivity.size());
                int i = 0;
                foreach (var pbsInfo in expectedPbs)
                {
                    Assert.AreEqual(pbsInfo.Key, pitchBendSensitivity.getKeyClock(i));
                    Assert.AreEqual(pbsInfo.Value, pitchBendSensitivity.getElementA(i));
                    ++i;
                }
            }
        }
 public void reflectVibratoPitch(VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable)
 {
     base.reflectNoteEventPitch(item, pitchBend, pitchBendSensitivity, tempoTable);
 }
        /// <summary>
        /// 音符に付随するピッチベンドの情報を、PIT・PBS カーブに反映する
        /// </summary>
        /// <param name="item">音符</param>
        /// <param name="pitchBend">PIT カーブ</param>
        /// <param name="pitchBendSensitivity">PBS カーブ</param>
        /// <param name="tempoTable">テンポ情報</param>
        protected void reflectNoteEventPitch(VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable)
        {
            if (item.ID.type != VsqIDType.Anote)
            {
                return;
            }

            // AquesTone2 では、note on と同 clock にピッチベンドイベントを送らないと音程が反映されないので、必ずピッチイベントが送られるようにする
            pitchBend.add(item.Clock, pitchBend.getValue(item.Clock));

            if (item.ID.VibratoHandle == null)
            {
                return;
            }

            int startClock    = item.Clock + item.ID.VibratoDelay;
            int vibratoLength = item.ID.Length - item.ID.VibratoDelay;

            var iterator = new VibratoPointIteratorByClock(tempoTable,
                                                           item.ID.VibratoHandle.RateBP, item.ID.VibratoHandle.StartRate,
                                                           item.ID.VibratoHandle.DepthBP, item.ID.VibratoHandle.StartDepth,
                                                           startClock, vibratoLength);
            var pitContext = new ByRef <int>(0);
            var pbsContext = new ByRef <int>(0);

            int pitAtEnd  = pitchBend.getValue(startClock + vibratoLength);
            int pbsAtEnd  = pitchBendSensitivity.getValue(startClock + vibratoLength);
            var pitBackup = (VsqBPList)pitchBend.Clone();
            var pbsBackup = (VsqBPList)pitchBendSensitivity.Clone();

            bool   resetPBS = false;
            double maxNetPitchBendInCent = 0.0;

            for (int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock)
            {
                double       vibratoPitchBendInCent = iterator.next() * 100.0;
                int          pit                = pitchBend.getValue(clock, pitContext);
                int          pbs                = pitchBendSensitivity.getValue(clock, pbsContext);
                const double pow2_13            = 8192;
                double       netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max(maxNetPitchBendInCent, Math.Abs(netPitchBendInCent));
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / pbs);

                if (draftPitchBend < pitchBend.Minimum || pitchBend.Maximum < draftPitchBend)
                {
                    // pbs を変更せずにビブラートによるピッチベンドを反映しようとすると、
                    // pit が範囲を超えてしまう。
                    resetPBS = true;
                }
                else
                {
                    if (draftPitchBend != pit)
                    {
                        pitchBend.add(clock, draftPitchBend);
                    }
                }
            }

            if (!resetPBS)
            {
                return;
            }

            pitchBend.Data = pitBackup.Data;

            // ピッチベンドの最大値を実現するのに必要なPBS
            int requiredPitchbendSensitivity  = (int)Math.Ceiling(maxNetPitchBendInCent / 100.0);
            int pseudoMaxPitchbendSensitivity = 12; // AquesTone2 は最大 12 半音までベンドできる。

            if (requiredPitchbendSensitivity < pitchBendSensitivity.Minimum)
            {
                requiredPitchbendSensitivity = pitchBendSensitivity.Minimum;
            }
            if (pseudoMaxPitchbendSensitivity < requiredPitchbendSensitivity)
            {
                requiredPitchbendSensitivity = pseudoMaxPitchbendSensitivity;
            }

            {
                int i = 0;
                while (i < pitchBend.size())
                {
                    var clock = pitchBend.getKeyClock(i);
                    if (startClock <= clock && clock < startClock + vibratoLength)
                    {
                        pitchBend.removeElementAt(i);
                    }
                    else
                    {
                        ++i;
                    }
                }
            }
            {
                int i = 0;
                while (i < pitchBendSensitivity.size())
                {
                    var clock = pitchBendSensitivity.getKeyClock(i);
                    if (startClock <= clock && clock < startClock + vibratoLength)
                    {
                        pitchBendSensitivity.removeElementAt(i);
                    }
                    else
                    {
                        ++i;
                    }
                }
            }
            if (pitchBendSensitivity.getValue(startClock) != requiredPitchbendSensitivity)
            {
                pitchBendSensitivity.add(startClock, requiredPitchbendSensitivity);
            }
            pitchBend.add(startClock + vibratoLength, pitAtEnd);
            pitchBendSensitivity.add(startClock + vibratoLength, pbsAtEnd);

            iterator.rewind();
            pitContext.value = 0;
            pbsContext.value = 0;
            int lastPitchBend = pitchBend.getValue(startClock);

            for (int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock)
            {
                double vibratoPitchBendInCent = iterator.next() * 100.0;
                int    pit = pitBackup.getValue(clock, pitContext);
                int    pbs = pbsBackup.getValue(clock, pbsContext);

                const double pow2_13            = 8192;
                double       netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max(maxNetPitchBendInCent, Math.Abs(netPitchBendInCent));
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / requiredPitchbendSensitivity);
                if (draftPitchBend < pitchBend.Minimum)
                {
                    draftPitchBend = pitchBend.Minimum;
                }
                if (pitchBend.Maximum < draftPitchBend)
                {
                    draftPitchBend = pitchBend.Maximum;
                }
                if (draftPitchBend != lastPitchBend)
                {
                    pitchBend.add(clock, draftPitchBend);
                    lastPitchBend = draftPitchBend;
                }
            }
        }
Ejemplo n.º 16
0
 public RenderedStatus()
 {
     track  = new VsqTrack(0, 0, 0);
     tempo  = new TempoVector();
     config = new SequenceConfig();
 }
Ejemplo n.º 17
0
        private List <TiedEvent> quantizeTrack(VsqTrack track, TimesigVector timesig_table, TempoVector tempo_table)
        {
            var result = new List <TiedEvent>();

            if (track.MetaText == null)
            {
                return(result);
            }

            track.MetaText.Events.Events
            .AsParallel()
            .ForAll((item) => {
                if (item.ID != null)
                {
                    var start_clock = quantize(item.Clock);
                    var end_clock   = quantize(item.Clock + item.ID.getLength());
                    item.Clock      = start_clock;
                    item.ID.setLength(end_clock - start_clock);
                }
            });

            track.MetaText.Events.Events
            .RemoveAll((item) => {
                if (item.ID == null)
                {
                    return(false);
                }
                return(item.ID.getLength() <= 0);
            });

            int count = track.MetaText.Events.Events.Count;
            int clock = 0;

            for (int i = 0; i < count; ++i)
            {
                var item = track.MetaText.Events.Events[i];
                if (item.ID.type == VsqIDType.Anote)
                {
                    int rest_length = item.Clock - clock;
                    if (rest_length > 0)
                    {
                        result.Add(new TiedEvent(clock, rest_length, timesig_table, tempo_table));
                    }
                    result.Add(new TiedEvent(item, timesig_table, tempo_table));
                    clock = item.Clock + item.ID.getLength();
                }
            }
            return(result);
        }
Ejemplo n.º 18
0
        /// <summary>
        /// このWAVE描画コンテキストが保持しているWAVEデータを、ゲートタイム基準でグラフィクスに描画します。
        /// </summary>
        /// <param name="g">描画に使用するグラフィクスオブジェクト</param>
        /// <param name="pen">描画に使用するペン</param>
        /// <param name="rect">描画範囲</param>
        /// <param name="clock_start">描画開始位置のゲートタイム</param>
        /// <param name="clock_end">描画終了位置のゲートタイム</param>
        /// <param name="tempo_table">ゲートタイムから秒数を調べる際使用するテンポ・テーブル</param>
        /// <param name="pixel_per_clock">ゲートタイムあたりの秒数</param>
        /// <param name="scale_y">Y軸方向の描画スケール。デフォルトは1.0</param>
        /// <param name="auto_maximize">自動で最大化するかどうか</param>
        private void drawCore(
            Graphics2D g,
            Color pen,
            Rectangle rect,
            int clock_start,
            int clock_end,
            TempoVector tempo_table,
            float pixel_per_clock,
            float scale_y,
            bool auto_maximize)
        {
            if (mWave.Length == 0)
            {
                return;
            }
#if DEBUG
            double startedTime = PortUtil.getCurrentTime();
#endif
            mDrawer.setGraphics(g);
            mDrawer.clear();
            double secStart = tempo_table.getSecFromClock(clock_start);
            double secEnd   = tempo_table.getSecFromClock(clock_end);
            int    sStart0  = (int)(secStart * mSampleRate) - 1;
            int    sEnd0    = (int)(secEnd * mSampleRate) + 1;

            int    count   = tempo_table.Count;
            int    sStart  = 0;
            double cStart  = 0.0;
            float  order_y = 1.0f;
            if (auto_maximize)
            {
                order_y = rect.height / 2.0f / 127.0f * mMaxAmplitude / mActualMaxAmplitude;
            }
            else
            {
                order_y = rect.height / 127.0f * scale_y * mMaxAmplitude;
            }
            int  ox       = rect.x;
            int  oy       = rect.height / 2;
            int  last     = mWave[0];
            int  lastx    = ox;
            int  lastYMax = oy - (int)(last * order_y);
            int  lastYMin = lastYMax;
            int  lasty    = lastYMin;
            int  lasty2   = lastYMin;
            bool skipped  = false;
            mDrawer.append(ox, lasty);
            int xmax      = rect.x + rect.width;
            int lastTempo = 500000;
            for (int i = 0; i <= count; i++)
            {
                double time  = 0.0;
                int    tempo = 500000;
                int    cEnd  = 0;
                if (i < count)
                {
                    TempoTableEntry entry = tempo_table[i];
                    time  = entry.Time;
                    tempo = entry.Tempo;
                    cEnd  = entry.Clock;
                }
                else
                {
                    time  = tempo_table.getSecFromClock(clock_end);
                    tempo = tempo_table[i - 1].Tempo;
                    cEnd  = clock_end;
                }
                int sEnd = (int)(time * mSampleRate);

                // sStartサンプルからsThisEndサンプルまでを描画する(必要なら!)
                if (sEnd < sStart0)
                {
                    sStart    = sEnd;
                    cStart    = cEnd;
                    lastTempo = tempo;
                    continue;
                }
                if (sEnd0 < sStart)
                {
                    break;
                }

                //
                int    xoffset       = (int)(cStart * pixel_per_clock) - AppManager.mMainWindowController.getStartToDrawX() + AppManager.keyOffset;
                double sec_per_clock = lastTempo * 1e-6 / 480.0;
                lastTempo = tempo;
                double pixel_per_sample = 1.0 / mSampleRate / sec_per_clock * pixel_per_clock;
                int    j0 = sStart;
                if (j0 < 0)
                {
                    j0 = 0;
                }
                int j1 = sEnd;
                if (mWave.Length < j1)
                {
                    j1 = mWave.Length;
                }

                // 第j0サンプルのデータを画面に描画したときのx座標がいくらになるか?
                int draftStartX = xoffset + (int)((j0 - sStart) * pixel_per_sample);
                if (draftStartX < rect.x)
                {
                    j0 = (int)((rect.x - xoffset) / pixel_per_sample) + sStart;
                }
                // 第j1サンプルのデータを画面に描画した時のx座標がいくらになるか?
                int draftEndX = xoffset + (int)((j1 - sStart) * pixel_per_sample);
                if (rect.x + rect.width < draftEndX)
                {
                    j1 = (int)((rect.x + rect.width - xoffset) / pixel_per_sample) + sStart;
                }

                bool breakRequired = false;
                for (int j = j0; j < j1; j++)
                {
                    int v = mWave[j];
                    if (v == last)
                    {
                        skipped = true;
                        continue;
                    }
                    int x = xoffset + (int)((j - sStart) * pixel_per_sample);
                    if (xmax < x)
                    {
                        breakRequired = true;
                        break;
                    }
                    if (x < rect.x)
                    {
                        continue;
                    }
                    int y = oy - (int)(v * order_y);
                    if (lastx == x)
                    {
                        lastYMax = Math.Max(lastYMax, y);
                        lastYMin = Math.Min(lastYMin, y);
                        continue;
                    }

                    if (skipped)
                    {
                        mDrawer.append(x - 1, lasty);
                        lastx = x - 1;
                    }
                    if (lastYMax == lastYMin)
                    {
                        mDrawer.append(x, y);
                    }
                    else
                    {
                        if (lasty2 != lastYMin)
                        {
                            mDrawer.append(lastx, lastYMin);
                        }
                        mDrawer.append(lastx, lastYMax);
                        if (lastYMax != lasty)
                        {
                            mDrawer.append(lastx, lasty);
                        }
                        mDrawer.append(x, y);
                    }
                    lasty2   = lasty;
                    lastx    = x;
                    lastYMin = y;
                    lastYMax = y;
                    lasty    = y;
                    last     = v;
                    skipped  = false;
                }
                sStart = sEnd;
                cStart = cEnd;
                if (breakRequired)
                {
                    break;
                }
            }

            mDrawer.append(rect.x + rect.width, lasty);
            mDrawer.flush();
        }