1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System.IO;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Exceptions;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.Sound
15 {
16     public class PCMDecoder
17     {
PCMDecoder(uint sampleWidthBits, uint samplingRateHz, uint numberOfChannels, bool concatenatedChannels, IPeripheral loggingParent = null)18         public PCMDecoder(uint sampleWidthBits, uint samplingRateHz, uint numberOfChannels, bool concatenatedChannels, IPeripheral loggingParent = null)
19         {
20             if(concatenatedChannels)
21             {
22                throw new ConstructionException("Concatenated channels are currently not supported");
23             }
24 
25             if(sampleWidthBits != 8u && sampleWidthBits != 16u && sampleWidthBits != 24u && sampleWidthBits != 32u)
26             {
27                throw new ConstructionException($"Not supported sample width: {0}. Only 8/16/24/32 bits are currently supported.");
28             }
29 
30             samples = new Queue<uint>();
31 
32             this.sampleWidthBits = sampleWidthBits;
33             this.numberOfChannels = numberOfChannels;
34             this.samplingRateHz = samplingRateHz;
35 
36             this.loggingParent = loggingParent;
37         }
38 
Reset()39         public void Reset()
40         {
41             lock(samples)
42             {
43                 samples.Clear();
44             }
45         }
46 
LoadFile(ReadFilePath path)47         public void LoadFile(ReadFilePath path)
48         {
49             var sampleSize = (int)(sampleWidthBits / 8);
50 
51             lock(samples)
52             {
53                 using(var br = new BinaryReader(File.Open(path, FileMode.Open)))
54                 {
55                     while(true)
56                     {
57                         var bytes = br.ReadBytes(sampleSize);
58                         if(bytes.Length == 0)
59                         {
60                             break;
61                         }
62 
63                         var sample = BitHelper.ToUInt32(bytes, 0, bytes.Length, false);
64                         samples.Enqueue(sample);
65                     }
66                 }
67             }
68         }
69 
LoadSample(uint sample)70         public void LoadSample(uint sample)
71         {
72             var croppedSample = BitHelper.GetMaskedValue(sample, 0, (int)sampleWidthBits);
73             if(croppedSample != sample)
74             {
75                 loggingParent?.Log(LogLevel.Warning, "Cropping the sample from 0x{0:X} to 0x{1:X} to fit to the sample width ({2} bits)", sample, croppedSample, sampleWidthBits);
76             }
77 
78             lock(samples)
79             {
80                 samples.Enqueue(croppedSample);
81             }
82         }
83 
GetSingleSample()84         public uint GetSingleSample()
85         {
86             return samples.TryDequeue(out var sample) ? sample : 0u;
87         }
88 
GetSamplesByCount(uint samplesCountPerChannel)89         public IEnumerable<uint> GetSamplesByCount(uint samplesCountPerChannel)
90         {
91             lock(samples)
92             {
93                 return samples.DequeueRange((int)(samplesCountPerChannel * numberOfChannels));
94             }
95         }
96 
GetSamplesByTime(uint ms)97         public IEnumerable<uint> GetSamplesByTime(uint ms)
98         {
99             lock(samples)
100             {
101                 var samplesPerChannel = ms * (samplingRateHz / 1000);
102                 return GetSamplesByCount(samplesPerChannel);
103             }
104         }
105 
106         private readonly uint samplingRateHz;
107         private readonly uint numberOfChannels;
108         private readonly uint sampleWidthBits;
109 
110         private readonly IPeripheral loggingParent;
111         private readonly Queue<uint> samples;
112     }
113 }
114