OpenDAFF C++ API  v1.7
Directional Audio File Format
DAFFReaderImpl.cpp
Go to the documentation of this file.
1 #include "DAFFReaderImpl.h"
2 
3 #include "DAFFHeader.h"
4 #include "DAFFMetadataImpl.h"
5 #include <DAFFUtils.h>
6 
7 #include "Utils.h"
8 
9 #include <cassert>
10 #include <cmath>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <sstream>
14 
15 // Disable MSVC security warning for unsafe fopen
16 #ifdef _MSC_VER
17 #pragma warning(disable: 4996)
18 #endif // _MSC_VER
19 
20 
22  : m_bDAFFObjectValid( false )
23  , m_bDAFFObjectFromFileValid( false )
24  , m_file( NULL ),
25  m_pFileBlockTable( NULL ),
26  m_pMainHeader( NULL ),
27  m_pContentHeader( NULL ),
28  m_pRecordDescriptorBlock( NULL ),
29  m_pDataBlock( NULL ),
30  m_bOverallPeakInitialized( false ),
31  m_fOverallPeak( 0.0 )
32 {
33  m_pEmptyMetadata = new DAFFMetadataImpl;
34 }
35 
37 {
38  tidyup();
39  delete m_pEmptyMetadata;
40 }
41 
43 {
44  return ( m_bDAFFObjectFromFileValid && m_bDAFFObjectValid );
45 }
46 
48 {
49  return m_bDAFFObjectValid;
50 }
51 
52 int DAFFReaderImpl::deserialize( char* pDAFFDataBuffer )
53 {
54  if( m_bDAFFObjectValid )
55  return DAFF_MODAL_ERROR;
56 
57  // File header
58  char* pFileHeaderBuffer = ( char* ) &m_fileHeader;
59  for( size_t i = 0; i < sizeof( DAFFFileHeader ); i++ )
60  pFileHeaderBuffer[ i ] = pDAFFDataBuffer[ i ];
61 
62  int ec = loadFileHeader();
63  if( ec != DAFF_NO_ERROR )
64  return ec;
65 
66  size_t nBufferReadPos = sizeof( DAFFFileHeader );
67 
68  // File block table
69  size_t nFileBlockTableSize = m_fileHeader.iNumFileBlocks * sizeof( DAFFFileBlockEntry );
70  m_pFileBlockTable = ( DAFFFileBlockEntry* ) DAFF::malloc_aligned16( nFileBlockTableSize );
71  char* pFileBlockTableBuffer = ( char* ) m_pFileBlockTable;
72 
73  for( size_t i = 0; i < nFileBlockTableSize; i++ )
74  pFileBlockTableBuffer[ i ] = pDAFFDataBuffer[ i + nBufferReadPos ];
75 
76  ec = loadFileBlockTable();
77  if( ec != DAFF_NO_ERROR )
78  {
79  DAFF::free_aligned16( m_pFileBlockTable );
80  tidyup();
81  return ec;
82  }
83 
84  nBufferReadPos += nFileBlockTableSize;
85 
86  // Main header
87  DAFFFileBlockEntry* pfbMainHeader;
88  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_MAIN_HEADER_ID, pfbMainHeader ) != 1 )
89  {
90  tidyup();
91  return DAFF_FILE_INVALID;
92  }
93 
94  m_pMainHeader = ( DAFFMainHeader* ) DAFF::malloc_aligned16( sizeof( DAFFMainHeader ) );
95  char* pMainHeaderBuffer = ( char* ) m_pMainHeader;
96 
97  for( size_t i = 0; i < sizeof( DAFFMainHeader ); i++ )
98  pMainHeaderBuffer[ i ] = pDAFFDataBuffer[ i + pfbMainHeader->ui64Offset ];
99 
100  ec = loadMainHeader();
101  if( ec != DAFF_NO_ERROR )
102  {
103  DAFF::free_aligned16( m_pMainHeader );
104  tidyup();
105  return ec;
106  }
107 
108  // Content header
109  DAFFFileBlockEntry* pfbContentHeader;
110  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_CONTENT_HEADER_ID, pfbContentHeader ) != 1 )
111  {
112  tidyup();
113  return DAFF_FILE_CORRUPTED;
114  }
115 
116  m_pContentHeader = ( char* ) DAFF::malloc_aligned16( ( size_t ) pfbContentHeader->ui64Size );
117  char* pContentHeaderBuffer = ( char* ) m_pContentHeader;
118 
119  for( size_t i = 0; i < ( size_t ) pfbContentHeader->ui64Size; i++ )
120  pContentHeaderBuffer[ i ] = pDAFFDataBuffer[ i + pfbContentHeader->ui64Offset ];
121 
122  ec = loadContentHeader();
123  if( ec != DAFF_NO_ERROR )
124  {
125  DAFF::free_aligned16( m_pContentHeader );
126  tidyup();
127  return ec;
128  }
129 
130  // Record descriptor
131  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_RECORD_DESC_ID, m_pRecordDescriptorTable ) != 1 )
132  {
133  tidyup();
134  return DAFF_FILE_CORRUPTED;
135  }
136 
137  m_pRecordDescriptorBlock = ( char* ) DAFF::malloc_aligned16( ( size_t ) m_pRecordDescriptorTable->ui64Size );
138  char* pRecordDescriptorBuffer = ( char* ) m_pRecordDescriptorBlock;
139 
140  for( size_t i = 0; i < ( size_t ) m_pRecordDescriptorTable->ui64Size; i++ )
141  pRecordDescriptorBuffer[ i ] = pDAFFDataBuffer[ i + m_pRecordDescriptorTable->ui64Offset ];
142 
143  ec = loadRecordDescriptor();
144  if( ec != DAFF_NO_ERROR )
145  {
146  DAFF::free_aligned16( m_pRecordDescriptorBlock );
147  tidyup();
148  return ec;
149  }
150 
151  // Record data
152  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_DATA_ID, m_pDataFileBlock ) != 1 )
153  {
154  tidyup();
155  return DAFF_FILE_CORRUPTED;
156  }
157 
158  m_pDataBlock = DAFF::malloc_aligned16( ( size_t ) m_pDataFileBlock->ui64Size );
159  char* pDataBlockBuffer = ( char* ) m_pDataBlock;
160 
161  for( size_t i = 0; i < ( size_t ) m_pDataFileBlock->ui64Size; i++ )
162  pDataBlockBuffer[ i ] = pDAFFDataBuffer[ i + m_pDataFileBlock->ui64Offset ];
163 
164  ec = loadRecordData();
165  if( ec != DAFF_NO_ERROR )
166  {
167  DAFF::free_aligned16( m_pDataBlock );
168  tidyup();
169  return ec;
170  }
171 
172  // Metadata
173  DAFFFileBlockEntry* pMetadataFileBlock = NULL;
174  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_METADATA_ID, pMetadataFileBlock ) > 1 )
175  {
176  tidyup();
177  return DAFF_FILE_CORRUPTED;
178  }
179 
180  if( pMetadataFileBlock == nullptr )
181  {
182  m_vpMetadata.push_back( new DAFFMetadataImpl ); // Empty
183  }
184  else if( pMetadataFileBlock->ui64Size == 0 )
185  {
186  m_vpMetadata.push_back( new DAFFMetadataImpl ); // Empty )
187  }
188  else
189  {
190  // Metadata block present
191  void* pMetadataBuf = DAFF::malloc_aligned16( ( size_t ) pMetadataFileBlock->ui64Size );
192  char* pMetadataBuffer = ( char* ) pMetadataBuf;
193 
194  for( size_t i = 0; i < ( size_t ) pMetadataFileBlock->ui64Size; i++ )
195  pMetadataBuffer[ i ] = pDAFFDataBuffer[ i + pMetadataFileBlock->ui64Offset ];
196 
197  ec = loadMetadata( pMetadataBuffer ); // Converts to internal representation
198 
199  DAFF::free_aligned16( pMetadataBuf );
200 
201  if( ec != DAFF_NO_ERROR )
202  {
203  tidyup();
204  return ec;
205  }
206 
207  }
208 
209  fixAngleRanges();
210 
211  // ... done.
212 
213  m_bDAFFObjectFromFileValid = false;
214  m_bDAFFObjectValid = true;
215 
216  return DAFF_NO_ERROR;
217 }
218 int DAFFReaderImpl::openFile( const std::string& sFilePath )
219 {
220  if( m_bDAFFObjectValid )
221  return DAFF_MODAL_ERROR;
222 
223  m_file = fopen( sFilePath.c_str(), "rb" );
224  if( !m_file )
225  return DAFF_FILE_NOT_FOUND;
226 
227  // File header
228  if( fread( &m_fileHeader, 1, sizeof( DAFFFileHeader ), m_file ) != sizeof( DAFFFileHeader ) )
229  {
230  tidyup();
231  return DAFF_FILE_INVALID;
232  }
233 
234  int ec = loadFileHeader();
235  if( ec != DAFF_NO_ERROR )
236  return ec;
237 
238  // File block table
239  size_t iFileBlockTableSize = m_fileHeader.iNumFileBlocks * sizeof( DAFFFileBlockEntry );
240  m_pFileBlockTable = ( DAFFFileBlockEntry* ) DAFF::malloc_aligned16( iFileBlockTableSize );
241  if( fread( m_pFileBlockTable, 1, iFileBlockTableSize, m_file ) != iFileBlockTableSize )
242  {
243  tidyup();
244  return DAFF_FILE_INVALID;
245  }
246 
247  ec = loadFileBlockTable();
248  if( ec != DAFF_NO_ERROR )
249  return ec;
250 
251  // Main header
252  DAFFFileBlockEntry* pfbMainHeader;
253  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_MAIN_HEADER_ID, pfbMainHeader ) != 1 )
254  {
255  tidyup();
256  return DAFF_FILE_INVALID;
257  }
258 
259  m_pMainHeader = ( DAFFMainHeader* ) DAFF::malloc_aligned16( sizeof( DAFFMainHeader ) );
260  fseek( m_file, ( long ) pfbMainHeader->ui64Offset, SEEK_SET );
261  if( fread( m_pMainHeader, 1, sizeof( DAFFMainHeader ), m_file ) != sizeof( DAFFMainHeader ) )
262  {
263  tidyup();
264  return DAFF_FILE_INVALID;
265  }
266 
267  ec = loadMainHeader();
268  if( ec != DAFF_NO_ERROR )
269  return ec;
270 
271  // Content header
272  DAFFFileBlockEntry* pfbContentHeader;
273  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_CONTENT_HEADER_ID, pfbContentHeader ) != 1 )
274  {
275  tidyup();
276  return DAFF_FILE_CORRUPTED;
277  }
278 
279  m_pContentHeader = ( char* ) DAFF::malloc_aligned16( ( size_t ) pfbContentHeader->ui64Size );
280  fseek( m_file, ( long ) pfbContentHeader->ui64Offset, SEEK_SET );
281  if( fread( m_pContentHeader, 1, ( size_t ) pfbContentHeader->ui64Size, m_file ) != ( size_t ) pfbContentHeader->ui64Size )
282  {
283  tidyup();
284  return DAFF_FILE_CORRUPTED;
285  }
286 
287  ec = loadContentHeader();
288  if( ec != DAFF_NO_ERROR )
289  return ec;
290 
291  // Record descriptor
292  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_RECORD_DESC_ID, m_pRecordDescriptorTable ) != 1 )
293  {
294  tidyup();
295  return DAFF_FILE_CORRUPTED;
296  }
297 
298  m_pRecordDescriptorBlock = ( char* ) DAFF::malloc_aligned16( ( size_t ) m_pRecordDescriptorTable->ui64Size );
299  fseek( m_file, ( long ) m_pRecordDescriptorTable->ui64Offset, SEEK_SET );
300  if( fread( m_pRecordDescriptorBlock, 1, ( size_t ) m_pRecordDescriptorTable->ui64Size, m_file ) != ( size_t ) m_pRecordDescriptorTable->ui64Size )
301  {
302  tidyup();
303  return DAFF_FILE_CORRUPTED;
304  }
305 
306  ec = loadRecordDescriptor();
307  if( ec != DAFF_NO_ERROR )
308  return ec;
309 
310  // Record data
311  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_DATA_ID, m_pDataFileBlock ) != 1 )
312  {
313  tidyup();
314  return DAFF_FILE_CORRUPTED;
315  }
316 
317  m_pDataBlock = DAFF::malloc_aligned16( ( size_t ) m_pDataFileBlock->ui64Size );
318  fseek( m_file, ( long ) m_pDataFileBlock->ui64Offset, SEEK_SET );
319  if( fread( m_pDataBlock, 1, ( size_t ) m_pDataFileBlock->ui64Size, m_file ) != ( size_t ) m_pDataFileBlock->ui64Size )
320  {
321  DAFF::free_aligned16( m_pDataBlock );
322  tidyup();
323  return DAFF_FILE_CORRUPTED;
324  }
325 
326  ec = loadRecordData();
327  if( ec != DAFF_NO_ERROR )
328  return ec;
329 
330  // Metadata
331  DAFFFileBlockEntry* pMetadataFileBlock = NULL;
332  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_METADATA_ID, pMetadataFileBlock ) > 1 )
333  {
334  tidyup();
335  return DAFF_FILE_CORRUPTED;
336  }
337 
338  if( pMetadataFileBlock == nullptr )
339  {
340  m_vpMetadata.push_back( new DAFFMetadataImpl ); // Empty
341  }
342  else if( pMetadataFileBlock->ui64Size == 0 )
343  {
344  m_vpMetadata.push_back( new DAFFMetadataImpl ); // Empty )
345  }
346  else
347  {
348  // Metadata block present
349  void* pMetadataBuf = DAFF::malloc_aligned16( ( size_t ) pMetadataFileBlock->ui64Size );
350  fseek( m_file, ( long ) pMetadataFileBlock->ui64Offset, SEEK_SET );
351  if( fread( pMetadataBuf, 1, ( size_t ) pMetadataFileBlock->ui64Size, m_file ) != ( size_t ) pMetadataFileBlock->ui64Size )
352  {
353  DAFF::free_aligned16( pMetadataBuf );
354  tidyup();
355  return DAFF_FILE_CORRUPTED;
356  }
357 
358  ec = loadMetadata( ( char* ) pMetadataBuf );
359  if( ec != DAFF_NO_ERROR )
360  return ec;
361 
362  DAFF::free_aligned16( pMetadataBuf );
363  }
364 
365  fixAngleRanges();
366 
367  fclose( m_file );
368  m_file = NULL;
369 
370  // ... done.
371 
372  m_sFilePath = sFilePath;
373  m_bDAFFObjectValid = true;
374  m_bDAFFObjectFromFileValid = true;
375 
376  return DAFF_NO_ERROR;
377 }
378 
379 int DAFFReaderImpl::loadFileHeader()
380 {
381  /*
382  * 1st step: Load the file header and validate it for correctness
383  */
384 
385  m_fileHeader.fixEndianness();
386 
387  // Check signature
388  if( !( ( m_fileHeader.pcSignature[ 0 ] == 'F' ) && ( m_fileHeader.pcSignature[ 1 ] == 'W' ) ) )
389  {
390  // File is not an OpenDAFF database.
391  tidyup();
392  return DAFF_FILE_INVALID;
393  }
394 
395  // Check version
396  // [This implementation supports version number 1.7]
397  if( m_fileHeader.iFileFormatVersion != 170 )
398  {
399  // Database version not supported
400  tidyup();
402  }
403 
404  // Check file block entries
405  if( m_fileHeader.iNumFileBlocks <= 0 )
406  {
407  // There must be at least one block
408  tidyup();
409  return DAFF_FILE_INVALID;
410  }
411 
412  return DAFF_NO_ERROR;
413 }
414 
415 int DAFFReaderImpl::loadFileBlockTable()
416 {
417  // Read the file block table
418  size_t iFileBlockTableSize = m_fileHeader.iNumFileBlocks * sizeof( DAFFFileBlockEntry );
419 
420  for( int i = 0; i < m_fileHeader.iNumFileBlocks; i++ )
421  m_pFileBlockTable[ i ].fixEndianness();
422 
423 #if ( DAFF_DEBUG == 1 )
424  for( int i=0; i<m_fileHeader.iNumFileBlocks; i++ )
425  printf( "FILE BLOCK[%d] = { ID = 0x%04X, offset = %llu, size = %llu bytes }\n",
426  i, m_pFileBlockTable[i].iID, m_pFileBlockTable[i].ui64Offset, m_pFileBlockTable[i].ui64Size );
427 #endif
428 
429  // Check for correctness
430  for( int i = 0; i < m_fileHeader.iNumFileBlocks; i++ )
431  {
432  // Note: IDs are not checked
433  if( ( m_pFileBlockTable[ i ].ui64Offset < ( sizeof( DAFFFileHeader ) + iFileBlockTableSize ) ) )
434  {
435  tidyup();
436  return DAFF_FILE_INVALID;
437  }
438  }
439 
440  return DAFF_NO_ERROR;
441 }
442 
443 int DAFFReaderImpl::loadMainHeader()
444 {
445  /*
446  * 2nd step: Load the main header, validate it for correctness
447  */
448 
449  m_pMainHeader->fixEndianness();
450 
451  // Content type
452  switch( m_pMainHeader->iContentType )
453  {
456  case DAFF_PHASE_SPECTRUM:
458  case DAFF_DFT_SPECTRUM:
459  break;
460 
461  default:
462  // Invalid content type
463  tidyup();
465  };
466 
467  // Quantization
468  switch( m_pMainHeader->iQuantization )
469  {
470  case DAFF_INT16:
471  case DAFF_INT24:
472  case DAFF_FLOAT32:
473  break;
474 
475  default:
476  // Invalid quantization
477  tidyup();
479  };
480 
481  if( m_pMainHeader->iNumChannels < 1 )
483 
484  if( m_pMainHeader->iNumRecords < 1 )
486 
487  if( m_pMainHeader->iElementsPerRecord < 1 )
489 
490  if( m_pMainHeader->iAlphaPoints < 1 )
492 
493  // alpha start value must not be 360&deg;
494  if( ( m_pMainHeader->fAlphaStart < 0.0f ) || ( m_pMainHeader->fAlphaStart >= 360.0f ) )
496 
497  // alpha stop value may be 360&deg; indicating that the full alpha range is covered.
498  if( ( m_pMainHeader->fAlphaEnd < 0.0f ) || ( m_pMainHeader->fAlphaEnd > 360.0f ) )
500 
501  // Beta angle validation
502  if( m_pMainHeader->iBetaPoints < 1 )
504 
505  if( m_pMainHeader->fBetaStart > m_pMainHeader->fBetaEnd )
507 
508  if( ( m_pMainHeader->fBetaStart < 0.0f ) || ( m_pMainHeader->fBetaStart > 180.0f ) )
510 
511  if( ( m_pMainHeader->fBetaEnd < 0.0f ) || ( m_pMainHeader->fBetaEnd > 180.0f ) )
513 
514  // Orientation
515  m_orientationDefault.fYawAngleDeg = m_pMainHeader->fOrientYaw;
516  m_orientationDefault.fPitchAngleDeg = m_pMainHeader->fOrientPitch;
517  m_orientationDefault.fRollAngleDeg = m_pMainHeader->fOrientRoll;
518  m_tTrans.setOrientation( m_orientationDefault );
519 
520  return DAFF_NO_ERROR;
521 }
522 
523 int DAFFReaderImpl::loadContentHeader()
524 {
525  /*
526  * 3rd step: Load the content header, validate it for correctness
527  */
528 
529  float* pfFreqs = 0;
530 
531  switch( m_pMainHeader->iContentType )
532  {
534  m_pContentHeaderIR = static_cast< DAFFContentHeaderIR* >( m_pContentHeader );
535  m_pContentHeaderIR->fixEndianness();
536 
537  if( m_pContentHeaderIR->fSamplerate < 0.0f )
539 
540  if( ( m_pContentHeaderIR->iMaxEffectiveFilterLength < 0 ) ||
541  ( m_pContentHeaderIR->iMaxEffectiveFilterLength > m_pMainHeader->iElementsPerRecord ) )
543 
544  if( ( m_pContentHeaderIR->iMinFilterOffset < 0 ) ||
545  ( m_pContentHeaderIR->iMinFilterOffset > m_pMainHeader->iElementsPerRecord ) )
547 
548  break;
549 
551  m_pContentHeaderMS = static_cast< DAFFContentHeaderMS* >( m_pContentHeader );
552  m_pContentHeaderMS->fixEndianness();
553 
554  if( m_pContentHeaderMS->iNumFreqs <= 0 )
556 
557  pfFreqs = ( float* ) ( ( char* ) m_pContentHeader + 8 );
558 
559  // Fix the endianness of the frequency list
560  DAFF::le2se_4byte( pfFreqs, m_pContentHeaderMS->iNumFreqs );
561 
562  // Load the (dynamically sized) frequency list
563  m_vfFreqs.resize( m_pContentHeaderMS->iNumFreqs );
564  for( int i = 0; i < m_pContentHeaderMS->iNumFreqs; i++ )
565  m_vfFreqs[ i ] = pfFreqs[ i ];
566 
567  break;
568 
569  case DAFF_PHASE_SPECTRUM:
570  m_pContentHeaderPS = static_cast< DAFFContentHeaderPS* >( m_pContentHeader );
571  m_pContentHeaderPS->fixEndianness();
572 
573  if( m_pContentHeaderPS->iNumFreqs <= 0 )
575 
576  pfFreqs = ( float* ) ( ( char* ) m_pContentHeader + 8 );
577 
578  // Fix the endianness of the frequency list
579  DAFF::le2se_4byte( pfFreqs, m_pContentHeaderPS->iNumFreqs );
580 
581  // Load the (dynamically sized) frequency list
582  m_vfFreqs.resize( m_pContentHeaderPS->iNumFreqs );
583  for( int i = 0; i < m_pContentHeaderPS->iNumFreqs; i++ ) m_vfFreqs[ i ] = pfFreqs[ i ];
584 
585  break;
586 
588  m_pContentHeaderMPS = static_cast< DAFFContentHeaderMPS* >( m_pContentHeader );
589  m_pContentHeaderMPS->fixEndianness();
590 
591  if( m_pContentHeaderMPS->iNumFreqs <= 0 )
593 
594  pfFreqs = ( float* ) ( ( char* ) m_pContentHeader + 8 );
595 
596  // Fix the endianness of the frequency list
597  DAFF::le2se_4byte( pfFreqs, m_pContentHeaderMPS->iNumFreqs );
598 
599  // Load the (dynamically sized) frequency list
600  m_vfFreqs.resize( m_pContentHeaderMPS->iNumFreqs );
601  for( int i = 0; i < m_pContentHeaderMPS->iNumFreqs; i++ ) m_vfFreqs[ i ] = pfFreqs[ i ];
602 
603  break;
604 
605  case DAFF_DFT_SPECTRUM:
606  m_pContentHeaderDFT = static_cast< DAFFContentHeaderDFT* >( m_pContentHeader );
607  m_pContentHeaderDFT->fixEndianness();
608 
609  if( ( m_pContentHeaderDFT->iNumDFTCoeffs != m_pContentHeaderDFT->iTransformSize ) &&
610  ( m_pContentHeaderDFT->iNumDFTCoeffs != floor( m_pContentHeaderDFT->iTransformSize / 2.0 ) + 1 ) )
612 
613  break;
614  }
615 
616  return DAFF_NO_ERROR;
617 }
618 
619 int DAFFReaderImpl::loadRecordDescriptor()
620 {
621  /*
622  * 4rd step: Load the record descriptor block
623  */
624 
625  // Set access pointer and fix the endianness
626  switch( m_pMainHeader->iContentType )
627  {
629  // A single IR record channel desc is 4+4+4+8 Byte = 20 Bytes
630  m_iRecordChannelDescSize = sizeof( DAFFRecordChannelDescIR );
631  assert( m_iRecordChannelDescSize == 20 );
632 
633  // Fix endianness for channel descriptors and metadata index
634  for( int i = 0; i < m_pMainHeader->iNumRecords; i++ )
635  {
636  for( int c = 0; c < m_pMainHeader->iNumChannels; c++ )
637  {
638  DAFFRecordChannelDescIR* pDesc = reinterpret_cast< DAFFRecordChannelDescIR* >( getRecordChannelDescPtr( i, c ) );
639  pDesc->fixEndianness();
640  }
641 
642  DAFF::le2se_4byte( getRecordMetadataIndexPtr( i ), 1 );
643  };
644 
645  break;
646 
648  case DAFF_PHASE_SPECTRUM:
650  case DAFF_DFT_SPECTRUM:
651  // All other content use a default record channel desc (MS/PS/MPS/DFT) which is 8 Bytes
652  m_iRecordChannelDescSize = sizeof( DAFFRecordChannelDescDefault );
653 
654  // Fix endianness for channel descriptors and metadata index
655  for( int i = 0; i < m_pMainHeader->iNumRecords; i++ )
656  {
657  for( int c = 0; c < m_pMainHeader->iNumChannels; c++ )
658  {
659  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( i, c ) );
660  pDesc->fixEndianness();
661  }
662 
663  DAFF::le2se_4byte( getRecordMetadataIndexPtr( i ), 1 );
664  };
665 
666  break;
667  };
668 
669  return DAFF_NO_ERROR;
670 }
671 
672 int DAFFReaderImpl::loadRecordData()
673 {
674  /*
675  * 5th step: Load the record data
676  */
677 
678  // Fix the endianess of the data
679  switch( m_pMainHeader->iQuantization )
680  {
681  case DAFF_INT16:
682  DAFF::le2se_2byte( m_pDataBlock, ( size_t ) ( m_pDataFileBlock->ui64Size / 2 ) );
683  break;
684 
685  case DAFF_INT24:
686  DAFF::le2se_3byte( m_pDataBlock, ( size_t ) ( m_pDataFileBlock->ui64Size / 3 ) );
687  break;
688 
689  case DAFF_FLOAT32:
690  DAFF::le2se_4byte( m_pDataBlock, ( size_t ) ( m_pDataFileBlock->ui64Size / 4 ) );
691  break;
692  }
693 
694  return DAFF_NO_ERROR;
695 }
696 
697 int DAFFReaderImpl::loadMetadata( char* pMetadataBuf )
698 {
699  /*
700  * 6th step: Load the metadata
701  */
702 
703  DAFFFileBlockEntry* pMetadataFileBlock = NULL;
704  if( getFirstFileBlockByID( FILEBLOCK_DAFF1_METADATA_ID, pMetadataFileBlock ) > 1 )
705  {
706  tidyup();
707  return DAFF_FILE_CORRUPTED;
708  }
709 
710  if( pMetadataFileBlock == nullptr )
711  {
712  m_vpMetadata.push_back( new DAFFMetadataImpl ); // Empty
713  }
714  else if( pMetadataFileBlock->ui64Size == 0 )
715  {
716  m_vpMetadata.push_back( new DAFFMetadataImpl ); // Empty )
717  }
718  else
719  {
720 
721  // Read all the DAFFMetadataImpl instances
722  DAFFMetadataImpl* pMetadataImpl = NULL;
723  size_t iBytesRead = 0;
724  char* pCurrentBuf = pMetadataBuf;
725  char* pEndOfMetaDataBuf = pCurrentBuf + ( size_t ) pMetadataFileBlock->ui64Size;
726  while( pCurrentBuf < pEndOfMetaDataBuf )
727  {
728  pMetadataImpl = new DAFFMetadataImpl;
729  int iError = pMetadataImpl->load( pCurrentBuf, iBytesRead );
730  if( ( iError != 0 ) || ( iBytesRead == 0 ) )
731  {
732  tidyup();
733  return iError;
734  }
735 
736  m_vpMetadata.push_back( pMetadataImpl );
737 
738  // Set Buffer to next DAFFMetaDataImpl instance
739  pCurrentBuf += iBytesRead;
740  }
741  }
742 
743  return DAFF_NO_ERROR;
744 }
745 
746 void DAFFReaderImpl::fixAngleRanges()
747 {
748 
749  // Important: If there is only one point in a dimension => Then there is no resolution
750  // TODO: Recheck if this is correct for non-full and full angular ranges
751 
752  float fAlphaSpan;
753  if( m_pMainHeader->fAlphaEnd > m_pMainHeader->fAlphaStart )
754  fAlphaSpan = m_pMainHeader->fAlphaEnd - m_pMainHeader->fAlphaStart;
755  else
756  fAlphaSpan = 360 - m_pMainHeader->fAlphaStart + m_pMainHeader->fAlphaEnd;
757  float fBetaSpan = m_pMainHeader->fBetaEnd - m_pMainHeader->fBetaStart;
758 
759  /*
760  * [fwe] Bugfix 2011-05-30
761  * Only if the full azimuth range is span, the formula
762  *
763  * m_fAlphaResolution = fAlphaSpan / m_pMainHeader->iAlphaPoints
764  *
765  * is valid. In case there is no full alpha coverage, the last point
766  * marks the end of the interval and does not count. Therefore:
767  *
768  * m_fAlphaResolution = fAlphaSpan / (m_pMainHeader->iAlphaPoints-1)
769  *
770  */
771 
772  if( m_pMainHeader->iAlphaPoints > 1 )
773  {
774  if( fAlphaSpan == 360 )
775  m_fAlphaResolution = fAlphaSpan / m_pMainHeader->iAlphaPoints;
776  else
777  m_fAlphaResolution = fAlphaSpan / ( m_pMainHeader->iAlphaPoints - 1 );
778  }
779  else
780  m_fAlphaResolution = 0;
781 
782  if( m_pMainHeader->iBetaPoints > 1 )
783  m_fBetaResolution = fBetaSpan / ( m_pMainHeader->iBetaPoints - 1 );
784  else
785  m_fBetaResolution = 0;
786 }
787 
789 {
790  if( !m_bDAFFObjectValid )
791  return;
792 
793  tidyup();
794 }
795 
796 void DAFFReaderImpl::tidyup()
797 {
798  if( m_file )
799  {
800  fclose( m_file );
801  m_file = NULL;
802  }
803 
804  DAFF::free_aligned16( m_pFileBlockTable );
805  m_pFileBlockTable = NULL;
806 
807  DAFF::free_aligned16( m_pMainHeader );
808  m_pMainHeader = NULL;
809 
810  DAFF::free_aligned16( m_pContentHeader );
811  m_pContentHeader = NULL;
812 
813  DAFF::free_aligned16( m_pRecordDescriptorBlock );
814  m_pRecordDescriptorBlock = NULL;
815 
816  DAFF::free_aligned16( m_pDataBlock );
817  m_pDataBlock = NULL;
818 
819  for( size_t i = 0; i < m_vpMetadata.size(); ++i )
820  delete m_vpMetadata[ i ];
821 
822  m_vpMetadata.clear();
823 
824  m_sFilePath = "";
825  m_bDAFFObjectValid = false;
826 }
827 
828 int DAFFReaderImpl::getFirstFileBlockByID( int iID, DAFFFileBlockEntry*& pfDest ) const
829 {
830  std::vector<DAFFFileBlockEntry*> v;
831  getFileBlocksByID( iID, v );
832 
833  if( v.empty() )
834  {
835  pfDest = NULL;
836  return 0;
837  }
838 
839  pfDest = v.front();
840  return ( int ) v.size();
841 }
842 
843 int DAFFReaderImpl::getFileBlocksByID( int iID, std::vector<DAFFFileBlockEntry*>& vpfDest ) const
844 {
845  vpfDest.clear();
846  for( int i = 0; i < m_fileHeader.iNumFileBlocks; i++ ) {
847  if( m_pFileBlockTable[ i ].iID == iID ) vpfDest.push_back( &( m_pFileBlockTable[ i ] ) );
848  }
849 
850  return ( int ) vpfDest.size();
851 }
852 
853 std::string DAFFReaderImpl::getFilename() const
854 {
855  assert( m_bDAFFObjectValid );
856  return m_sFilePath;
857 }
858 
860 {
861  assert( m_bDAFFObjectValid );
862  return m_fileHeader.iFileFormatVersion;
863 }
864 
866 {
867  assert( m_bDAFFObjectValid );
868  return m_pMainHeader->iContentType;
869 }
870 
872 {
873  assert( m_bDAFFObjectValid );
874  // Logical constness here!
875  // TODO: Bad cast
876  return ( DAFFContentIR* ) this;
877 }
878 
880 {
881  assert( m_bDAFFObjectValid );
882  return m_vpMetadata[ 0 ];
883 }
884 
886 {
887  assert( m_bDAFFObjectValid );
888  // TODO: Fixme
889  return ( DAFFProperties* ) this;
890 }
891 
892 std::string DAFFReaderImpl::toString() const
893 {
894  assert( m_bDAFFObjectValid );
895 
896  std::stringstream ss;
897 
898  float fVersion = getFileFormatVersion() / 1000.0F;;
899  ss << "File format version: " << DAFFUtils::Float2StrNice( fVersion, 3, false ) << std::endl;
900  ss << "Content type: " << DAFFUtils::StrContentType( getProperties()->getContentType() ) << std::endl;
901  ss << "Quantization: " << DAFFUtils::StrQuantizationType( getProperties()->getQuantization() ) << std::endl << std::endl;
902  ss << "Number of channels: " << getProperties()->getNumberOfChannels() << std::endl;
903  ss << "Number of records: " << getProperties()->getNumberOfRecords() << std::endl << std::endl;
904  ss << "Alpha points: " << getProperties()->getAlphaPoints() << std::endl;
905  ss << "Alpha range: [" <<
906  DAFFUtils::Float2StrNice( getProperties()->getAlphaStart(), 3, false ) << "\xF8, " <<
907  DAFFUtils::Float2StrNice( getProperties()->getAlphaEnd(), 3, false ) << "\xF8]" << std::endl;
908  ss << "Beta points: " << getProperties()->getBetaPoints() << std::endl;
909  ss << "Beta range: [" <<
910  DAFFUtils::Float2StrNice( getProperties()->getBetaStart(), 3, false ) << "\xF8, " <<
911  DAFFUtils::Float2StrNice( getProperties()->getBetaEnd(), 3, false ) << "\xF8]" << std::endl;
912  ss << "Full sphere: " << ( getProperties()->coversFullSphere() ? "yes" : "no" ) << std::endl;
914  getOrientation( o );
915  ss << "Orientation: " << o.toString() << std::endl;
916 
917  DAFFContentIR* pContentIR;
918  DAFFReaderImpl* pContent;
919  DAFFContentDFT* pContentDFT;
920  std::vector<float> vsFrequencies;
921 
922  switch( getContentType() ) {
924  pContentIR = dynamic_cast< DAFFContentIR* >( getContent() );
925  ss << "Samplerate: " << DAFFUtils::Double2StrNice( pContentIR->getSamplerate(), 1, false ) << " Hz" << std::endl;
926  ss << "Filter length: " << pContentIR->getFilterLength() << std::endl;
927  break;
928 
930  case DAFF_PHASE_SPECTRUM:
932  pContent = dynamic_cast< DAFFReaderImpl* >( getContent() );
933  ss << "Number of frequencies: " << pContent->getNumFrequencies() << std::endl;
934  vsFrequencies = pContent->getFrequencies();
935  ss << "Frequency support: ";
936  for( size_t i = 0; i < vsFrequencies.size(); i++ ) {
937  ss << DAFFUtils::Float2StrNice( vsFrequencies[ i ], 3, false );
938  if( i < ( vsFrequencies.size() - 1 ) ) ss << ", ";
939  }
940  ss << " Hz" << std::endl;
941  break;
942 
943 
944  case DAFF_DFT_SPECTRUM:
945  pContentDFT = dynamic_cast< DAFFContentDFT* >( getContent() );
946  ss << "Transform size: " << pContentDFT->getTransformSize() << std::endl;
947  ss << "Symmetric: " << ( ( pContentDFT->isSymmetric() ) ? "yes" : "no" ) << std::endl;
948  ss << "Samplerate: " << pContentDFT->getSamplerate() << std::endl;
949  break;
950  }
951  return ss.str();
952 }
953 
954 // --------------------------------------------------------
955 
957  assert( m_bDAFFObjectValid );
958  return m_pMainHeader->iQuantization;
959 }
960 
962  assert( m_bDAFFObjectValid );
963  return m_pMainHeader->iNumChannels;
964 }
965 
967 {
968  assert( m_bDAFFObjectValid );
969  return m_pMainHeader->iNumRecords;
970 }
971 
972 std::string DAFFReaderImpl::getChannelLabel( int iChannel ) const
973 {
974  /* @todo
975  This specific function requires a certain key/value pair
976  within the global metadata entries in the DAFF file. It appears
977  more elegant to provide "styles" that can be met with a defined
978  set of keys and values. Compatibility can be checked during loading
979  or runtime and the file is marked as "whateever"-kompatible.
980  */
981 
982  assert( m_bDAFFObjectValid );
983  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
984 
985  // Fetch the channel name from the metadata
986  std::stringstream ss;
987  ss << "LABEL_CHANNEL_" << ( iChannel + 1 );
988  return ( ( m_vpMetadata.size() > 0 ) && ( m_vpMetadata[ 0 ]->hasKey( ss.str() ) ) ? m_vpMetadata[ 0 ]->getKeyString( ss.str() ) : "" );
989 }
990 
992 {
993  assert( m_bDAFFObjectValid );
994  return m_pMainHeader->iAlphaPoints;
995 }
996 
998  assert( m_bDAFFObjectValid );
999 
1000  return m_fAlphaResolution;
1001 }
1002 
1004  assert( m_bDAFFObjectValid );
1005  return m_pMainHeader->fAlphaStart;
1006 }
1007 
1009  assert( m_bDAFFObjectValid );
1010  return m_pMainHeader->fAlphaEnd;
1011 }
1012 
1014  assert( m_bDAFFObjectValid );
1015  if( m_pMainHeader->fAlphaStart <= m_pMainHeader->fAlphaEnd )
1016  return m_pMainHeader->fAlphaEnd - m_pMainHeader->fAlphaStart;
1017  else // wrap around 0&deg;
1018  return 360 - m_pMainHeader->fAlphaStart + m_pMainHeader->fAlphaEnd;
1019 }
1020 
1022  assert( m_bDAFFObjectValid );
1023  return m_pMainHeader->iBetaPoints;
1024 }
1025 
1027  assert( m_bDAFFObjectValid );
1028  return m_fBetaResolution;
1029 }
1030 
1032  assert( m_bDAFFObjectValid );
1033  return m_pMainHeader->fBetaStart;
1034 }
1035 
1037  assert( m_bDAFFObjectValid );
1038  return m_pMainHeader->fBetaEnd;
1039 }
1040 
1042  assert( m_bDAFFObjectValid );
1043  return m_pMainHeader->fAlphaEnd - m_pMainHeader->fAlphaStart;
1044 }
1045 
1047  assert( m_bDAFFObjectValid );
1048  o = m_orientationDefault;
1049 }
1050 
1052  assert( m_bDAFFObjectValid );
1053  m_tTrans.setOrientation( m_orientationDefault );
1054 }
1055 
1057  assert( m_bDAFFObjectValid );
1058  m_tTrans.getOrientation( o );
1059 }
1060 
1062  assert( m_bDAFFObjectValid );
1063  m_tTrans.setOrientation( o );
1064 }
1065 
1067  assert( m_bDAFFObjectValid );
1068  // full range coverage is given only when alphastart == 0 and alphaend == 360
1069  if( ( m_pMainHeader->fAlphaStart == 0 ) && ( m_pMainHeader->fAlphaEnd == 360 ) )
1070  return true;
1071  else
1072  return false;
1073 }
1074 
1076  assert( m_bDAFFObjectValid );
1077  // full range coverage is given only when betastart == 0 and betaend == 180
1078  if( ( m_pMainHeader->fBetaStart == 0 ) && ( m_pMainHeader->fBetaEnd == 180 ) )
1079  return true;
1080  else
1081  return false;
1082 }
1083 
1085  assert( m_bDAFFObjectValid );
1086  /*
1087  if ( ((m_pMainHeader->fAlphaEnd - m_pMainHeader->fAlphaStart) >= (360.0f - getAlphaResolution()) &&
1088  ((m_pMainHeader->fBetaEnd - m_pMainHeader->fBetaStart) == 180.0f)) )
1089  return true;
1090 
1091  return false;*/
1093 }
1094 
1096  // We are the reader ourself!
1097  // Logical constness here!
1098  return const_cast< DAFFReaderImpl* >( this );
1099 }
1100 
1101 void DAFFReaderImpl::getNearestNeighbour( int iView, float fAngle1, float fAngle2, int& iRecordIndex ) const {
1102  assert( ( iView == DAFF_DATA_VIEW ) || ( iView == DAFF_OBJECT_VIEW ) );
1103 
1104  bool bDummy;
1105  getNearestNeighbour( iView, fAngle1, fAngle2, iRecordIndex, bDummy );
1106 }
1107 
1108 const DAFFMetadata* DAFFReaderImpl::getRecordMetadata( int iRecordIndex ) const
1109 {
1110  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1111 
1112  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) )
1113  return m_pEmptyMetadata;
1114 
1115  int iMetadataIndex = *getRecordMetadataIndexPtr( iRecordIndex );
1116 
1117  assert( ( iMetadataIndex >= -1 ) && ( iMetadataIndex < ( int ) m_vpMetadata.size() ) );
1118 
1119  if( iMetadataIndex == -1 )
1120  return m_pEmptyMetadata;
1121  else
1122  return m_vpMetadata[ iMetadataIndex ];
1123 }
1124 
1125 int DAFFReaderImpl::getRecordCoords( int iRecordIndex, int iView, float& fAngle1, float& fAngle2 ) const {
1126  assert( ( iRecordIndex >= 0 ) || ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1127  assert( ( iView == DAFF_DATA_VIEW ) || ( iView == DAFF_OBJECT_VIEW ) );
1128 
1129  // Invalid record index - projection to get a valid index
1130  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ) {
1131  // TODO: Discuss if this makes sense
1132  return -1;
1133  }
1134 
1135  int iAlpha, iBeta;
1136  float fAlpha, fBeta;
1137 
1138  bool bSouthPolePresent = false;
1139  if( m_pMainHeader->fBetaStart == 0.0f ) // South pole present (single record here)
1140  bSouthPolePresent = true;
1141 
1142  if( bSouthPolePresent ) {
1143  if( iRecordIndex == 0 ) { // Hit south pole
1144  fAlpha = 0.0f;
1145  fBeta = 0.0f;
1146  }
1147  else { // somewhere inside the grid (with single value at south pole)
1148  iAlpha = ( iRecordIndex - 1 ) % m_pMainHeader->iAlphaPoints;
1149  iBeta = 1 + ( int ) ( ( iRecordIndex - 1 ) / m_pMainHeader->iAlphaPoints );
1150  fAlpha = m_pMainHeader->fAlphaStart + ( ( float ) iAlpha * m_fAlphaResolution );
1151  fBeta = ( float ) iBeta * m_fBetaResolution;
1152  }
1153  }
1154  else { // somewhere inside the grid (without south pole present)
1155  iAlpha = iRecordIndex % m_pMainHeader->iAlphaPoints;
1156  iBeta = ( int ) ( iRecordIndex / m_pMainHeader->iAlphaPoints );
1157  fAlpha = m_pMainHeader->fAlphaStart + ( ( float ) iAlpha * m_fAlphaResolution );
1158  fBeta = m_pMainHeader->fBetaStart + ( ( float ) iBeta * m_fBetaResolution );
1159  }
1160 
1161  if( iView == DAFF_DATA_VIEW ) {
1162  fAngle1 = fAlpha;
1163  fAngle2 = fBeta;
1164  }
1165  else {
1166  transformAnglesD2O( fAlpha, fBeta, fAngle1, fAngle2 );
1167  }
1168 
1169  return 0;
1170 }
1171 
1172 void DAFFReaderImpl::getNearestNeighbour( int iView, float fAngle1, float fAngle2, int& iRecordIndex, bool& bOutOfBounds ) const
1173 {
1174  assert( ( iView == DAFF_DATA_VIEW ) || ( iView == DAFF_OBJECT_VIEW ) );
1175 
1176  float fAlpha;
1177  float fBeta;
1178 
1179  if( iView == DAFF_DATA_VIEW )
1180  {
1181  fAlpha = fAngle1;
1182  fBeta = fAngle2;
1183  }
1184  else
1185  {
1186  // Transform the coordinates into the DSC
1187  transformAnglesO2D( fAngle1, fAngle2, fAlpha, fBeta );
1188  }
1189 
1190  // Normalize the direction
1191  DAFFUtils::NormalizeDirection( DAFF_DATA_VIEW, fAlpha, fBeta, fAlpha, fBeta );
1192 
1193  iRecordIndex = -1;
1194  bOutOfBounds = false;
1195 
1196  int iAlphaIndex, iBetaIndex;
1197 
1198  if( m_pMainHeader->iAlphaPoints == 1 )
1199  {
1200  // Trivial case: Just one point
1201  iAlphaIndex = 0;
1202  bOutOfBounds = true;
1203  if( fAlpha == m_pMainHeader->fAlphaStart && fAlpha == std::fmod( m_pMainHeader->fAlphaEnd, 360.0f ) )
1204  bOutOfBounds = false; // Direct hit
1205  }
1206  else
1207  {
1208  if( ( fAlpha >= m_pMainHeader->fAlphaStart ) && ( fAlpha <= m_pMainHeader->fAlphaEnd ) )
1209  {
1210  // Within the covered alpha range
1211  iAlphaIndex = ( int ) roundf( ( fAlpha - m_pMainHeader->fAlphaStart ) / m_fAlphaResolution );
1212  }
1213  else
1214  {
1215  // Outside the covered alpha range
1216  // Decide: Which is closer? Start boundary or end boundary?
1217  if( DAFF::anglef_mindiff_abs_0_360_DEG( m_pMainHeader->fAlphaStart, fAlpha ) <= DAFF::anglef_mindiff_abs_0_360_DEG( m_pMainHeader->fAlphaEnd, fAlpha ) )
1218  iAlphaIndex = 0; // Start index
1219  else
1220  iAlphaIndex = ( int ) m_pMainHeader->iAlphaPoints - 1; // End index
1221 
1222  bOutOfBounds = true;
1223  }
1224  }
1225 
1226  if( m_pMainHeader->iBetaPoints == 1 )
1227  {
1228  // Trivial case: Just one point
1229  iBetaIndex = 0;
1230  bOutOfBounds = true;
1231  if( fBeta == m_pMainHeader->fBetaEnd && fBeta == m_pMainHeader->fBetaStart )
1232  bOutOfBounds = false; // Direct hit
1233  }
1234  else
1235  {
1236  if( ( fBeta >= m_pMainHeader->fBetaStart ) && ( fBeta <= m_pMainHeader->fBetaEnd ) )
1237  {
1238  // Within the covered beta range
1239  iBetaIndex = ( int ) roundf( ( fBeta - m_pMainHeader->fBetaStart ) / m_fBetaResolution );
1240  }
1241  else
1242  {
1243  // Outside the covered beta range
1244  // Decide: Which is closer? Start boundary or end boundary?
1245  if( std::abs( m_pMainHeader->fBetaStart - fBeta ) <= std::abs( m_pMainHeader->fBetaEnd - fBeta ) )
1246  iBetaIndex = 0; // Start index
1247  else
1248  iBetaIndex = ( int ) m_pMainHeader->iBetaPoints - 1; // End index
1249 
1250  bOutOfBounds = true;
1251  }
1252  }
1253 
1254  // Calculate index
1255  if( m_pMainHeader->fBetaStart == 0.0f )
1256  { // South pole present: increment by one (single record at poles)
1257  if( iBetaIndex == 0 )
1258  { // Hit south pole
1259  iRecordIndex = 0;
1260  }
1261  else
1262  {
1263  if( ( iBetaIndex == m_pMainHeader->iBetaPoints - 1 ) && ( m_pMainHeader->fBetaEnd == 180.0f ) ) // Hit north pole
1264  iRecordIndex = 1 + ( iBetaIndex - 1 ) * m_pMainHeader->iAlphaPoints;
1265  else
1266  iRecordIndex = 1 + ( iBetaIndex - 1 ) * m_pMainHeader->iAlphaPoints + iAlphaIndex;
1267  }
1268  }
1269  else
1270  {
1271  if( ( iBetaIndex == m_pMainHeader->iBetaPoints - 1 ) && ( m_pMainHeader->fBetaEnd == 180.0f ) ) // Hit north pole
1272  iRecordIndex = iBetaIndex * m_pMainHeader->iAlphaPoints;
1273  else
1274  iRecordIndex = iBetaIndex * m_pMainHeader->iAlphaPoints + iAlphaIndex;
1275  }
1276 
1277  return;
1278 }
1279 
1280 void DAFFReaderImpl::getCell( int iView, const float fAngle1, const float fAngle2, DAFFQuad& qIndices ) const {
1281 
1282  //switch to data view
1283  float fAlpha = fAngle1;
1284  float fBeta = fAngle2;
1285  if( iView == DAFF_OBJECT_VIEW )
1286  transformAnglesO2D( fAngle1, fAngle2, fAlpha, fBeta );
1287  DAFFUtils::NormalizeDirection( DAFF_DATA_VIEW, fAlpha, fBeta, fAlpha, fBeta );
1288 
1289  // south pole with full sphere covered is a problem (but algorithm holds for north pole)
1290  if( fBeta == 0.0f && coversFullSphere() ) { // return the south pole 4 times
1291  getNearestNeighbour( DAFF_DATA_VIEW, 0.0f, 0.0f, qIndices.iIndex1 );
1292  qIndices.iIndex2 = qIndices.iIndex1;
1293  qIndices.iIndex3 = qIndices.iIndex1;
1294  qIndices.iIndex4 = qIndices.iIndex1;
1295  return;
1296  }
1297 
1298  // grid angles
1299  float fAlpha1 = 0, fAlpha2 = 0, fAlpha3 = 0, fAlpha4 = 0;
1300  float fBeta1 = 0, fBeta2 = 0, fBeta3 = 0, fBeta4 = 0;
1301 
1302  fAlpha1 = fAlpha - fmodf( fAlpha, getAlphaResolution() );
1303  fAlpha2 = fAlpha1;
1304  fAlpha3 = fAlpha + getAlphaResolution() - fmodf( fAlpha, getAlphaResolution() );
1305  fAlpha4 = fAlpha3;
1306 
1307  fBeta1 = fBeta - fmodf( fBeta, getBetaResolution() );
1308  fBeta2 = fBeta + getBetaResolution() - fmodf( fBeta, getBetaResolution() );
1309  fBeta3 = fBeta2;
1310  fBeta4 = fBeta1;
1311 
1312  // Upper beta angles are not allowed to overrun the north pole
1313  if( fBeta2 > 180.0f ) {
1314  fBeta2 = 180.0f;
1315  fBeta3 = 180.0f;
1316  }
1317 
1318  // Normalize & get indices
1319  DAFFUtils::NormalizeDirection( DAFF_DATA_VIEW, fAlpha1, fBeta1, fAlpha1, fBeta1 );
1320  DAFFUtils::NormalizeDirection( DAFF_DATA_VIEW, fAlpha2, fBeta2, fAlpha2, fBeta2 );
1321  DAFFUtils::NormalizeDirection( DAFF_DATA_VIEW, fAlpha3, fBeta3, fAlpha3, fBeta3 );
1322  DAFFUtils::NormalizeDirection( DAFF_DATA_VIEW, fAlpha4, fBeta4, fAlpha4, fBeta4 );
1323 
1324  getNearestNeighbour( DAFF_DATA_VIEW, fAlpha1, fBeta1, qIndices.iIndex1 );
1325  getNearestNeighbour( DAFF_DATA_VIEW, fAlpha2, fBeta2, qIndices.iIndex2 );
1326  getNearestNeighbour( DAFF_DATA_VIEW, fAlpha3, fBeta3, qIndices.iIndex3 );
1327  getNearestNeighbour( DAFF_DATA_VIEW, fAlpha4, fBeta4, qIndices.iIndex4 );
1328 }
1329 
1330 void DAFFReaderImpl::transformAnglesD2O( const float fAlpha, const float fBeta, float& fAzimuth, float& fElevation ) const {
1331  m_tTrans.transformDSC2OSC( fAlpha, fBeta, fAzimuth, fElevation );
1332 }
1333 
1334 void DAFFReaderImpl::transformAnglesO2D( const float fAzimuth, const float fElevation, float& fAlpha, float& fBeta ) const {
1335  m_tTrans.transformOSC2DSC( fAzimuth, fElevation, fAlpha, fBeta );
1336 }
1337 
1339  if( m_pMainHeader->iContentType == DAFF_IMPULSE_RESPONSE )
1340  return m_pContentHeaderIR->fSamplerate;
1341  if( m_pMainHeader->iContentType == DAFF_DFT_SPECTRUM )
1342  return m_pContentHeaderDFT->fSamplerate;
1343  return 0; // error
1344 }
1345 
1347  return m_pMainHeader->iElementsPerRecord;
1348 }
1349 
1351  return m_pContentHeaderIR->iMinFilterOffset;
1352 }
1353 
1355  return m_pContentHeaderIR->iMaxEffectiveFilterLength;
1356 }
1357 
1358 int DAFFReaderImpl::getFilterCoeffs( int iRecordIndex, int iChannel, float* pfDest, float fGain ) const
1359 {
1360  int iOffset;
1361  int iEffectiveLength;
1362  int iError;
1363 
1364  iError = getEffectiveFilterBounds( iRecordIndex, iChannel, iOffset, iEffectiveLength );
1365  if( iError != DAFF_NO_ERROR ) return iError;
1366 
1367  // Place zeros before the data
1368  for( int i = 0; i < iOffset; i++ )
1369  pfDest[ i ] = 0;
1370 
1371  // Insert the data
1372  iError = getEffectiveFilterCoeffs( iRecordIndex, iChannel, pfDest + iOffset, fGain );
1373  if( iError != DAFF_NO_ERROR ) return iError;
1374 
1375  // Place zeros behind the data
1376  for( int i = iOffset + iEffectiveLength; i < getFilterLength(); i++ )
1377  pfDest[ i ] = 0;
1378 
1379  return DAFF_NO_ERROR;
1380 }
1381 
1382 int DAFFReaderImpl::addFilterCoeffs( int iRecordIndex, int iChannel, float* pfDest, float fGain ) const
1383 {
1384  int iOffset;
1385  int iEffectiveLength;
1386  int iError;
1387 
1388  iError = getEffectiveFilterBounds( iRecordIndex, iChannel, iOffset, iEffectiveLength );
1389  if( iError != DAFF_NO_ERROR )
1390  return iError;
1391 
1392  // Insert the data
1393  iError = addEffectiveFilterCoeffs( iRecordIndex, iChannel, pfDest + iOffset, fGain );
1394  if( iError != DAFF_NO_ERROR )
1395  return iError;
1396 
1397  return DAFF_NO_ERROR;
1398 }
1399 
1400 int DAFFReaderImpl::getEffectiveFilterBounds( int iRecordIndex, int iChannel, int& iOffset, int& iLength ) const
1401 {
1402  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1403  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1404 
1405  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1406  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1407  return DAFF_INVALID_INDEX;
1408 
1409  DAFFRecordChannelDescIR* pDesc = reinterpret_cast< DAFFRecordChannelDescIR* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1410  iOffset = pDesc->iLeadingZeros;
1411  iLength = pDesc->iElementLength;
1412 
1413  return DAFF_NO_ERROR;
1414 }
1415 
1416 int DAFFReaderImpl::getEffectiveFilterCoeffs( int iRecordIndex, int iChannel, float* pfDest, float fGain ) const
1417 {
1418  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1419  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1420 
1421  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1422  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1423  return DAFF_INVALID_INDEX;
1424 
1425  if( pfDest == NULL )
1426  return DAFF_NO_ERROR;
1427 
1428  DAFFRecordChannelDescIR* pDesc = reinterpret_cast< DAFFRecordChannelDescIR* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1429  // Check data offset for buffer overruns
1430  assert( pDesc->ui64DataOffset < m_pDataFileBlock->ui64Size );
1431  void* pData = reinterpret_cast< char* >( m_pDataBlock ) + pDesc->ui64DataOffset;
1432 
1433  // Data type conversion
1434  switch( m_pMainHeader->iQuantization )
1435  {
1436  case DAFF_INT16:
1437  DAFF::stc_sint16_to_float( pfDest, ( const short* ) pData, pDesc->iElementLength, 1, 1, fGain );
1438  break;
1439 
1440  case DAFF_INT24:
1441  DAFF::stc_sint24_to_float( pfDest, pData, pDesc->iElementLength, 1, 1, fGain );
1442  break;
1443 
1444  case DAFF_FLOAT32:
1445  if( fGain == 1 )
1446  { // Direct copy
1447  memcpy( pfDest, pData, pDesc->iElementLength * sizeof( float ) );
1448  }
1449  else
1450  {
1451  // Copy with gain multiplication
1452  float* pfData = ( float* ) pData;
1453  for( int i = 0; i < pDesc->iElementLength; i++ )
1454  pfDest[ i ] = pfData[ i ] * fGain;
1455  }
1456  break;
1457  }
1458 
1459  return DAFF_NO_ERROR;
1460 }
1461 
1462 int DAFFReaderImpl::addEffectiveFilterCoeffs( int iRecordIndex, int iChannel, float* pfDest, float fGain ) const
1463 {
1464  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1465  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1466 
1467  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1468  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1469  return DAFF_INVALID_INDEX;
1470 
1471  if( pfDest == NULL ) return DAFF_NO_ERROR;
1472 
1473  DAFFRecordChannelDescIR* pDesc = reinterpret_cast< DAFFRecordChannelDescIR* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1474  // Check data offset for buffer overruns
1475  assert( pDesc->ui64DataOffset < m_pDataFileBlock->ui64Size );
1476  void* pData = reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset;
1477 
1478  // Data type conversion
1479  switch( m_pMainHeader->iQuantization ) {
1480  case DAFF_INT16:
1481  DAFF::stc_sint16_to_float_add( pfDest, ( const short* ) pData, pDesc->iElementLength, 1, 1, fGain );
1482  break;
1483 
1484  case DAFF_INT24:
1485  DAFF::stc_sint24_to_float_add( pfDest, pData, pDesc->iElementLength, 1, 1, fGain );
1486  break;
1487 
1488  case DAFF_FLOAT32:
1489  float* pfData = ( float* ) pData;
1490  for( int i = 0; i < pDesc->iElementLength; i++ )
1491  pfDest[ i ] += pfData[ i ] * fGain;
1492  break;
1493  }
1494 
1495  return DAFF_NO_ERROR;
1496 }
1497 
1499  switch( m_pMainHeader->iContentType )
1500  {
1502  return m_pContentHeaderMS->iNumFreqs;
1503  case DAFF_PHASE_SPECTRUM:
1504  return m_pContentHeaderPS->iNumFreqs;
1506  return m_pContentHeaderMPS->iNumFreqs;
1507  }
1508  return 0; // error!
1509 }
1510 
1511 const std::vector<float>& DAFFReaderImpl::getFrequencies() const
1512 {
1513  return m_vfFreqs;
1514 }
1515 
1517  switch( m_pMainHeader->iContentType )
1518  {
1520  return m_pContentHeaderMS->fMax;
1522  return m_pContentHeaderMPS->fMax;
1523  case DAFF_DFT_SPECTRUM:
1524  return m_pContentHeaderDFT->fMax;
1525  }
1526  return 0.0; // error!
1527 }
1528 
1530 {
1531  if( !m_bOverallPeakInitialized )
1532  {
1533  // lazy initialization
1534  float *pBuf;
1535  int iOffs = 0, iLen = 0, iSize = getMaxEffectiveFilterLength();
1536  pBuf = new float[ iSize ];
1537  for( int i = 0; i < m_pMainHeader->iNumRecords; i++ )
1538  for( int j = 0; j < m_pMainHeader->iNumChannels; j++ ) {
1539  getEffectiveFilterCoeffs( i, j, pBuf );
1540  getEffectiveFilterBounds( i, j, iOffs, iLen );
1541  for( int k = 0; k<iLen - iOffs; k++ )
1542  if( fabs( pBuf[ k ] ) > m_fOverallPeak )
1543  m_fOverallPeak = fabs( pBuf[ k ] );
1544  }
1545  delete pBuf;
1546  m_bOverallPeakInitialized = true;
1547  }
1548  return m_fOverallPeak;
1549 }
1550 
1551 int DAFFReaderImpl::getMagnitudes( int iRecordIndex, int iChannel, float* pfData ) const {
1552  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1553  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1554 
1555  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1556  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1557  return DAFF_INVALID_INDEX;
1558 
1559  if( pfData == NULL ) return DAFF_NO_ERROR;
1560 
1561  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1562  float* pfSrc = 0;
1563 
1564  switch( m_pMainHeader->iContentType ) {
1566  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1567  memcpy( pfData, pfSrc, m_pContentHeaderMS->iNumFreqs*sizeof( float ) );
1568  break;
1570  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1571  // TODO: maybe find a better way to do this
1572  for( int i = 0; i <= m_pContentHeaderMPS->iNumFreqs; i++ )
1573  pfData[ i ] = pfSrc[ 2 * i ];
1574  break;
1575  default:
1576  return DAFF_MODAL_ERROR;
1577  }
1578 
1579  return DAFF_NO_ERROR;
1580 }
1581 
1582 int DAFFReaderImpl::getMagnitude( int iRecordIndex, int iChannel, int iFreqIndex, float& fMag ) const
1583 {
1584  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1585  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1586 
1587  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1588  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1589  return DAFF_INVALID_INDEX;
1590 
1591  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1592  float* pfSrc = NULL;
1593 
1594  switch( m_pMainHeader->iContentType )
1595  {
1597  if( ( iFreqIndex < 0 ) || ( iFreqIndex >= m_pContentHeaderMS->iNumFreqs ) )
1598  return DAFF_INVALID_INDEX;
1599 
1600  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) + pDesc->ui64DataOffset );
1601  fMag = pfSrc[ iFreqIndex ];
1602  break;
1604  if( ( iFreqIndex < 0 ) || ( iFreqIndex >= m_pContentHeaderMPS->iNumFreqs ) )
1605  return DAFF_INVALID_INDEX;
1606 
1607  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) + pDesc->ui64DataOffset );
1608  fMag = pfSrc[ 2 * iFreqIndex ];
1609  break;
1610  default:
1611  return DAFF_MODAL_ERROR;
1612  }
1613 
1614  return DAFF_NO_ERROR;
1615 }
1616 
1617 int DAFFReaderImpl::getPhases( int iRecordIndex, int iChannel, float* pfData ) const
1618 {
1619  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1620  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1621 
1622  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1623  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1624  return DAFF_INVALID_INDEX;
1625 
1626  if( pfData == NULL ) return DAFF_NO_ERROR;
1627 
1628  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1629  float* pfSrc = 0;
1630 
1631  switch( m_pMainHeader->iContentType )
1632  {
1633  case DAFF_PHASE_SPECTRUM:
1634  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1635  memcpy( pfData, pfSrc, m_pContentHeaderPS->iNumFreqs * sizeof( float ) );
1636  break;
1638  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1639  for( int i = 0; i <= m_pContentHeaderMPS->iNumFreqs; i++ )
1640  pfData[ i ] = pfSrc[ 2 * i + 1 ];
1641  break;
1642  default:
1643  return DAFF_MODAL_ERROR;
1644  }
1645  return DAFF_NO_ERROR;
1646 }
1647 
1648 int DAFFReaderImpl::getPhase( int iRecordIndex, int iChannel, int iFreqIndex, float& fPhase ) const
1649 {
1650  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1651  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1652 
1653  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1654  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1655  return DAFF_INVALID_INDEX;
1656 
1657  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1658  float* pfSrc = 0;
1659 
1660  switch( m_pMainHeader->iContentType ) {
1661  case DAFF_PHASE_SPECTRUM:
1662  if( ( iFreqIndex < 0 ) || ( iFreqIndex >= m_pContentHeaderPS->iNumFreqs ) )
1663  return DAFF_INVALID_INDEX;
1664 
1665  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1666  fPhase = pfSrc[ iFreqIndex ];
1667  break;
1669  if( ( iFreqIndex < 0 ) || ( iFreqIndex >= m_pContentHeaderMPS->iNumFreqs ) )
1670  return DAFF_INVALID_INDEX;
1671 
1672  pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1673  fPhase = pfSrc[ 2 * iFreqIndex + 1 ];
1674  break;
1675  default:
1676  return DAFF_MODAL_ERROR;
1677  }
1678 
1679  return DAFF_NO_ERROR;
1680 }
1681 int DAFFReaderImpl::getCoefficientsMP( int iRecordIndex, int iChannel, float* pfDest ) const {
1682  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1683  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1684 
1685  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1686  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1687  return DAFF_INVALID_INDEX;
1688 
1689  if( pfDest == NULL ) return DAFF_NO_ERROR;
1690 
1691  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1692  float* pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1693 
1694  //TODO: find a better way to do this
1695  for( int i = 0; i <= m_pContentHeaderMPS->iNumFreqs; i++ ) {
1696  //Magnitude
1697  pfDest[ 2 * i ] = DAFF::cabs( pfSrc[ 2 * i ], pfSrc[ 2 * i + 1 ] );
1698  //Phase
1699  pfDest[ 2 * i + 1 ] = DAFF::carg( pfSrc[ 2 * i ], pfSrc[ 2 * i + 1 ] );
1700  }
1701 
1702  return DAFF_NO_ERROR;
1703 }
1704 
1705 int DAFFReaderImpl::getCoefficientsRI( int iRecordIndex, int iChannel, float* pfDest ) const {
1706  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1707  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1708 
1709  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1710  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1711  return DAFF_INVALID_INDEX;
1712 
1713  if( pfDest == NULL ) return DAFF_NO_ERROR;
1714 
1715  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1716  float* pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1717  memcpy( pfDest, pfSrc, 2 * m_pContentHeaderMPS->iNumFreqs*sizeof( float ) );
1718 
1719  return DAFF_NO_ERROR;
1720 }
1721 
1723  return m_pContentHeaderDFT->iTransformSize;
1724 }
1725 
1727  return m_pContentHeaderDFT->iNumDFTCoeffs;
1728 }
1729 
1731 {
1732  return ( m_pContentHeaderDFT->iNumDFTCoeffs != m_pContentHeaderDFT->iTransformSize );
1733 }
1734 
1736  return getSamplerate() / ( double ) getTransformSize();
1737 }
1738 
1739 int DAFFReaderImpl::getDFTCoeff( int iRecordIndex, int iChannel, int iDFTCoeff, float& fReal, float& fImag ) const {
1740  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1741  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1742  assert( ( iDFTCoeff >= 0 ) && ( iDFTCoeff < m_pContentHeaderDFT->iNumDFTCoeffs ) );
1743 
1744  // TODO: Wrap complex-conjugate symmetric range
1745 
1746  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1747  float* pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1748 
1749  fReal = pfSrc[ 2 * iDFTCoeff + 0 ];
1750  fImag = pfSrc[ 2 * iDFTCoeff + 1 ];
1751 
1752  return DAFF_NO_ERROR;
1753 }
1754 
1755 int DAFFReaderImpl::getDFTCoeffs( int iRecordIndex, int iChannel, float* pfDest ) const {
1756  assert( ( iRecordIndex >= 0 ) && ( iRecordIndex < m_pMainHeader->iNumRecords ) );
1757  assert( ( iChannel >= 0 ) && ( iChannel < m_pMainHeader->iNumChannels ) );
1758 
1759  if( ( iRecordIndex < 0 ) || ( iRecordIndex >= m_pMainHeader->iNumRecords ) ||
1760  ( iChannel < 0 ) || ( iChannel >= m_pMainHeader->iNumChannels ) )
1761  return DAFF_INVALID_INDEX;
1762 
1763  if( pfDest == NULL ) return DAFF_NO_ERROR;
1764 
1765  DAFFRecordChannelDescDefault* pDesc = reinterpret_cast< DAFFRecordChannelDescDefault* >( getRecordChannelDescPtr( iRecordIndex, iChannel ) );
1766  float* pfSrc = reinterpret_cast< float* >( reinterpret_cast< char* >( m_pDataBlock ) +pDesc->ui64DataOffset );
1767  memcpy( pfDest, pfSrc, 2 * m_pContentHeaderDFT->iNumDFTCoeffs*sizeof( float ) );
1768 
1769  return DAFF_NO_ERROR;
1770 }
1771 
1772 void* DAFFReaderImpl::getRecordChannelDescPtr( int iRecord, int iChannel ) const
1773 {
1774  // Relative to beginning of record descriptor block in bytes
1775  uint64_t uiRecordDescriptorOffset = iRecord * ( m_pMainHeader->iNumChannels * m_iRecordChannelDescSize ) + iChannel * m_iRecordChannelDescSize;
1776 
1777  // Check buffer overruns
1778  assert( uiRecordDescriptorOffset < m_pRecordDescriptorTable->ui64Size );
1779 
1780  // Return absolute position in memory by using pointer of record descriptor block pointer
1781  void* pPtr = ( ( char* ) m_pRecordDescriptorBlock ) + uiRecordDescriptorOffset;
1782  return pPtr;
1783 }
1784 
1785 int* DAFFReaderImpl::getRecordMetadataIndexPtr( int iRecord ) const
1786 {
1787  char* p = ( char* ) ( getRecordChannelDescPtr( iRecord, 0 ) );
1788  int* piMetaDataIndex = ( int* ) ( p ); // Index is at first position of descriptor struct
1789 
1790  return piMetaDataIndex;
1791 }
int getNumberOfRecords() const
Returns the overall number of records.
int getPhases(int iRecordIndex, int iChannel, float *pfData) const
Retrieves phase coefficients.
DAFF file format content header for phase spectra.
Definition: DAFFHeader.h:187
float fOrientPitch
@ Yaw angle of the orientation [°]
Definition: DAFFHeader.h:122
float getBetaResolution() const
float getAlphaEnd() const
File has unkown content type (IR, MS, DFT, etc)
Definition: DAFFDefs.h:99
void fixEndianness()
@ Roll angle of the orientation [°]
Definition: DAFFHeader.h:128
float fPitchAngleDeg
Pitch angle (degrees)
Definition: DAFFDefs.h:142
float fBetaStart
@ Number of measurement points in beta range [0°, 180°]
Definition: DAFFHeader.h:119
void getDefaultOrientation(DAFFOrientationYPR &o) const
Returns the default orientation as stored in the file.
Reader interface for DAFF files.
Definition: DAFFReader.h:116
int getRecordCoords(int iRecordIndex, int iView, float &fAngle1, float &fAngle2) const
Determines the spherical coordinates of a record (grid point on spherical regular grid) ...
void transformOSC2DSC(float azimuth_in, float elevation_in, float &alpha_out, float &beta_out) const
Transform coordinates from OSC -> DSC (including coordinate system rotation)
void fixEndianness()
@ Maximum effective Filterlength among all IRs
Definition: DAFFHeader.h:160
Discrete Fourier spectrum in the frequency-domain.
Definition: DAFFDefs.h:70
void fixEndianness()
@ Number of support frequencies
Definition: DAFFHeader.h:195
virtual int getTransformSize() const =0
Returns the size of the transform (number of overall DFT coefficients)
int getQuantization() const
Returns the quantization of the data elements.
void closeFile()
Closes an opened DAFF file.
int32_t iMinFilterOffset
@ Samplingrate [in Hertz]
Definition: DAFFHeader.h:155
Invalid alpha angles or range problem.
Definition: DAFFDefs.h:100
std::string getChannelLabel(int iChannel) const
Returns the label of a channel.
DAFF file format content header for magnitude spectra.
Definition: DAFFHeader.h:169
bool coversFullAlphaRange() const
Indicates whether the data covers the full alpha range [0°, 360°)
int32_t iLeadingZeros
@ Position inside the file where samples/coefficients reside (in bytes)
Definition: DAFFHeader.h:267
void fixEndianness()
@ Number of data values (length of element of record channel for a single channel, only)
Definition: DAFFHeader.h:272
No error = 0.
Definition: DAFFDefs.h:94
uint8_t pcSignature[2]
Definition: DAFFHeader.h:64
uint64_t ui64DataOffset
@ Index in metadata table (C-style indexing: beginning with 0)
Definition: DAFFHeader.h:250
Invalid index (e.g. record index)
Definition: DAFFDefs.h:108
void transformAnglesD2O(float fAlpha, float fBeta, float &fAzimuth, float &fElevation) const
Transforms data spherical coordinates into object spherical coordinates.
int getPhase(int iRecordIndex, int iChannel, int iFreqIndex, float &fPhase) const
Retrieves a single phase coefficient.
static void NormalizeDirection(int iView, float fAngle1DegIn, float fAngle2DegIn, float &fAngle1DegOut, float &fAngle2DegOut)
Normalize a direction (angular pair)
Definition: DAFFUtils.cpp:217
Common content interface.
Definition: DAFFContent.h:40
void fixEndianness()
@ Maximum magnitude value over all records/channels/frequencies
Definition: DAFFHeader.h:229
Pure data class that describes the points of a quad by their indices and coordinates.
Definition: DAFFDefs.h:122
void(* le2se_2byte)(void *src, size_t count)
Definition: Utils.cpp:100
void(* le2se_3byte)(void *src, size_t count)
Definition: Utils.cpp:101
Magnitude spectrum defined at discrete frequencies.
Definition: DAFFDefs.h:67
int addFilterCoeffs(int iRecordIndex, int iChannel, float *pfDest, float fGain=1.0F) const
Adds filter coefficients for record and channel to a given buffer.
File format version is not supported by this library version.
Definition: DAFFDefs.h:103
uint64_t ui64DataOffset
@ Index in metadata table (C-style indexing: beginning with 0)
Definition: DAFFHeader.h:266
int getMinEffectiveFilterOffset() const
Returns the minimal effective filter offset over all records.
int getFilterLength() const
Returns the number of filter coefficients.
void fixEndianness()
@ Number of file blocks
Definition: DAFFHeader.h:73
void setDefaultOrientation()
Sets/alters the default orientation manually.
float getOverallMagnitudeMaximum() const
Returns the overall greatest magnitude value.
int getMagnitudes(int iRecordIndex, int iChannel, float *pfData) const
Retrieves magnitude coefficients.
int32_t iElementLength
@ Offset of actual data within impulse response (leading zeros that are not included in DAFF data) ...
Definition: DAFFHeader.h:268
int load(void *pData, size_t &iBytesRead)
Invalid beta angles or range problem.
Definition: DAFFDefs.h:101
#define NULL
Definition: DAFFDefs.h:59
int getNumberOfChannels() const
Returns the number of channels.
int32_t iAlphaPoints
@ Index of global metadata
Definition: DAFFHeader.h:116
int getEffectiveFilterBounds(int iRecordIndex, int iChannel, int &iOffset, int &iLength) const
Retrieves the offset and length of the effective part of a filter.
int getTransformSize() const
Returns the size of the transform (number of overall DFT coefficients)
virtual int getFilterLength() const =0
Returns the number of filter coefficients.
void getOrientation(DAFFOrientationYPR &orient) const
Return the OSC->DSC orientation (yaw-pitch-roll)
virtual double getSamplerate() const =0
Returns the sampling rate [in Hertz].
bool isValid() const
int openFile(const std::string &)
Opens a DAFF file for reading.
Magnitude-phase spectrum defined at discrete frequencies.
Definition: DAFFDefs.h:69
static std::string StrQuantizationType(int iQuantizationType)
Returns a string corresponding to a quantization type.
Definition: DAFFUtils.cpp:205
int getFileFormatVersion() const
Returns the DAFF version of the file format.
const DAFFMetadata * getRecordMetadata(int iRecordIndex) const
Returns the metadata of a record.
void stc_sint16_to_float(float *dest, const short *src, size_t count, int input_stride, int output_stride, float gain)
Convert signed integer 16-Bit -> single precision floating point (32-Bit)
Definition: Utils.cpp:212
int getAlphaPoints() const
void stc_sint24_to_float(float *dest, const void *src, size_t count, int input_stride, int output_stride, float gain)
Convert signed integer 24-Bit -> single precision floating point (32-Bit)
Definition: Utils.cpp:225
Impulse response (IR) in the time-domain.
Definition: DAFFDefs.h:66
int32_t iElementsPerRecord
@ Overall number of records
Definition: DAFFHeader.h:113
int getMaxEffectiveFilterLength() const
Returns the maximum effective filter length over all records.
int iIndex1
First index point.
Definition: DAFFDefs.h:124
void transformAnglesO2D(float fAzimuth, float fElevation, float &fAlpha, float &fBeta) const
Transforms object spherical coordinates into data spherical coordinates.
int32_t iNumFileBlocks
@ (digits 0-2 => minor version, other digits => major version)
Definition: DAFFHeader.h:67
void setOrientation(const DAFFOrientationYPR &orient)
Sets the OSC->DSC orientation (yaw-pitch-roll)
float carg(float Re, float Im)
Definition: Utils.cpp:64
void fixEndianness()
@ Number of support frequencies
Definition: DAFFHeader.h:179
float fSamplerate
@ DFT transform size
Definition: DAFFHeader.h:224
This is the (pre) header of DAFF files.
Definition: DAFFHeader.h:61
DAFF file format content header for discrete Fourier spectra.
Definition: DAFFHeader.h:219
float getBetaEnd() const
int getEffectiveFilterCoeffs(int iRecordIndex, int iChannel, float *pfDest, float fGain=1.0F) const
Retrieves effective filter coefficients for record and channel.
float fMax
@ Samplingrate [in Hertz]
Definition: DAFFHeader.h:225
Modal error (e.g. close a file that is not opened)
Definition: DAFFDefs.h:96
float fAlphaStart
@ Number of measurement points in alpha range [0°, 360°)
Definition: DAFFHeader.h:117
int32_t iNumRecords
@ Number of channels
Definition: DAFFHeader.h:112
int32_t iFileFormatVersion
@ The magical signature
Definition: DAFFHeader.h:65
void stc_sint16_to_float_add(float *dest, const short *src, size_t count, int input_stride, int output_stride, float gain)
Definition: Utils.cpp:219
double getSamplerate() const
Returns the correspondig sampling rate [in Hertz].
float getAlphaStart() const
virtual int getAlphaPoints() const =0
void getNearestNeighbour(int iView, float fAngle1Deg, float fAngle2Deg, int &iRecordIndex) const
Determine the nearest neighbour record and return its index.
A file block entry.
Definition: DAFFHeader.h:82
int getDFTCoeffs(int iRecordIndex, int iChannel, float *pfDest) const
Retrieves magnitude coefficients.
int deserialize(char *pDAFFDataBuffer)
Deserializes DAFF content from a byte buffer.
static std::string Double2StrNice(double d, int precision, bool showpos, int leadingzeros=0)
Converts a double precision floating point into nice std::string.
Definition: DAFFUtils.cpp:49
int getNumFrequencies() const
Returns the number of support points (frequencies)
float fRollAngleDeg
Roll angle (degrees)
Definition: DAFFDefs.h:143
Data reading error of an otherwise valid DAFF file.
Definition: DAFFDefs.h:107
float getOverallPeak()
Get overall peak value.
virtual int getNumberOfRecords() const =0
Returns the overall number of records.
int32_t iTransformSize
@ Number of (stored) DFT coefficients (= complex elements per record)
Definition: DAFFHeader.h:223
std::string toString() const
Returns string with information about the reader.
std::string getFilename() const
Returns the name of the opened DAFF file.
float getBetaSpan() const
int32_t iQuantization
@ Identificator of the database content type
Definition: DAFFHeader.h:110
Content parameter invalid (sampling rate, num supporting frequencies, etc)
Definition: DAFFDefs.h:104
16-Bit signed integer
Definition: DAFFDefs.h:77
Invalid DAFF file, i.e. wrong signature.
Definition: DAFFDefs.h:97
float anglef_mindiff_abs_0_360_DEG(float alpha, float beta)
Definition: Utils.cpp:53
bool isSymmetric() const
Returns whether the spectrum is complex-conjugated symmetric.
float getBetaStart() const
int getBetaPoints() const
int32_t iNumFreqs
@ Maximum magnitude value over all records/channels/frequencies
Definition: DAFFHeader.h:206
bool isFileOpened() const
Returns whether a file is opened.
float fYawAngleDeg
Yaw angle (degrees)
Definition: DAFFDefs.h:141
32-Bit floating point
Definition: DAFFDefs.h:79
Impulse response content interface.
Definition: DAFFContentIR.h:38
uint64_t ui64Offset
Definition: DAFFHeader.h:86
const std::vector< float > & getFrequencies() const
Retrieves the frequencies [in Hertz] at which values are defined.
void fixEndianness()
@ Position inside the file where samples/coefficients reside
Definition: DAFFHeader.h:254
void(* le2se_4byte)(void *src, size_t count)
Definition: Utils.cpp:102
double getFrequencyBandwidth() const
Returns the frequency resolution [in Hertz].
const DAFFMetadata * getMetadata() const
Returns the metadata.
int iIndex3
Third index point.
Definition: DAFFDefs.h:126
int iIndex2
Second index point.
Definition: DAFFDefs.h:125
int getMagnitude(int iRecordIndex, int iChannel, int iFreqIndex, float &fMag) const
Retrieves a single magnitude coefficient.
virtual bool isSymmetric() const =0
Returns whether the spectrum is complex-conjugated symmetric.
int getCoefficientsRI(int iRecordIndex, int iChannel, float *pfDest) const
Retrieves coefficients in cartesian form.
float cabs(float Re, float Im)
Definition: Utils.cpp:60
Metadata interface.
Definition: DAFFMetadata.h:31
float getAlphaResolution() const
Discrete Fourier spectrum content interface.
Data uses unrecognized or wrong quantization.
Definition: DAFFDefs.h:102
int getNumDFTCoeffs() const
Returns the number of DFT coefficients.
virtual bool coversFullSphere() const =0
Indicates whether the data covers the full sphere.
24-Bit signed integer
Definition: DAFFDefs.h:78
int iIndex4
Fourth index point.
Definition: DAFFDefs.h:127
static std::string StrContentType(int iContentType)
Returns a string corresponding to a content type.
Definition: DAFFUtils.cpp:166
File not found.
Definition: DAFFDefs.h:105
DAFF file format content header for impulse responses.
Definition: DAFFHeader.h:151
virtual int getBetaPoints() const =0
DAFFProperties * getProperties() const
Returns the properties of the file.
int32_t iMaxEffectiveFilterLength
@ Minimum offset (number of leading zeros) among all IRs
Definition: DAFFHeader.h:156
Properties of a DAFF file that uses regular sphere grids (or parts of a regular grid) ...
void * malloc_aligned16(size_t bytes)
Definition: Utils.cpp:185
Phase spectrum defined at discrete frequencies.
Definition: DAFFDefs.h:68
int32_t iNumChannels
@ Quantization of samples/coefficients
Definition: DAFFHeader.h:111
File has invalid main header parameter (num channels, etc)
Definition: DAFFDefs.h:98
int getContentType() const
Returns the content type.
int getCoefficientsMP(int iRecordIndex, int iChannel, float *pfDest) const
Retrieves coefficients in polar form.
void setOrientation(const DAFFOrientationYPR &o)
Sets the current orientation of the object view.
virtual double getSamplerate() const =0
Returns the correspondig sampling rate [in Hertz].
static std::string Float2StrNice(float f, int precision, bool showpos, int leadingzeros=0)
Converts a single precision floating point into nice std::string.
Definition: DAFFUtils.cpp:27
uint64_t ui64Size
Definition: DAFFHeader.h:87
void stc_sint24_to_float_add(float *dest, const void *src, size_t count, int input_stride, int output_stride, float gain)
Definition: Utils.cpp:276
int getFilterCoeffs(int iRecordIndex, int iChannel, float *pfDest, float fGain=1.0F) const
Retrieves filter coefficients for record and channel.
int32_t iNumFreqs
@ Maximum magnitude value over all records/channels/frequencies
Definition: DAFFHeader.h:173
int getDFTCoeff(int iRecordIndex, int iChannel, int iDFTCoeff, float &fReal, float &fImag) const
Retrieve a single magnitude coefficient.
DAFFContent * getContent() const
Returns the content.
float getAlphaSpan() const
virtual int getNumberOfChannels() const =0
Returns the number of channels.
void transformDSC2OSC(float alpha_in, float beta_in, float &azimuth_out, float &elevation_out) const
Transform coordinates from DSC -> OSC (including coordinate system rotation)
void fixEndianness()
@ Number of support frequencies
Definition: DAFFHeader.h:211
void getCell(int iView, float fAngle1, float fAngle2, DAFFQuad &qIndices) const
Determines the cell of a given direction on the sphere grid and delivers its surrounding record indic...
Data class for orientations in yaw-pitch-roll (YPR) angles (right-handed OpenGL coordinate system) ...
Definition: DAFFDefs.h:138
bool coversFullSphere() const
Indicates whether the data covers the full sphere.
int32_t iBetaPoints
@ Alpha range boundaries
Definition: DAFFHeader.h:118
DAFFReader * getParent() const
Returns the parent reader.
void getOrientation(DAFFOrientationYPR &o) const
Returns the current orientation of the object view.
void free_aligned16(void *ptr)
Definition: Utils.cpp:201
int addEffectiveFilterCoeffs(int iRecordIndex, int iChannel, float *pfDest, float fGain=1.0F) const
Adds effective filter coefficients for record and channel to a given buffer.
float fOrientRoll
@ Pitch angle of the orientation [°]
Definition: DAFFHeader.h:123
DAFF file format content header for magnitude-phase spectra.
Definition: DAFFHeader.h:202
Data-related view referring to data spherical coordinates (DSC)
Definition: DAFFDefs.h:86
Record channel descriptor: impulse responses content.
Definition: DAFFHeader.h:262
bool coversFullBetaRange() const
Indicates whether the data covers the full beta range [0°, 180°].
Object-related view referring to object spherical coordinates (OSC)
Definition: DAFFDefs.h:87
float fOrientYaw
@ Beta range boundaries
Definition: DAFFHeader.h:121
int32_t iContentType
Definition: DAFFHeader.h:109
OpenDAFF is a project from the Institute of Technical Acoustics, RWTH Aachen University, Germany.