uint32 AudioStream::Read(short* buffer, size_t count) { size_t cnt; size_t toRead = count; // Count is the amount of s16 samples. if (!mSource || !mSource->IsValid()) { mIsPlaying = false; return 0; } if (PaUtil_GetRingBufferReadAvailable(&mRingBuf) < toRead || !mIsPlaying) { memset(buffer, 0, toRead); toRead = PaUtil_GetRingBufferReadAvailable(&mRingBuf); } if (mIsPlaying) { cnt = PaUtil_ReadRingBuffer(&mRingBuf, buffer, toRead); mStreamTime += (double)(cnt/Channels) / (double)mSource->GetRate(); mPlaybackTime = mStreamTime - MixerGetLatency(); }else return 0; return cnt ? cnt : mIsPlaying; }
void ScreenGameplay::RenderObjects(float TimeDelta, bool drawPlayable) { Vec2 mpos = WindowFrame.GetRelativeMPos(); Cursor.SetPosition(mpos); Cursor.AddRotation(CursorRotospeed * TimeDelta); int Beat = MeasureRatio * MySong->MeasureLength; float Fraction = (float(MeasureRatio * MySong->MeasureLength) - Beat); Lifebar.SetScaleX(1.0 - 0.05 * Fraction); // Rendering ahead. if (IsPaused) { Background.Blue = Background.Red = Background.Green = 0.5; } else Background.Blue = Background.Red = Background.Green = 1; Background.Render(); MarkerA.Render(); MarkerB.Render(); if (!EditMode) Lifebar.Render(); if (drawPlayable) { DrawVector(NotesHeld, TimeDelta); DrawVector(AnimateOnly, TimeDelta); if (Measure > 0) { if (NotesInMeasure.size() && // there are measures and Measure - 1 < NotesInMeasure.size() && // the measure is within the range and NotesInMeasure.at(Measure - 1).size() > 0) // there are notes in this measure { DrawVector(NotesInMeasure[Measure - 1], TimeDelta); } } // Render current measure on front of the next! if (Measure + 1 < CurrentDiff->Measures.size()) { if (NotesInMeasure.size() > Measure + 1 && NotesInMeasure.at(Measure + 1).size() > 0) { DrawVector(NotesInMeasure[Measure + 1], TimeDelta); } } if (Measure < CurrentDiff->Measures.size()) { if (NotesInMeasure.size() > Measure && NotesInMeasure.at(Measure).size() > 0) { DrawVector(NotesInMeasure[Measure], TimeDelta); } } } Barline.Render(); if (!EditMode) aJudgment.Render(); // Combo rendering. std::stringstream str; str << Combo; float textX = GetScreenOffset(0.5).x - (str.str().length() * ComboSizeX / 2); MyFont.Render(str.str(), Vec2(textX, 0)); std::stringstream str2; str2 << int32_t(1000000.0 * Evaluation.dpScoreSquare / (Evaluation.totalNotes * (Evaluation.totalNotes + 1))); textX = GetScreenOffset(0.5).x - (str2.str().length() * ComboSizeX / 2); MyFont.Render(str2.str(), Vec2(textX, 720)); /* Lengthy information printing code goes here.*/ std::stringstream info; if (IsAutoplaying) info << "Autoplay"; #ifndef NDEBUG info << "\nSongTime: " << SongTime << "\nPlaybackTime: "; if (Music) info << Music->GetPlayedTime(); else info << "???"; /*info << "\nStreamTime: "; if(Music) info << Music->GetStreamedTime(); else info << "???"; */ info << "\naudioFactor: " << MixerGetFactor(); info << "\nSongDelta: " << SongDelta; info << "\nDevice Latency: " << (int)(MixerGetLatency() * 1000); /* if (Music) info << Music->GetStreamedTime() - Music->GetPlaybackTime(); else info << "???"; */ info << "\nScreenTime: " << GetScreenTime(); info << "\nMeasureRatio: " << MeasureRatio; info << "\nMeasureRatioPerSecond: " << RatioPerSecond; #endif if (TappingMode) info << "\nTapping mode"; if (!FailEnabled) info << "\nFailing Disabled"; #ifdef NDEBUG if (EditMode) #endif info << "\nMeasure: " << Measure; SongInfo.Render(info.str(), Vec2(0, 0)); ReadySign.Render(); Cursor.Render(); }
bool ScreenGameplay7K::ProcessSong() { TimeCompensation = 0; double DesiredDefaultSpeed = Configuration::GetSkinConfigf("DefaultSpeedUnits"); ESpeedType Type = (ESpeedType)(int)Configuration::GetSkinConfigf("DefaultSpeedKind"); double SpeedConstant = 0; // Unless set, assume we're using speed changes int ApplyDriftVirtual = Configuration::GetConfigf("UseAudioCompensationKeysounds"); int ApplyDriftDecoder = Configuration::GetConfigf("UseAudioCompensationNonKeysounded"); if (AudioCompensation && // Apply drift is enabled and: ((ApplyDriftVirtual && CurrentDiff->IsVirtual) || // We want to apply it to a keysounded file and it's virtual (ApplyDriftDecoder && !CurrentDiff->IsVirtual))) // or we want to apply it to a non-keysounded file and it's not virtual TimeCompensation += MixerGetLatency(); TimeCompensation += Configuration::GetConfigf("Offset7K"); if (CurrentDiff->IsVirtual) TimeCompensation += Configuration::GetConfigf("OffsetKeysounded"); else TimeCompensation += Configuration::GetConfigf("OffsetNonKeysounded"); JudgeOffset = Configuration::GetConfigf("JudgeOffsetMS") / 1000; double Drift = TimeCompensation; Log::Logf("TimeCompensation: %f (Latency: %f / Offset: %f)\n", TimeCompensation, MixerGetLatency(), CurrentDiff->Offset); /* * There are three kinds of speed modifiers: * -CMod (Keep speed the same through the song, equal to a constant) * -MMod (Find highest speed and set multiplier to such that the highest speed is equal to a constant) * -First (Find the first speed in the chart, and set multiplier to such that the first speed is equal to a constant) * * The calculations are done ahead, and while SpeedConstant = 0 either MMod or first are assumed * but only if there's a constant specified by the user. * */ // What, you mean we don't have timing data at all? if (CurrentDiff->Timing.size() == 0) { Log::Printf("Error loading chart: No timing data.\n"); return false; } Log::Printf("Processing song... "); if (DesiredDefaultSpeed) { if (Type == SPEEDTYPE_CMOD) // cmod { SpeedMultiplierUser = 1; SpeedConstant = DesiredDefaultSpeed; } CurrentDiff->GetPlayableData(NotesByChannel, BPS, VSpeeds, Warps, Drift, SpeedConstant); if (Type == SPEEDTYPE_MMOD) // mmod { double speed_max = 0; // Find the highest speed for (auto i = VSpeeds.begin(); i != VSpeeds.end(); ++i) { speed_max = std::max(speed_max, abs(i->Value)); } double Ratio = DesiredDefaultSpeed / speed_max; // How much above or below are we from the maximum speed? SpeedMultiplierUser = Ratio; } else if (Type == SPEEDTYPE_FIRST) // We use this case as default. The logic is "Not a CMod, Not a MMod, then use first, the default. { double DesiredMultiplier = DesiredDefaultSpeed / VSpeeds[0].Value; SpeedMultiplierUser = DesiredMultiplier; } else if (Type != SPEEDTYPE_CMOD) // other cases { double bpsd = 4.0 / (BPS[0].Value); double Speed = (MeasureBaseSpacing / bpsd); double DesiredMultiplier = DesiredDefaultSpeed / Speed; SpeedMultiplierUser = DesiredMultiplier; } } else CurrentDiff->GetPlayableData(NotesByChannel, BPS, VSpeeds, Warps, Drift); // Regular processing if (Type != SPEEDTYPE_CMOD) Speeds = CurrentDiff->Data->Speeds; for (auto&& w : Warps) w.Time += Drift; for (auto&& s : Speeds) s.Time += Drift; // Toggle whether we can use our guarantees for optimizations or not at rendering time. HasNegativeScroll = false; for (auto S : Speeds) if (S.Value < 0) HasNegativeScroll = true; for (auto S : VSpeeds) if (S.Value < 0) HasNegativeScroll = true; if (Random) NoteTransform::Randomize(NotesByChannel, CurrentDiff->Channels, CurrentDiff->Data->Turntable); // Load up BGM events std::vector<AutoplaySound> BGMs = CurrentDiff->Data->BGMEvents; if (Configuration::GetConfigf("DisableKeysounds")) NoteTransform::MoveKeysoundsToBGM(CurrentDiff->Channels, NotesByChannel, BGMs); std::sort(BGMs.begin(), BGMs.end()); for (auto &s : BGMs) BGMEvents.push(s); return true; }