@@ -1631,6 +1631,134 @@ class FilteredStream : public AudioStream {
1631
1631
1632
1632
};
1633
1633
1634
+ /* *
1635
+ * @brief AudioStream class that can define a start and (an optional) stop time
1636
+ * Usually it is used to wrap an Audio Sink (e.g. I2SStream), but wrapping an
1637
+ * Audio Source is supported as well. Only wrap classes which represent PCM
1638
+ * data!
1639
+ * @author Phil Schatzmann
1640
+ * @copyright GPLv3
1641
+ */
1642
+ class TimedStream : public AudioStream {
1643
+ public:
1644
+ TimedStream (AudioStream &io, long startSeconds = 0 , long endSeconds = -1 ) {
1645
+ p_stream = &io;
1646
+ p_print = &io;
1647
+ p_info = &io;
1648
+ setStartSecond (startSeconds);
1649
+ setEndSecond (endSeconds);
1650
+ }
1651
+
1652
+ TimedStream (AudioOutput &o, long startSeconds = 0 , long endSeconds = -1 ) {
1653
+ p_print = &o;
1654
+ p_info = &o;
1655
+ setStartSecond (startSeconds);
1656
+ setEndSecond (endSeconds);
1657
+ }
1658
+
1659
+ // / Defines the start time in seconds. The audio before the start time will be
1660
+ // / skipped
1661
+ void setStartSecond (long startSeconds) { start_seconds = startSeconds; }
1662
+
1663
+ // / Defines (an optional) the end time in seconds. After the end time no audio
1664
+ // / is played and available() will return 0
1665
+ void setEndSecond (long endSeconds) { end_seconds = endSeconds; }
1666
+
1667
+ // / Returns true if we are in a valid time range and are still playing sound
1668
+ bool isPlaying () {
1669
+ if (current_bytes < start_bytes) return false ;
1670
+ if (end_bytes > 0 && current_bytes > end_bytes) return false ;
1671
+ return true ;
1672
+ }
1673
+
1674
+ // / Returns true if we are not past the end time;
1675
+ bool isActive () {
1676
+ return (current_bytes < end_bytes && current_bytes > start_bytes);
1677
+ }
1678
+
1679
+ bool begin (AudioInfo info) {
1680
+ setAudioInfo (info);
1681
+ return begin ();
1682
+ }
1683
+
1684
+ bool begin () {
1685
+ calculateByteLimits ();
1686
+ current_bytes = 0 ;
1687
+ return true ;
1688
+ }
1689
+
1690
+ operator bool () { return isActive (); }
1691
+
1692
+ // / Provides only data for the indicated start and end time. Only supported
1693
+ // / for data which does not contain any heder information: so PCM, mp3 should
1694
+ // / work!
1695
+ size_t readBytes (uint8_t *buffer, size_t length) override {
1696
+ // if reading is not supported we stop
1697
+ if (p_stream == nullptr ) return 0 ;
1698
+ // if we are past the end we stop
1699
+ if (!isActive ()) return 0 ;
1700
+ // read the data now
1701
+ size_t result = 0 ;
1702
+ do {
1703
+ result = p_stream->readBytes (buffer, length);
1704
+ current_bytes += length;
1705
+ // ignore data before start time
1706
+ } while (result > 0 && current_bytes < start_bytes);
1707
+ return isPlaying () ? result : 0 ;
1708
+ }
1709
+
1710
+ // / Plays only data for the indiated start and end time
1711
+ size_t write (const uint8_t *buffer, size_t length) override {
1712
+ current_bytes += length;
1713
+ return isPlaying () ? p_print->write (buffer, length) : length;
1714
+ }
1715
+
1716
+ // / Provides the available bytes until the end time has reached
1717
+ int available () override {
1718
+ if (p_stream == nullptr ) return 0 ;
1719
+ return isActive () ? p_stream->available () : 0 ;
1720
+ }
1721
+
1722
+ // / Updates the AudioInfo in the current object and in the source or target
1723
+ void setAudioInfo (AudioInfo info) override {
1724
+ AudioStream::setAudioInfo (info);
1725
+ p_info->setAudioInfo (info);
1726
+ calculateByteLimits ();
1727
+ }
1728
+
1729
+ int availableForWrite () override { return p_print->availableForWrite (); }
1730
+
1731
+ // / Experimental: if used on mp3 you can set the compression ratio e.g. to 11
1732
+ // / which will be used to approximate the time
1733
+ void setCompressionRatio (float ratio) { compression_ratio = ratio; }
1734
+
1735
+ // / Calculates the bytes per second from the AudioInfo
1736
+ int bytesPerSecond () {
1737
+ return info.sample_rate * info.channels * info.bits_per_sample / 8 ;
1738
+ }
1739
+
1740
+ protected:
1741
+ Stream *p_stream = nullptr ;
1742
+ Print *p_print = nullptr ;
1743
+ AudioInfoDependent *p_info = nullptr ;
1744
+ uint32_t start_seconds = 0 ;
1745
+ uint32_t end_seconds = UINT32_MAX;
1746
+ uint32_t start_bytes = 0 ;
1747
+ uint32_t end_bytes = UINT32_MAX;
1748
+ uint32_t current_bytes = 0 ;
1749
+ float compression_ratio = 1.0 ;
1750
+
1751
+ void calculateByteLimits () {
1752
+ int bytes_per_second = bytesPerSecond ();
1753
+ if (bytes_per_second > 0 ) {
1754
+ start_bytes = bytes_per_second * start_seconds / compression_ratio;
1755
+ end_bytes = bytes_per_second * end_seconds / compression_ratio;
1756
+ } else {
1757
+ LOGE (" AudioInfo not defined" );
1758
+ }
1759
+ }
1760
+ };
1761
+
1634
1762
1635
1763
#ifdef USE_TIMER
1636
1764
/* *
0 commit comments