File: AudioGraphTask.cpp

package info (click to toggle)
audacity 3.7.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 125,252 kB
  • sloc: cpp: 358,238; ansic: 75,458; lisp: 7,761; sh: 3,410; python: 1,503; xml: 1,385; perl: 854; makefile: 122
file content (98 lines) | stat: -rw-r--r-- 2,927 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**********************************************************************

  Audacity: A Digital Audio Editor

  @file AudioGraphTask.cpp

  Dominic Mazzoni
  Vaughan Johnson
  Martyn Shaw

  Paul Licameli split from PerTrackEffect.cpp

**********************************************************************/
#include "AudioGraphTask.h"
#include "AudioGraphBuffers.h"
#include "AudioGraphSink.h"
#include "AudioGraphSource.h"
#include "SampleCount.h"
#include <cassert>

AudioGraph::Task::Task(Source &source, Buffers &buffers, Sink &sink)
   : mSource{ source }, mBuffers{ buffers }, mSink{ sink }
{
   assert(source.AcceptsBlockSize(buffers.BlockSize()));
   assert(source.AcceptsBuffers(buffers));
   assert(sink.AcceptsBuffers(buffers));
}

bool AudioGraph::Task::RunLoop()
{
   // Satisfy invariant initially
   mBuffers.Rewind();
   Status status{};
   do {
      assert(mBuffers.Remaining() >= mBuffers.BlockSize());
      status = RunOnce();
   } while (status == Status::More);
   return status == Status::Done;
}

auto AudioGraph::Task::RunOnce() -> Status
{
   const auto blockSize = mBuffers.BlockSize();
   assert(mBuffers.Remaining() >= blockSize); // pre

#ifndef NDEBUG
   // Variable used only for a loop termination sanity check
   std::optional<sampleCount> oldRemaining;
   if (mRanOnce)
      oldRemaining.emplace(mSource.Remaining());
   // else Remaining() may not be meaningful
#endif
 
   if (auto oCurBlockSize = mSource.Acquire(mBuffers, blockSize)) {
      const auto curBlockSize = *oCurBlockSize;
#ifndef NDEBUG
      mRanOnce = true;
      const auto remaining = mSource.Remaining();
      // Assert a post of Acquire which is part of proof of termination
      assert(!mSource.Terminates() || !oldRemaining ||
         *oldRemaining == remaining);
      oldRemaining.emplace(remaining);
      // Assert another post that guarantees progress (even if not terminating)
      assert(blockSize == 0 || remaining == 0 || curBlockSize > 0);
#endif
      if (curBlockSize == 0)
         // post (same as pre) obviously preserved
         return Status::Done;

      // post of source.Acquire() satisfies pre of sink.Release()
      assert(curBlockSize <= blockSize);
      if (!mSink.Release(mBuffers, curBlockSize))
         return Status::Fail;
   
      // This may break the post
      mBuffers.Advance(curBlockSize);

      // posts of source.Acquire() and source.Release()
      // give termination guarantee
      assert(mSource.Remaining() == 0 || curBlockSize > 0);
      if (!mSource.Release())
         return Status::Fail;
#ifndef NDEBUG
      // Assert a post of Release
      assert(!mSource.Terminates() ||
         mSource.Remaining() == remaining - curBlockSize);
#endif

      // Reestablish the post
      if (!mSink.Acquire(mBuffers))
         return Status::Fail;
      assert(mBuffers.Remaining() >= blockSize);

      return Status::More;
   }
   else
      return Status::Fail;
}