Exemplo n.º 1
0
bool ADMRIFFFile::PostReadChunks()
{
  bool success = RIFFFile::PostReadChunks();

  // after reading of chunks, find chna and axml chunks and decode them
  // to create an ADM
  if (success)
  {
    RIFFChunk *chna = GetChunk(chna_ID);
    RIFFChunk *axml = GetChunk(axml_ID);

    // ensure each chunk is valid
    if (adm &&
        chna && chna->GetData() &&
        axml && axml->GetData())
    {
      // decode chunks
      success = adm->Set(chna->GetData(), chna->GetLength(), (const char *)axml->GetData());

#if BBCDEBUG_LEVEL >= 4
      { // dump ADM as text
        std::string str;
        adm->Dump(str);

        BBCDEBUG("%s", str.c_str());
      }

      { // dump ADM as XML
        std::string str;
        adm->GetAxml(str);

        BBCDEBUG("%s", str.c_str());
      }

      BBCDEBUG("Audio objects:");
      std::vector<const ADMObject *> list;
      adm->GetObjects(ADMAudioObject::Type, list);
      uint_t i;
      for (i = 0; i < list.size(); i++)
      {
        BBCDEBUG("%s", list[i]->ToString().c_str());
      }
#endif
    }
    // test for different types of failure
    else if (!adm)
    {
      BBCERROR("Cannot decode ADM, no ADM decoder available");
      success = false;
    }
    else if (!chna || !axml)
    {
      // acceptable failure - chna and/or axml chunk not specified - not an ADM compatible BWF file but open anyway
      BBCDEBUG("Warning: no chna/axml chunks!");

      // if no chna supplied, create default channel mapping using standard definitions
      if (adm && !chna)
      {
        // attempt to find a single audioPackFormat from the standard definitions with the correct number of channels
        std::vector<const ADMObject *> packFormats, streamFormats;
        ADMAudioObject *object = adm->CreateObject("Main");     // create audio object for entire file
        uint_t i;

        // get a list of pack formats - these will be searched for the pack format with the correct number of channels
        adm->GetObjects(ADMAudioPackFormat::Type, packFormats);

        // get a list of stream formats - these will be used to search for track formats and channel formats
        adm->GetObjects(ADMAudioStreamFormat::Type, streamFormats);

        // search all pack formats
        for (i = 0; i < packFormats.size(); i++)
        {
          ADMAudioPackFormat *packFormat;

          if ((packFormat = dynamic_cast<ADMAudioPackFormat *>(const_cast<ADMObject *>(packFormats[i]))) != NULL)
          {
            // get channel format ref list - the size of this dictates the number of channels supported by the pack format
            const std::vector<ADMAudioChannelFormat *>& channelFormatRefs = packFormat->GetChannelFormatRefs();

            // if the pack has the correct number of channels
            if (channelFormatRefs.size() == GetChannels())
            {
              uint_t j;

              BBCDEBUG("Found pack format '%s' ('%s') for %u channels", packFormat->GetName().c_str(), packFormat->GetID().c_str(), GetChannels());

              // add pack format to audio object
              if (object) object->Add(packFormat);

              // for each channel, create a track and link pack format to each
              for (j = 0; j < channelFormatRefs.size(); j++)
              {
                ADMAudioChannelFormat *channelFormat = channelFormatRefs[j];
                ADMAudioTrack *track;
                std::string name;

                // create track
                if ((track = adm->CreateTrack(j)) != NULL)
                {
                  uint_t k;

                  track->Add(packFormat);

                  // find stream format that points to the correct channel format and use that to find the trackFormat
                  for (k = 0; k < streamFormats.size(); k++)
                  {
                    ADMAudioStreamFormat *streamFormat;

                    // stream format points to channel format and track format so look for stream format with the correct channel format ref
                    if (((streamFormat = dynamic_cast<ADMAudioStreamFormat *>(const_cast<ADMObject *>(streamFormats[k]))) != NULL) &&
                        streamFormat->GetChannelFormatRefs().size() &&
                        (streamFormat->GetChannelFormatRefs()[0] == channelFormat) &&   // check for correct channel format ref
                        streamFormat->GetTrackFormatRefs().size())                      // make sure there are some track formats ref'd as well
                    {
                      // get track format ref
                      ADMAudioTrackFormat *trackFormat = streamFormat->GetTrackFormatRefs()[0];

                      BBCDEBUG("Found stream format '%s' ('%s') which refs channel format '%s' ('%s')", streamFormat->GetName().c_str(), streamFormat->GetID().c_str(), channelFormat->GetName().c_str(), channelFormat->GetID().c_str());
                      BBCDEBUG("Found stream format '%s' ('%s') which refs track   format '%s' ('%s')", streamFormat->GetName().c_str(), streamFormat->GetID().c_str(), trackFormat->GetName().c_str(), trackFormat->GetID().c_str());

                      // add track format to track
                      track->Add(trackFormat);
                      break;
                    }
                  }

                  // add track to audio object
                  if (object) object->Add(track);
                }
              }
              break;
            }
          }
        }

        // set default time limits on audio object
        if (object && filesamples)
        {
          BBCDEBUG("Setting duration to %sns", StringFrom(filesamples->GetLengthNS()).c_str());
          object->SetDuration(filesamples->GetLengthNS());
        }
      }

      success = true;
    }
    else {
      // unacceptible failures: empty chna or empty axml chunks
      if (chna && !chna->GetData()) BBCERROR("Cannot decode ADM, chna chunk not available");
      if (axml && !axml->GetData()) BBCERROR("Cannot decode ADM, axml chunk not available");
      success = false;
    }

    // now that the data is dealt with, the chunk data can be deleted
    if (axml) axml->DeleteData();
    if (chna) chna->DeleteData();
  }

  return success;
}