• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 3-Clause Clear License
5  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6  * License was not distributed with this source code in the LICENSE file, you
7  * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8  * Alliance for Open Media Patent License 1.0 was not distributed with this
9  * source code in the PATENTS file, you can obtain it at
10  * www.aomedia.org/license/patent.
11  */
12 
13 #include "iamf/cli/wav_reader.h"
14 
15 #include <cerrno>
16 #include <cstddef>
17 #include <cstdint>
18 #include <cstdio>
19 #include <cstring>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/log/log.h"
25 #include "absl/status/status.h"
26 #include "absl/status/statusor.h"
27 #include "absl/strings/str_cat.h"
28 #include "src/dsp/read_wav_file.h"
29 #include "src/dsp/read_wav_info.h"
30 
31 namespace iamf_tools {
32 
33 namespace {
34 const int kAudioToTactileFailure = 0;
35 }
36 
CreateFromFile(const std::string & wav_filename,const size_t num_samples_per_frame)37 absl::StatusOr<WavReader> WavReader::CreateFromFile(
38     const std::string& wav_filename, const size_t num_samples_per_frame) {
39   if (num_samples_per_frame == 0) {
40     return absl::InvalidArgumentError("num_samples_per_frame must be > 0");
41   }
42   LOG(INFO) << "Reading \"" << wav_filename << "\"";
43   FILE* file = std::fopen(wav_filename.c_str(), "rb");
44   if (file == nullptr) {
45     return absl::FailedPreconditionError(
46         absl::StrCat("Failed to open file: \"", wav_filename,
47                      "\" with error: ", std::strerror(errno), "."));
48   }
49 
50   ReadWavInfo info;
51   if (ReadWavHeader(file, &info) == kAudioToTactileFailure) {
52     return absl::FailedPreconditionError(
53         absl::StrCat("Failed to read header of file: \"", wav_filename,
54                      "\". Maybe it is not a valid RIFF WAV."));
55   }
56 
57   // Overwrite `info_.destination_alignment_bytes` to 4 to always store results
58   // in 4 bytes (32 bits), so we can handle 16-, 24-, and 32-bit PCMs.
59   info.destination_alignment_bytes = 4;
60 
61   // Log the header info.
62   LOG(INFO) << "WAV header info:";
63   LOG(INFO) << "  num_channels= " << info.num_channels;
64   LOG(INFO) << "  sample_rate_hz= " << info.sample_rate_hz;
65   LOG(INFO) << "  remaining_samples= " << info.remaining_samples;
66   LOG(INFO) << "  bit_depth= " << info.bit_depth;
67   LOG(INFO) << "  destination_alignment_bytes= "
68             << info.destination_alignment_bytes;
69   LOG(INFO) << "  encoding= " << info.encoding;
70   LOG(INFO) << "  sample_format= " << info.sample_format;
71 
72   return WavReader(num_samples_per_frame, file, info);
73 }
74 
WavReader(const size_t num_samples_per_frame,FILE * file,const ReadWavInfo & info)75 WavReader::WavReader(const size_t num_samples_per_frame, FILE* file,
76                      const ReadWavInfo& info)
77     : buffers_(num_samples_per_frame,
78                std::vector<int32_t>(info.num_channels, 0)),
79       num_samples_per_frame_(num_samples_per_frame),
80       file_(file),
81       info_(info) {}
82 
WavReader(WavReader && original)83 WavReader::WavReader(WavReader&& original)
84     : buffers_(std::move(original.buffers_)),
85       num_samples_per_frame_(original.num_samples_per_frame_),
86       file_(original.file_),
87       info_(original.info_) {
88   // Invalidate the file pointer on the original copy to prevent it from being
89   // closed on destruction.
90   original.file_ = nullptr;
91 }
92 
~WavReader()93 WavReader::~WavReader() {
94   if (file_ != nullptr) {
95     std::fclose(file_);
96   }
97 }
98 
ReadFrame()99 size_t WavReader::ReadFrame() {
100   size_t samples_read = 0;
101   for (int i = 0; i < buffers_.size(); i++) {
102     samples_read +=
103         ReadWavSamples(file_, &info_, buffers_[i].data(), buffers_[i].size());
104   }
105   return samples_read;
106 }
107 
108 }  // namespace iamf_tools
109