Exemplo n.º 1
1
/*--------------------------------------------------------------------------------*/
bool XMLADMData::ReadXMLFromFile(const std::string& filename, bool finalise)
{
  EnhancedFile fp;
  bool success = false;

  if (fp.fopen(filename.c_str()))
  {
    fp.fseek(0, SEEK_END);
    off_t len = fp.ftell();
    fp.rewind();

    char *buffer;
    if ((buffer = new char[len + 1]) != NULL)
    {
      len = fp.fread(buffer, sizeof(char), len);
      buffer[len] = 0;

      success = SetAxml(buffer, finalise);

      delete[] buffer;
    }
    else BBCERROR("Failed to allocate %s chars for file '%s'", StringFrom(len + 1).c_str(), filename.c_str());

    fp.fclose();
  }
  else BBCERROR("Failed to open file '%s' for reading", filename.c_str());

  return success;
}
Exemplo n.º 2
1
/*--------------------------------------------------------------------------------*/
bool XMLADMData::ReadChnaFromFile(const std::string& filename, bool finalise)
{
  EnhancedFile fp;
  bool success = false;

  if (fp.fopen(filename.c_str()))
  {
    char buffer[1024];
    int l;

    success = true;

    while (success && ((l = fp.readline(buffer, sizeof(buffer) - 1)) != EOF))
    {
      if (l > 0)
      {
        std::vector<std::string> words;

        SplitString(std::string(buffer), words);

        if (words.size() == 4)
        {
          uint_t tracknum;

          if (Evaluate(words[0], tracknum))
          {
            if (tracknum)
            {
              const std::string& trackuid    = words[1];
              const std::string& trackformat = words[2];
              const std::string& packformat  = words[3];
              ADMAudioTrack *track;
              std::string id;

              if ((track = dynamic_cast<ADMAudioTrack *>(Create(ADMAudioTrack::Type, trackuid, ""))) != NULL)
              {
                XMLValue tvalue, pvalue;

                track->SetTrackNum(tracknum - 1);

                tvalue.name = ADMAudioTrackFormat::Reference;
                tvalue.value = trackformat;
                track->AddValue(tvalue);

                pvalue.name = ADMAudioPackFormat::Reference;
                pvalue.value = packformat;
                track->AddValue(pvalue);

                track->SetValues();

                BBCDEBUG2(("Track %u: Index %u UID '%s' TrackFormatRef '%s' PackFormatRef '%s'",
                        (uint_t)tracklist.size(),
                        track->GetTrackNum() + 1,
                        track->GetID().c_str(),
                        tvalue.value.c_str(),
                        pvalue.value.c_str()));
              }
              else
              {
                BBCERROR("Failed to create AudioTrack for UID %u", tracknum);
                success = false;
              }
            }
          }
          else
          {
            BBCERROR("CHNA line '%s' word 1 ('%s') should be a track number", buffer, words[0].c_str());
            success = false;
          }
        }
        else
        {
          BBCERROR("CHNA line '%s' requires 4 words", buffer);
          success = false;
        }
      }
    }

    fp.fclose();

    if (success && finalise) Finalise();
  }

  return success;
}
Exemplo n.º 3
0
/*--------------------------------------------------------------------------------*/
bool XMLADMData::SetChna(const uint8_t *data, uint64_t len)
{
  const CHNA_CHUNK& chna = *(const CHNA_CHUNK *)data;
  uint_t maxuids = (uint_t)((len - sizeof(CHNA_CHUNK)) / sizeof(chna.UIDs[0]));   // calculate maximum number of UIDs given chunk length
  std::string terminator;
  bool success = true;

  // create string with a single 0 byte in it to detect terminators
  terminator.push_back(0);

  if (maxuids < chna.UIDCount) BBCERROR("Warning: chna specifies %u UIDs but chunk has only length for %u", (uint_t)chna.UIDCount, maxuids);

  uint16_t i;
  for (i = 0; (i < chna.UIDCount) && (i < maxuids); i++)
  {
    // only handle non-zero track numbers
    if (chna.UIDs[i].TrackNum)
    {
      ADMAudioTrack *track;
      std::string id;

      id.assign(chna.UIDs[i].UID, sizeof(chna.UIDs[i].UID));
      id = id.substr(0, id.find(terminator));

      // delete any existing ADMAudioTracks of the same ID
      if ((track = dynamic_cast<ADMAudioTrack *>(Create(ADMAudioTrack::Type, id, "", true))) != NULL)
      {
        XMLValue tvalue, pvalue;

        track->SetTrackNum(chna.UIDs[i].TrackNum - 1);

        tvalue.name = ADMAudioTrackFormat::Reference;
        tvalue.value.assign(chna.UIDs[i].TrackRef, sizeof(chna.UIDs[i].TrackRef));
        // trim any zero bytes off the end of the string
        tvalue.value = tvalue.value.substr(0, tvalue.value.find(terminator));
        track->AddValue(tvalue);

        pvalue.name = ADMAudioPackFormat::Reference;
        pvalue.value.assign(chna.UIDs[i].PackRef, sizeof(chna.UIDs[i].PackRef));
        // trim any zero bytes off the end of the string
        pvalue.value = pvalue.value.substr(0, pvalue.value.find(terminator));
        track->AddValue(pvalue);

        track->SetValues();

        BBCDEBUG2(("Track %u/%u: Index %u UID '%s' TrackFormatRef '%s' PackFormatRef '%s'",
                i, (uint_t)tracklist.size(),
                track->GetTrackNum() + 1,
                track->GetID().c_str(),
                tvalue.value.c_str(),
                pvalue.value.c_str()));
      }
      else BBCERROR("Failed to create AudioTrack for UID %u", i);
    }
  }

  SortTracks();

  return success;
}
Exemplo n.º 4
0
/*--------------------------------------------------------------------------------*/
bool ADMRIFFFile::CreateExtraChunks()
{
  bool success = true;

  if (adm)
  {
    RIFFChunk *chunk;
    uint64_t  chnalen;
    uint8_t   *chna;
    uint_t i, nchannels = GetChannels();

    success = true;

    for (i = 0; i < nchannels; i++)
    {
      ADMAudioTrack *track;

      // create chna track data
      if ((track = adm->CreateTrack(i)) != NULL)
      {
        track->SetSampleRate(GetSampleRate());
        track->SetBitDepth(GetBitsPerSample());
      }
    }

    if (!admfile.empty())
    {
      // create ADM structure (content and objects from file)
      if (adm->CreateFromFile(admfile.c_str()))
      {
        // can prepare cursors now since all objects have been created
        PrepareCursors();
      }
      else
      {
        BBCERROR("Unable to create ADM structure from '%s'", admfile.c_str());
        success = false;
      }
    }

    // get ADM object to create chna chunk
    if ((chna = adm->GetChna(chnalen)) != NULL)
    {
      // and add it to the RIFF file
      if ((chunk = AddChunk(chna_ID)) != NULL)
      {
        success &= chunk->CreateChunkData(chna, chnalen);
      }
      else BBCERROR("Failed to add chna chunk");

      // don't need the raw data any more
      delete[] chna;
    }
    else BBCERROR("No chna data available");

    success &= (AddChunk(axml_ID) != NULL);
  }

  return success;
}
Exemplo n.º 5
0
/*--------------------------------------------------------------------------------*/
bool ADMRIFFFile::Open(const char *filename, const std::string& standarddefinitionsfile)
{
  bool success = false;

  if ((adm = XMLADMData::CreateADM(standarddefinitionsfile)) != NULL)
  {
    success = RIFFFile::Open(filename);
  }
  else BBCERROR("No providers for ADM XML decoding!");

  return success;
}
Exemplo n.º 6
0
/*--------------------------------------------------------------------------------*/
bool UDPSocket::send(const void *data, uint_t bytes, const struct sockaddr *to)
{
  bool success = false;

  if (socket >= 0)
  {
    if (to) success = (::sendto(socket, (const char *)data, bytes, 0, to, sizeof(*to)) >= 0);
    else    success = (::send(socket, (const char *)data, bytes, 0) >= 0);
    if (!success) BBCERROR("Failed to send %u bytes to socket (%s)", bytes, strerror(errno));
  }

  return success;
}
Exemplo n.º 7
0
/*--------------------------------------------------------------------------------*/
bool ADMRIFFFile::CreateADM(const std::string& standarddefinitionsfile)
{
  bool success = false;

  if (!adm)
  {
    if ((adm = XMLADMData::CreateADM(standarddefinitionsfile)) != NULL)
    {
      success = true;
    }
    else BBCERROR("No providers for ADM XML decoding!");
  }

  return success;
}
Exemplo n.º 8
0
/*--------------------------------------------------------------------------------*/
bool XMLADMData::LoadStandardDefinitions(const std::string& filename)
{
  static const char *paths[] =
  {
    "{env:BBCATFILEIOSHAREDIR}",    // BBCATFILEIOSHAREDIR environment variable
    "{fileiosharedir}",             // system parameter 'fileiosharedir'
    "{sharedir}/bbcat-fileio",      // use system parameter
    "share",                        // relative location
  };
  std::string filename2 = filename;
  bool success = false;

  // try various sources for the filename if it is empty
  if (filename2.empty()) filename2 = SystemParameters::Get().Substitute("{env:BBCATSTANDARDDEFINITIONSFILE}");
  if (filename2.empty()) SystemParameters::Get().GetSubstituted("standarddefinitionsfile", filename2);
  // use default name if none above work
  if (filename2.empty()) filename2 = "standarddefinitions.xml";

  BBCDEBUG3(("Using '%s' as filename for standard definitions file", filename2.c_str()));
  
  // delete any existing objects
  Delete();

  if (!(filename2 = FindFile(filename2, paths, NUMBEROF(paths))).empty())
  {
    BBCDEBUG("Found standard definitions file '%s' as '%s'", filename.c_str(), filename2.c_str());

    if (ReadXMLFromFile(filename2.c_str()))
    {
      ADMOBJECTS_IT it;

      // set standard def flag on all loaded objects
      for (it = admobjects.begin(); it != admobjects.end(); ++it)
      {
        it->second->SetStandardDefinition();
      }

      success = true;
    }
    else BBCERROR("Failed to read standard definitions file '%s'", filename2.c_str());
  }
  else BBCDEBUG1(("Standard definitions file '%s' doesn't exist", filename2.c_str()));

  return success;
}
Exemplo n.º 9
0
/*--------------------------------------------------------------------------------*/
sint_t UDPSocket::recv(void *data, uint_t maxbytes, struct sockaddr *from)
{
  sint_t bytes = -1;

  if (socket >= 0)
  {
    // recv() with MSG_PEEK doesn't work propely unless *some* buffer is supplied so this buffer is just used
    // as a dumping point for the data
    // it *still* means recv()  is thread-safe because we don't care about the data
    static char _staticbuf[16384];
    socklen_t len = sizeof(struct sockaddr);
    
    if (from) bytes = ::recvfrom(socket, data ? (char *)data : _staticbuf, data ? maxbytes : sizeof(_staticbuf), data ? 0 : MSG_PEEK, from, &len);
    else      bytes = ::recv(socket, data ? (char *)data : _staticbuf, data ? maxbytes : sizeof(_staticbuf), data ? 0 : MSG_PEEK);

    if (bytes < 0) BBCERROR("Failed to receive %u from socket (%s)", maxbytes, strerror(errno));
  }

  return bytes;
}
Exemplo n.º 10
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;
}
Exemplo n.º 11
0
/*--------------------------------------------------------------------------------*/
void ADMRIFFFile::Close(bool abortwrite)
{
  EnhancedFile *file = fileref;
  uint_t i;

  if (file && adm && writing && !abortwrite)
  {
    RIFFChunk *chunk;
    uint64_t  endtime = filesamples ? filesamples->GetAbsolutePositionNS() : 0;
    uint64_t  chnalen;
    uint8_t   *chna;

    BBCDEBUG1(("Finalising ADM for '%s'...", file->getfilename().c_str()));

    BBCDEBUG1(("Finishing all blockformats"));

    // complete BlockFormats on all channels
    for (i = 0; i < cursors.size(); i++)
    {
      cursors[i]->Seek(endtime);
      cursors[i]->EndChanges();
    }

    // finalise ADM
    adm->Finalise();

    // update audio object time limits
    adm->UpdateAudioObjectLimits();

    BBCDEBUG1(("Creating ADM RIFF chunks"));

    // get ADM object to create chna chunk
    if ((chna = adm->GetChna(chnalen)) != NULL)
    {
      // and add it to the RIFF file
      if ((chunk = GetChunk(chna_ID)) != NULL)
      {
        if (!chunk->UpdateChunkData(chna, chnalen)) BBCERROR("Failed to update chna data (possibly length has changed)");
      }
      else BBCERROR("Failed to add chna chunk");

      // don't need the raw data any more
      delete[] chna;
    }
    else BBCERROR("No chna data available");

    // add axml chunk
    if ((chunk = GetChunk(axml_ID)) != NULL)
    {
      // first, calculate size of ADM (to save lots of memory allocations)
      uint64_t admlen = adm->GetAxmlBuffer(NULL, 0);

      BBCDEBUG1(("ADM size is %s bytes", StringFrom(admlen).c_str()));
      
      // allocate chunk data
      if (chunk->CreateChunkData(admlen))
      {
        // finally, generate XML into buffer
        uint64_t admlen1 = adm->GetAxmlBuffer(chunk->GetDataWritable(), admlen);
        if (admlen1 != admlen) BBCERROR("Generating axml data for real resulted in different size (%s vs %s)", StringFrom(admlen1).c_str(), StringFrom(admlen).c_str());
      }
      else BBCERROR("Failed to allocate %s bytes for axml data", StringFrom(admlen).c_str());
    }
    else BBCERROR("Failed to add axml chunk");
  }

  // write chunks and close file
  RIFFFile::Close(abortwrite);

  for (i = 0; i < cursors.size(); i++)
  {
    delete cursors[i];
  }
  cursors.clear();

  if (adm)
  {
    adm->Delete();
    delete adm;
    adm = NULL;
  }
}
Exemplo n.º 12
0
/*--------------------------------------------------------------------------------*/
bool AudioObjectParameters::FromJSON(const JSONValue& obj, bool reset)
{
  Position     pval;
  ParameterSet sval;
  std::string  str;
  double       dval;
  sint64_t     i64val;
  float        fval;
  uint_t       uval;
  int          ival;
  bool         bval;
  bool         success = true;
    
  success &= SetFromJSON<>(Parameter_channel, values.channel, ival, obj, reset, 0U, &Limit0u);
  success &= SetFromJSON<>(Parameter_duration, values.duration, i64val, obj, reset, (uint64_t)0);
  success &= SetFromJSON<>(Parameter_cartesian, values.cartesian, bval, obj, reset);
  success &= SetFromJSON<>(Parameter_position, position, pval, obj, reset);
  success &= SetFromJSON<>(Parameter_minposition, &minposition, pval, obj, reset);
  success &= SetFromJSON<>(Parameter_maxposition, &maxposition, pval, obj, reset);
  success &= SetFromJSON<>(Parameter_gain, values.gain, dval, obj, reset, 1.0);
  success &= SetFromJSON<>(Parameter_width, values.width, fval, obj, reset, 0.f, &Limit0f);
  success &= SetFromJSON<>(Parameter_depth, values.depth, fval, obj, reset, 0.f, &Limit0f);
  success &= SetFromJSON<>(Parameter_height, values.height, fval, obj, reset, 0.f, &Limit0f);
  success &= SetFromJSON<>(Parameter_divergencebalance, values.divergencebalance, fval, obj, reset, 0.f, &Limit0to1f);
  success &= SetFromJSON<>(Parameter_divergenceazimuth, values.divergenceazimuth, fval, obj, reset, 0.f, &Limit0f);
  success &= SetFromJSON<>(Parameter_diffuseness, values.diffuseness, fval, obj, reset, 0.f, &Limit0to1f);
  success &= SetFromJSON<>(Parameter_delay, values.delay, fval, obj, reset, 0.f, &Limit0f);
  success &= SetFromJSON<>(Parameter_objectimportance, values.objectimportance, uval, obj, reset, (uint8_t)GetObjectImportanceDefault(), &LimitImportance);
  success &= SetFromJSON<>(Parameter_channelimportance, values.channelimportance, uval, obj, reset, (uint8_t)GetChannelImportanceDefault(), &LimitImportance);
  success &= SetFromJSON<>(Parameter_dialogue, values.dialogue, uval, obj, reset, (uint8_t)GetDialogueDefault(), &LimitDialogue);
  success &= SetFromJSON<>(Parameter_channellock, values.channellock, bval, obj, reset);
  success &= SetFromJSON<>(Parameter_channellockmaxdistance, values.channellockmaxdistance, fval, obj, reset, 0.f, &LimitMaxDistance);
  success &= SetFromJSON<>(Parameter_interact, values.interact, bval, obj, reset, (uint8_t)GetInteractDefault());
  success &= SetFromJSON<>(Parameter_interpolate, values.interpolate, bval, obj, reset, (uint8_t)1);
  success &= SetFromJSON<>(Parameter_interpolationtime, values.interpolationtime, i64val, obj, reset, (uint64_t)0);
  success &= SetFromJSON<>(Parameter_onscreen, values.onscreen, bval, obj, reset);
  success &= SetFromJSON<>(Parameter_disableducking, values.disableducking, bval, obj, reset, (uint8_t)GetDisableDuckingDefault());
  success &= SetFromJSON<>(Parameter_othervalues, othervalues, sval, obj, reset);
  
  // support legacy 'importance' parameter name for channel importance
  if (obj.isObject() && obj.isMember("importance"))
  {
    // read value from JSON into intermediate value
    if (json::FromJSON(obj["importance"], uval))
    {
      // use intermediate value to set parameter
      SetParameter<>(Parameter_channelimportance, values.channelimportance, uval, &LimitImportance);
    }
    else success = false;
  }

  // delete existing list of excluded zones
  if (excludedZones)
  {
    delete excludedZones;
    excludedZones = NULL;
  }

  {
    // try and find zoneExclusion item in object
    if (obj.isObject() && obj.isMember("excludedzones") && obj["excludedzones"].isArray())
    {
      const JSONValue& zones = obj["excludedzones"];

      for (uint_t i = 0; i < zones.size(); i++)
      {
        if (zones[i].isObject())
        {
          const JSONValue& obj = zones[i];
          std::string name;
          float minx, miny, minz, maxx, maxy, maxz;

          // extract name and limits of excluded zone
          if (json::FromJSON(obj, "name", name) &&
              json::FromJSON(obj, "minx", minx) &&
              json::FromJSON(obj, "miny", miny) &&
              json::FromJSON(obj, "minz", minz) &&
              json::FromJSON(obj, "maxx", maxx) &&
              json::FromJSON(obj, "maxy", maxy) &&
              json::FromJSON(obj, "maxz", maxz))
          {
            AddExcludedZone(name, minx, miny, minz, maxx, maxy, maxz);
          }
          else
          {
            BBCERROR("Unable to extract excluded zones from JSON '%s'", json::ToJSONString(obj).c_str());
            success = false;
          }
        }
      }
    }
  }
  
  return success;
}