Browse Source

Add the rest of the juce modules

tags/1.9.4
falkTX 12 years ago
parent
commit
b540208353
100 changed files with 44826 additions and 0 deletions
  1. +28
    -0
      source/modules/juce_audio_devices.h
  2. +79
    -0
      source/modules/juce_audio_devices/AppConfig.h
  3. +88
    -0
      source/modules/juce_audio_devices/Makefile
  4. +169
    -0
      source/modules/juce_audio_devices/audio_cd/juce_AudioCDBurner.h
  5. +57
    -0
      source/modules/juce_audio_devices/audio_cd/juce_AudioCDReader.cpp
  6. +174
    -0
      source/modules/juce_audio_devices/audio_cd/juce_AudioCDReader.h
  7. +968
    -0
      source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  8. +510
    -0
      source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h
  9. +48
    -0
      source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp
  10. +332
    -0
      source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h
  11. +78
    -0
      source/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp
  12. +182
    -0
      source/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h
  13. +61
    -0
      source/modules/juce_audio_devices/audio_io/juce_SystemAudioVolume.h
  14. +226
    -0
      source/modules/juce_audio_devices/juce_audio_devices.cpp
  15. +117
    -0
      source/modules/juce_audio_devices/juce_audio_devices.h
  16. +25
    -0
      source/modules/juce_audio_devices/juce_audio_devices.mm
  17. +28
    -0
      source/modules/juce_audio_devices/juce_module_info
  18. +182
    -0
      source/modules/juce_audio_devices/midi_io/juce_MidiInput.h
  19. +153
    -0
      source/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp
  20. +104
    -0
      source/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.h
  21. +162
    -0
      source/modules/juce_audio_devices/midi_io/juce_MidiOutput.cpp
  22. +147
    -0
      source/modules/juce_audio_devices/midi_io/juce_MidiOutput.h
  23. +175
    -0
      source/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h
  24. +443
    -0
      source/modules/juce_audio_devices/native/juce_android_Audio.cpp
  25. +84
    -0
      source/modules/juce_audio_devices/native/juce_android_Midi.cpp
  26. +622
    -0
      source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp
  27. +555
    -0
      source/modules/juce_audio_devices/native/juce_ios_Audio.cpp
  28. +1237
    -0
      source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp
  29. +77
    -0
      source/modules/juce_audio_devices/native/juce_linux_AudioCDReader.cpp
  30. +590
    -0
      source/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp
  31. +610
    -0
      source/modules/juce_audio_devices/native/juce_linux_Midi.cpp
  32. +491
    -0
      source/modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm
  33. +261
    -0
      source/modules/juce_audio_devices/native/juce_mac_AudioCDReader.mm
  34. +1336
    -0
      source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
  35. +528
    -0
      source/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp
  36. +1638
    -0
      source/modules/juce_audio_devices/native/juce_win32_ASIO.cpp
  37. +411
    -0
      source/modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp
  38. +1309
    -0
      source/modules/juce_audio_devices/native/juce_win32_AudioCDReader.cpp
  39. +1288
    -0
      source/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp
  40. +483
    -0
      source/modules/juce_audio_devices/native/juce_win32_Midi.cpp
  41. +1511
    -0
      source/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp
  42. +183
    -0
      source/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp
  43. +116
    -0
      source/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h
  44. +300
    -0
      source/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp
  45. +186
    -0
      source/modules/juce_audio_devices/sources/juce_AudioTransportSource.h
  46. +26
    -0
      source/modules/juce_audio_formats.h
  47. +53
    -0
      source/modules/juce_audio_formats/AppConfig.h
  48. +88
    -0
      source/modules/juce_audio_formats/Makefile
  49. +49
    -0
      source/modules/juce_audio_formats/codecs/flac/Flac Licence.txt
  50. +402
    -0
      source/modules/juce_audio_formats/codecs/flac/all.h
  51. +212
    -0
      source/modules/juce_audio_formats/codecs/flac/alloc.h
  52. +45
    -0
      source/modules/juce_audio_formats/codecs/flac/assert.h
  53. +184
    -0
      source/modules/juce_audio_formats/codecs/flac/callback.h
  54. +91
    -0
      source/modules/juce_audio_formats/codecs/flac/export.h
  55. +1010
    -0
      source/modules/juce_audio_formats/codecs/flac/format.h
  56. +149
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/bitmath.c
  57. +1350
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/bitreader.c
  58. +880
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/bitwriter.c
  59. +418
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/cpu.c
  60. +142
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/crc.c
  61. +435
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/fixed.c
  62. +308
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/float.c
  63. +598
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/format.c
  64. +49
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/all.h
  65. +42
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/bitmath.h
  66. +99
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/bitreader.h
  67. +103
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/bitwriter.h
  68. +88
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/cpu.h
  69. +61
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/crc.h
  70. +97
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/fixed.h
  71. +97
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/float.h
  72. +44
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/format.h
  73. +214
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/lpc.h
  74. +44
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/md5.h
  75. +56
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/memory.h
  76. +45
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/metadata.h
  77. +45
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/stream_encoder_framing.h
  78. +71
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/window.h
  79. +38
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/protected/all.h
  80. +58
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/protected/stream_decoder.h
  81. +110
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/include/protected/stream_encoder.h
  82. +1376
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/lpc_flac.c
  83. +425
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/md5.c
  84. +206
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/memory.c
  85. +3384
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/stream_decoder.c
  86. +4362
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/stream_encoder.c
  87. +553
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/stream_encoder_framing.c
  88. +225
    -0
      source/modules/juce_audio_formats/codecs/flac/libFLAC/window_flac.c
  89. +2181
    -0
      source/modules/juce_audio_formats/codecs/flac/metadata.h
  90. +80
    -0
      source/modules/juce_audio_formats/codecs/flac/ordinals.h
  91. +1559
    -0
      source/modules/juce_audio_formats/codecs/flac/stream_decoder.h
  92. +1768
    -0
      source/modules/juce_audio_formats/codecs/flac/stream_encoder.h
  93. +957
    -0
      source/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp
  94. +84
    -0
      source/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.h
  95. +528
    -0
      source/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp
  96. +77
    -0
      source/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.h
  97. +545
    -0
      source/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp
  98. +65
    -0
      source/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.h
  99. +227
    -0
      source/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp
  100. +71
    -0
      source/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.h

+ 28
- 0
source/modules/juce_audio_devices.h View File

@@ -0,0 +1,28 @@
/*
* Carla Juce setup
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/

#ifndef CARLA_JUCE_AUDIO_DEVICES_H_INCLUDED
#define CARLA_JUCE_AUDIO_DEVICES_H_INCLUDED

#include "juce_events.h"
#include "juce_audio_basics.h"
#include "juce_audio_formats.h"

#include "juce_audio_devices/AppConfig.h"
#include "juce_audio_devices/juce_audio_devices.h"

#endif // CARLA_JUCE_AUDIO_DEVICES_H_INCLUDED

+ 79
- 0
source/modules/juce_audio_devices/AppConfig.h View File

@@ -0,0 +1,79 @@
/*
==============================================================================
Build options for juce_audio_devices static library
==============================================================================
*/
#ifndef CARLA_JUCE_AUDIO_DEVICES_APPCONFIG_H_INCLUDED
#define CARLA_JUCE_AUDIO_DEVICES_APPCONFIG_H_INCLUDED
#include "../juce_events/AppConfig.h"
#include "../juce_audio_basics/AppConfig.h"
#include "../juce_audio_formats/AppConfig.h"
//=============================================================================
/** Config: JUCE_ASIO
Enables ASIO audio devices (MS Windows only).
Turning this on means that you'll need to have the Steinberg ASIO SDK installed
on your Windows build machine.
See the comments in the ASIOAudioIODevice class's header file for more
info about this.
*/
#if WINDOWS
#define JUCE_ASIO 1
#else
#define JUCE_ASIO 0
#endif
/** Config: JUCE_WASAPI
Enables WASAPI audio devices (Windows Vista and above).
*/
#define JUCE_WASAPI 0
/** Config: JUCE_DIRECTSOUND
Enables DirectSound audio (MS Windows only).
*/
#if WINDOWS
#define JUCE_DIRECTSOUND 1
#else
#define JUCE_DIRECTSOUND 0
#endif
/** Config: JUCE_ALSA
Enables ALSA audio devices (Linux only).
*/
#if LINUX
#define JUCE_ALSA 1
#define JUCE_ALSA_MIDI_INPUT_NAME "Carla"
#define JUCE_ALSA_MIDI_OUTPUT_NAME "Carla"
#define JUCE_ALSA_MIDI_INPUT_PORT_NAME "Midi In"
#define JUCE_ALSA_MIDI_OUTPUT_PORT_NAME "Midi Out"
#else
#define JUCE_ALSA 0
#endif
/** Config: JUCE_JACK
Enables JACK audio devices (Linux only).
*/
#if LINUX
#define JUCE_JACK 1
#define JUCE_JACK_CLIENT_NAME "Carla"
#else
#define JUCE_JACK 0
#endif
//=============================================================================
/** Config: JUCE_USE_CDREADER
Enables the AudioCDReader class (on supported platforms).
*/
#define JUCE_USE_CDREADER 0
/** Config: JUCE_USE_CDBURNER
Enables the AudioCDBurner class (on supported platforms).
*/
#define JUCE_USE_CDBURNER 0
#endif // CARLA_JUCE_AUDIO_DEVICES_APPCONFIG_H_INCLUDED

+ 88
- 0
source/modules/juce_audio_devices/Makefile View File

@@ -0,0 +1,88 @@
#!/usr/bin/make -f
# Makefile for juce_audio_devices #
# ------------------------------- #
# Created by falkTX
#

include ../../Makefile.mk

# --------------------------------------------------------------

BUILD_CXX_FLAGS += -I.

ifeq ($(MACOS),true)
BUILD_CXX_FLAGS += -objc++
OBJS = juce_audio_devices.mm.o
OBJS_posix32 = juce_audio_devices.mm.posix32.o
OBJS_posix64 = juce_audio_devices.mm.posix64.o
else
OBJS = juce_audio_devices.cpp.o
OBJS_posix32 = juce_audio_devices.cpp.posix32.o
OBJS_posix64 = juce_audio_devices.cpp.posix64.o
endif

OBJS_win32 = juce_audio_devices.cpp.win32.o
OBJS_win64 = juce_audio_devices.cpp.win64.o

# --------------------------------------------------------------

all: ../juce_audio_devices.a

posix32: ../juce_audio_devices.posix32.a
posix64: ../juce_audio_devices.posix64.a
win32: ../juce_audio_devices.win32.a
win64: ../juce_audio_devices.win64.a

# --------------------------------------------------------------

../juce_audio_devices.a: $(OBJS)
$(AR) rs $@ $^

../juce_audio_devices.posix32.a: $(OBJS_posix32)
$(AR) rs $@ $^

../juce_audio_devices.posix64.a: $(OBJS_posix64)
$(AR) rs $@ $^

../juce_audio_devices.win32.a: $(OBJS_win32)
$(AR) rs $@ $^

../juce_audio_devices.win64.a: $(OBJS_win64)
$(AR) rs $@ $^

../juce_audio_devices.dll: $(OBJS)
$(CXX) $^ -shared $(LINK_FLAGS) -o $@

../juce_audio_devices.dylib: $(OBJS)
$(CXX) $^ -dynamiclib $(LINK_FLAGS) -o $@

../juce_audio_devices.so: $(OBJS)
$(CXX) $^ -shared $(LINK_FLAGS) -o $@

# --------------------------------------------------------------

%.cpp.o: %.cpp
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

%.mm.o: %.mm
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

%.posix32.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@

%.posix64.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@

%.win32.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@

%.win64.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@

# --------------------------------------------------------------

clean:
rm -f *.o ../juce_audio_devices*.a

debug:
$(MAKE) DEBUG=true

+ 169
- 0
source/modules/juce_audio_devices/audio_cd/juce_AudioCDBurner.h View File

@@ -0,0 +1,169 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOCDBURNER_H_INCLUDED
#define JUCE_AUDIOCDBURNER_H_INCLUDED
#if JUCE_USE_CDBURNER || DOXYGEN
//==============================================================================
/**
*/
class AudioCDBurner : public ChangeBroadcaster
{
public:
//==============================================================================
/** Returns a list of available optical drives.
Use openDevice() to open one of the items from this list.
*/
static StringArray findAvailableDevices();
/** Tries to open one of the optical drives.
The deviceIndex is an index into the array returned by findAvailableDevices().
*/
static AudioCDBurner* openDevice (const int deviceIndex);
/** Destructor. */
~AudioCDBurner();
//==============================================================================
enum DiskState
{
unknown, /**< An error condition, if the device isn't responding. */
trayOpen, /**< The drive is currently open. Note that a slot-loading drive
may seem to be permanently open. */
noDisc, /**< The drive has no disk in it. */
writableDiskPresent, /**< The drive contains a writeable disk. */
readOnlyDiskPresent /**< The drive contains a read-only disk. */
};
/** Returns the current status of the device.
To get informed when the drive's status changes, attach a ChangeListener to
the AudioCDBurner.
*/
DiskState getDiskState() const;
/** Returns true if there's a writable disk in the drive. */
bool isDiskPresent() const;
/** Sends an eject signal to the drive.
The eject will happen asynchronously, so you can use getDiskState() and
waitUntilStateChange() to monitor its progress.
*/
bool openTray();
/** Blocks the current thread until the drive's state changes, or until the timeout expires.
@returns the device's new state
*/
DiskState waitUntilStateChange (int timeOutMilliseconds);
//==============================================================================
/** Returns the set of possible write speeds that the device can handle.
These are as a multiple of 'normal' speed, so e.g. '24x' returns 24, etc.
Note that if there's no media present in the drive, this value may be unavailable!
@see setWriteSpeed, getWriteSpeed
*/
Array<int> getAvailableWriteSpeeds() const;
//==============================================================================
/** Tries to enable or disable buffer underrun safety on devices that support it.
@returns true if it's now enabled. If the device doesn't support it, this
will always return false.
*/
bool setBufferUnderrunProtection (bool shouldBeEnabled);
//==============================================================================
/** Returns the number of free blocks on the disk.
There are 75 blocks per second, at 44100Hz.
*/
int getNumAvailableAudioBlocks() const;
/** Adds a track to be written.
The source passed-in here will be kept by this object, and it will
be used and deleted at some point in the future, either during the
burn() method or when this AudioCDBurner object is deleted. Your caller
method shouldn't keep a reference to it or use it again after passing
it in here.
*/
bool addAudioTrack (AudioSource* source, int numSamples);
//==============================================================================
/** Receives progress callbacks during a cd-burn operation.
@see AudioCDBurner::burn()
*/
class BurnProgressListener
{
public:
BurnProgressListener() noexcept {}
virtual ~BurnProgressListener() {}
/** Called at intervals to report on the progress of the AudioCDBurner.
To cancel the burn, return true from this method.
*/
virtual bool audioCDBurnProgress (float proportionComplete) = 0;
};
/** Runs the burn process.
This method will block until the operation is complete.
@param listener the object to receive callbacks about progress
@param ejectDiscAfterwards whether to eject the disk after the burn completes
@param performFakeBurnForTesting if true, no data will actually be written to the disk
@param writeSpeed one of the write speeds from getAvailableWriteSpeeds(), or
0 or less to mean the fastest speed.
*/
String burn (BurnProgressListener* listener,
bool ejectDiscAfterwards,
bool performFakeBurnForTesting,
int writeSpeed);
/** If a burn operation is currently in progress, this tells it to stop
as soon as possible.
It's also possible to stop the burn process by returning true from
BurnProgressListener::audioCDBurnProgress()
*/
void abortBurn();
private:
//==============================================================================
AudioCDBurner (const int deviceIndex);
class Pimpl;
friend struct ContainerDeletePolicy<Pimpl>;
ScopedPointer<Pimpl> pimpl;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioCDBurner)
};
#endif
#endif // JUCE_AUDIOCDBURNER_H_INCLUDED

+ 57
- 0
source/modules/juce_audio_devices/audio_cd/juce_AudioCDReader.cpp View File

@@ -0,0 +1,57 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_USE_CDREADER
int AudioCDReader::getNumTracks() const
{
return trackStartSamples.size() - 1;
}
int AudioCDReader::getPositionOfTrackStart (int trackNum) const
{
return trackStartSamples [trackNum];
}
const Array<int>& AudioCDReader::getTrackOffsets() const
{
return trackStartSamples;
}
int AudioCDReader::getCDDBId()
{
int checksum = 0;
const int numTracks = getNumTracks();
for (int i = 0; i < numTracks; ++i)
for (int offset = (trackStartSamples.getUnchecked(i) + 88200) / 44100; offset > 0; offset /= 10)
checksum += offset % 10;
const int length = (trackStartSamples.getLast() - trackStartSamples.getFirst()) / 44100;
// CCLLLLTT: checksum, length, tracks
return ((checksum & 0xff) << 24) | (length << 8) | numTracks;
}
#endif

+ 174
- 0
source/modules/juce_audio_devices/audio_cd/juce_AudioCDReader.h View File

@@ -0,0 +1,174 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOCDREADER_H_INCLUDED
#define JUCE_AUDIOCDREADER_H_INCLUDED
#if JUCE_USE_CDREADER || DOXYGEN
//==============================================================================
/**
A type of AudioFormatReader that reads from an audio CD.
One of these can be used to read a CD as if it's one big audio stream. Use the
getPositionOfTrackStart() method to find where the individual tracks are
within the stream.
@see AudioFormatReader
*/
class JUCE_API AudioCDReader : public AudioFormatReader
{
public:
//==============================================================================
/** Returns a list of names of Audio CDs currently available for reading.
If there's a CD drive but no CD in it, this might return an empty list, or
possibly a device that can be opened but which has no tracks, depending
on the platform.
@see createReaderForCD
*/
static StringArray getAvailableCDNames();
/** Tries to create an AudioFormatReader that can read from an Audio CD.
@param index the index of one of the available CDs - use getAvailableCDNames()
to find out how many there are.
@returns a new AudioCDReader object, or nullptr if it couldn't be created. The
caller will be responsible for deleting the object returned.
*/
static AudioCDReader* createReaderForCD (const int index);
//==============================================================================
/** Destructor. */
~AudioCDReader();
/** Implementation of the AudioFormatReader method. */
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) override;
/** Checks whether the CD has been removed from the drive. */
bool isCDStillPresent() const;
/** Returns the total number of tracks (audio + data). */
int getNumTracks() const;
/** Finds the sample offset of the start of a track.
@param trackNum the track number, where trackNum = 0 is the first track
and trackNum = getNumTracks() means the end of the CD.
*/
int getPositionOfTrackStart (int trackNum) const;
/** Returns true if a given track is an audio track.
@param trackNum the track number, where 0 is the first track.
*/
bool isTrackAudio (int trackNum) const;
/** Returns an array of sample offsets for the start of each track, followed by
the sample position of the end of the CD.
*/
const Array<int>& getTrackOffsets() const;
/** Refreshes the object's table of contents.
If the disc has been ejected and a different one put in since this
object was created, this will cause it to update its idea of how many tracks
there are, etc.
*/
void refreshTrackLengths();
/** Enables scanning for indexes within tracks.
@see getLastIndex
*/
void enableIndexScanning (bool enabled);
/** Returns the index number found during the last read() call.
Index scanning is turned off by default - turn it on with enableIndexScanning().
Then when the read() method is called, if it comes across an index within that
block, the index number is stored and returned by this method.
Some devices might not support indexes, of course.
(If you don't know what CD indexes are, it's unlikely you'll ever need them).
@see enableIndexScanning
*/
int getLastIndex() const;
/** Scans a track to find the position of any indexes within it.
@param trackNumber the track to look in, where 0 is the first track on the disc
@returns an array of sample positions of any index points found (not including
the index that marks the start of the track)
*/
Array<int> findIndexesInTrack (const int trackNumber);
/** Returns the CDDB id number for the CD.
It's not a great way of identifying a disc, but it's traditional.
*/
int getCDDBId();
/** Tries to eject the disk.
Ejecting the disk might not actually be possible, e.g. if some other process is using it.
*/
void ejectDisk();
//==============================================================================
enum
{
framesPerSecond = 75,
samplesPerFrame = 44100 / framesPerSecond
};
private:
//==============================================================================
Array<int> trackStartSamples;
#if JUCE_MAC
File volumeDir;
Array<File> tracks;
int currentReaderTrack;
ScopedPointer <AudioFormatReader> reader;
AudioCDReader (const File& volume);
#elif JUCE_WINDOWS
bool audioTracks [100];
void* handle;
MemoryBlock buffer;
bool indexingEnabled;
int lastIndex, firstFrameInBuffer, samplesInBuffer;
AudioCDReader (void* handle);
int getIndexAt (int samplePos);
#elif JUCE_LINUX
AudioCDReader();
#endif
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioCDReader)
};
#endif
#endif // JUCE_AUDIOCDREADER_H_INCLUDED

+ 968
- 0
source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp View File

@@ -0,0 +1,968 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioDeviceManager::AudioDeviceSetup::AudioDeviceSetup()
: sampleRate (0),
bufferSize (0),
useDefaultInputChannels (true),
useDefaultOutputChannels (true)
{
}
bool AudioDeviceManager::AudioDeviceSetup::operator== (const AudioDeviceManager::AudioDeviceSetup& other) const
{
return outputDeviceName == other.outputDeviceName
&& inputDeviceName == other.inputDeviceName
&& sampleRate == other.sampleRate
&& bufferSize == other.bufferSize
&& inputChannels == other.inputChannels
&& useDefaultInputChannels == other.useDefaultInputChannels
&& outputChannels == other.outputChannels
&& useDefaultOutputChannels == other.useDefaultOutputChannels;
}
//==============================================================================
class AudioDeviceManager::CallbackHandler : public AudioIODeviceCallback,
public MidiInputCallback,
public AudioIODeviceType::Listener
{
public:
CallbackHandler (AudioDeviceManager& adm) noexcept : owner (adm) {}
private:
void audioDeviceIOCallback (const float** ins, int numIns, float** outs, int numOuts, int numSamples) override
{
owner.audioDeviceIOCallbackInt (ins, numIns, outs, numOuts, numSamples);
}
void audioDeviceAboutToStart (AudioIODevice* device) override
{
owner.audioDeviceAboutToStartInt (device);
}
void audioDeviceStopped() override
{
owner.audioDeviceStoppedInt();
}
void audioDeviceError (const String& message) override
{
owner.audioDeviceErrorInt (message);
}
void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message) override
{
owner.handleIncomingMidiMessageInt (source, message);
}
void audioDeviceListChanged() override
{
owner.audioDeviceListChanged();
}
AudioDeviceManager& owner;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackHandler)
};
//==============================================================================
AudioDeviceManager::AudioDeviceManager()
: numInputChansNeeded (0),
numOutputChansNeeded (2),
listNeedsScanning (true),
useInputNames (false),
inputLevel (0),
testSoundPosition (0),
tempBuffer (2, 2),
cpuUsageMs (0),
timeToCpuScale (0)
{
callbackHandler = new CallbackHandler (*this);
}
AudioDeviceManager::~AudioDeviceManager()
{
currentAudioDevice = nullptr;
defaultMidiOutput = nullptr;
}
//==============================================================================
void AudioDeviceManager::createDeviceTypesIfNeeded()
{
if (availableDeviceTypes.size() == 0)
{
OwnedArray <AudioIODeviceType> types;
createAudioDeviceTypes (types);
for (int i = 0; i < types.size(); ++i)
addAudioDeviceType (types.getUnchecked(i));
types.clear (false);
if (AudioIODeviceType* first = availableDeviceTypes.getFirst())
currentDeviceType = first->getTypeName();
}
}
const OwnedArray <AudioIODeviceType>& AudioDeviceManager::getAvailableDeviceTypes()
{
scanDevicesIfNeeded();
return availableDeviceTypes;
}
void AudioDeviceManager::audioDeviceListChanged()
{
if (currentAudioDevice != nullptr)
{
currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
}
sendChangeMessage();
}
//==============================================================================
static void addIfNotNull (OwnedArray <AudioIODeviceType>& list, AudioIODeviceType* const device)
{
if (device != nullptr)
list.add (device);
}
void AudioDeviceManager::createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& list)
{
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_DirectSound());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_OpenSLES());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Android());
}
void AudioDeviceManager::addAudioDeviceType (AudioIODeviceType* newDeviceType)
{
if (newDeviceType != nullptr)
{
jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());
availableDeviceTypes.add (newDeviceType);
lastDeviceTypeConfigs.add (new AudioDeviceSetup());
newDeviceType->addListener (callbackHandler);
}
}
//==============================================================================
String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
const int numOutputChannelsNeeded,
const XmlElement* const e,
const bool selectDefaultDeviceOnFailure,
const String& preferredDefaultDeviceName,
const AudioDeviceSetup* preferredSetupOptions)
{
scanDevicesIfNeeded();
numInputChansNeeded = numInputChannelsNeeded;
numOutputChansNeeded = numOutputChannelsNeeded;
if (e != nullptr && e->hasTagName ("DEVICESETUP"))
{
lastExplicitSettings = new XmlElement (*e);
String error;
AudioDeviceSetup setup;
if (preferredSetupOptions != nullptr)
setup = *preferredSetupOptions;
if (e->getStringAttribute ("audioDeviceName").isNotEmpty())
{
setup.inputDeviceName = setup.outputDeviceName
= e->getStringAttribute ("audioDeviceName");
}
else
{
setup.inputDeviceName = e->getStringAttribute ("audioInputDeviceName");
setup.outputDeviceName = e->getStringAttribute ("audioOutputDeviceName");
}
currentDeviceType = e->getStringAttribute ("deviceType");
if (findType (currentDeviceType) == nullptr)
{
if (AudioIODeviceType* const type = findType (setup.inputDeviceName, setup.outputDeviceName))
currentDeviceType = type->getTypeName();
else if (availableDeviceTypes.size() > 0)
currentDeviceType = availableDeviceTypes.getUnchecked(0)->getTypeName();
}
setup.bufferSize = e->getIntAttribute ("audioDeviceBufferSize");
setup.sampleRate = e->getDoubleAttribute ("audioDeviceRate");
setup.inputChannels .parseString (e->getStringAttribute ("audioDeviceInChans", "11"), 2);
setup.outputChannels.parseString (e->getStringAttribute ("audioDeviceOutChans", "11"), 2);
setup.useDefaultInputChannels = ! e->hasAttribute ("audioDeviceInChans");
setup.useDefaultOutputChannels = ! e->hasAttribute ("audioDeviceOutChans");
error = setAudioDeviceSetup (setup, true);
midiInsFromXml.clear();
forEachXmlChildElementWithTagName (*e, c, "MIDIINPUT")
midiInsFromXml.add (c->getStringAttribute ("name"));
const StringArray allMidiIns (MidiInput::getDevices());
for (int i = allMidiIns.size(); --i >= 0;)
setMidiInputEnabled (allMidiIns[i], midiInsFromXml.contains (allMidiIns[i]));
if (error.isNotEmpty() && selectDefaultDeviceOnFailure)
error = initialise (numInputChannelsNeeded, numOutputChannelsNeeded, 0,
false, preferredDefaultDeviceName);
setDefaultMidiOutput (e->getStringAttribute ("defaultMidiOutput"));
return error;
}
else
{
AudioDeviceSetup setup;
if (preferredSetupOptions != nullptr)
{
setup = *preferredSetupOptions;
}
else if (preferredDefaultDeviceName.isNotEmpty())
{
for (int j = availableDeviceTypes.size(); --j >= 0;)
{
AudioIODeviceType* const type = availableDeviceTypes.getUnchecked(j);
const StringArray outs (type->getDeviceNames (false));
for (int i = 0; i < outs.size(); ++i)
{
if (outs[i].matchesWildcard (preferredDefaultDeviceName, true))
{
setup.outputDeviceName = outs[i];
break;
}
}
const StringArray ins (type->getDeviceNames (true));
for (int i = 0; i < ins.size(); ++i)
{
if (ins[i].matchesWildcard (preferredDefaultDeviceName, true))
{
setup.inputDeviceName = ins[i];
break;
}
}
}
}
insertDefaultDeviceNames (setup);
return setAudioDeviceSetup (setup, false);
}
}
void AudioDeviceManager::insertDefaultDeviceNames (AudioDeviceSetup& setup) const
{
if (AudioIODeviceType* type = getCurrentDeviceTypeObject())
{
if (setup.outputDeviceName.isEmpty())
setup.outputDeviceName = type->getDeviceNames (false) [type->getDefaultDeviceIndex (false)];
if (setup.inputDeviceName.isEmpty())
setup.inputDeviceName = type->getDeviceNames (true) [type->getDefaultDeviceIndex (true)];
}
}
XmlElement* AudioDeviceManager::createStateXml() const
{
return lastExplicitSettings.createCopy();
}
//==============================================================================
void AudioDeviceManager::scanDevicesIfNeeded()
{
if (listNeedsScanning)
{
listNeedsScanning = false;
createDeviceTypesIfNeeded();
for (int i = availableDeviceTypes.size(); --i >= 0;)
availableDeviceTypes.getUnchecked(i)->scanForDevices();
}
}
AudioIODeviceType* AudioDeviceManager::findType (const String& typeName)
{
scanDevicesIfNeeded();
for (int i = availableDeviceTypes.size(); --i >= 0;)
if (availableDeviceTypes.getUnchecked(i)->getTypeName() == typeName)
return availableDeviceTypes.getUnchecked(i);
return nullptr;
}
AudioIODeviceType* AudioDeviceManager::findType (const String& inputName, const String& outputName)
{
scanDevicesIfNeeded();
for (int i = availableDeviceTypes.size(); --i >= 0;)
{
AudioIODeviceType* const type = availableDeviceTypes.getUnchecked(i);
if ((inputName.isNotEmpty() && type->getDeviceNames (true).contains (inputName, true))
|| (outputName.isNotEmpty() && type->getDeviceNames (false).contains (outputName, true)))
{
return type;
}
}
return nullptr;
}
void AudioDeviceManager::getAudioDeviceSetup (AudioDeviceSetup& setup)
{
setup = currentSetup;
}
void AudioDeviceManager::deleteCurrentDevice()
{
currentAudioDevice = nullptr;
currentSetup.inputDeviceName = String::empty;
currentSetup.outputDeviceName = String::empty;
}
void AudioDeviceManager::setCurrentAudioDeviceType (const String& type,
const bool treatAsChosenDevice)
{
for (int i = 0; i < availableDeviceTypes.size(); ++i)
{
if (availableDeviceTypes.getUnchecked(i)->getTypeName() == type
&& currentDeviceType != type)
{
if (currentAudioDevice != nullptr)
{
closeAudioDevice();
Thread::sleep (1500); // allow a moment for OS devices to sort themselves out, to help
// avoid things like DirectSound/ASIO clashes
}
currentDeviceType = type;
AudioDeviceSetup s (*lastDeviceTypeConfigs.getUnchecked(i));
insertDefaultDeviceNames (s);
setAudioDeviceSetup (s, treatAsChosenDevice);
sendChangeMessage();
break;
}
}
}
AudioIODeviceType* AudioDeviceManager::getCurrentDeviceTypeObject() const
{
for (int i = 0; i < availableDeviceTypes.size(); ++i)
if (availableDeviceTypes.getUnchecked(i)->getTypeName() == currentDeviceType)
return availableDeviceTypes.getUnchecked(i);
return availableDeviceTypes[0];
}
String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup,
const bool treatAsChosenDevice)
{
jassert (&newSetup != &currentSetup); // this will have no effect
if (newSetup == currentSetup && currentAudioDevice != nullptr)
return String::empty;
if (! (newSetup == currentSetup))
sendChangeMessage();
stopDevice();
const String newInputDeviceName (numInputChansNeeded == 0 ? String::empty : newSetup.inputDeviceName);
const String newOutputDeviceName (numOutputChansNeeded == 0 ? String::empty : newSetup.outputDeviceName);
String error;
AudioIODeviceType* type = getCurrentDeviceTypeObject();
if (type == nullptr || (newInputDeviceName.isEmpty() && newOutputDeviceName.isEmpty()))
{
deleteCurrentDevice();
if (treatAsChosenDevice)
updateXml();
return String::empty;
}
if (currentSetup.inputDeviceName != newInputDeviceName
|| currentSetup.outputDeviceName != newOutputDeviceName
|| currentAudioDevice == nullptr)
{
deleteCurrentDevice();
scanDevicesIfNeeded();
if (newOutputDeviceName.isNotEmpty()
&& ! type->getDeviceNames (false).contains (newOutputDeviceName))
{
return "No such device: " + newOutputDeviceName;
}
if (newInputDeviceName.isNotEmpty()
&& ! type->getDeviceNames (true).contains (newInputDeviceName))
{
return "No such device: " + newInputDeviceName;
}
currentAudioDevice = type->createDevice (newOutputDeviceName, newInputDeviceName);
if (currentAudioDevice == nullptr)
error = "Can't open the audio device!\n\n"
"This may be because another application is currently using the same device - "
"if so, you should close any other applications and try again!";
else
error = currentAudioDevice->getLastError();
if (error.isNotEmpty())
{
deleteCurrentDevice();
return error;
}
if (newSetup.useDefaultInputChannels)
{
inputChannels.clear();
inputChannels.setRange (0, numInputChansNeeded, true);
}
if (newSetup.useDefaultOutputChannels)
{
outputChannels.clear();
outputChannels.setRange (0, numOutputChansNeeded, true);
}
if (newInputDeviceName.isEmpty()) inputChannels.clear();
if (newOutputDeviceName.isEmpty()) outputChannels.clear();
}
if (! newSetup.useDefaultInputChannels) inputChannels = newSetup.inputChannels;
if (! newSetup.useDefaultOutputChannels) outputChannels = newSetup.outputChannels;
currentSetup = newSetup;
currentSetup.sampleRate = chooseBestSampleRate (newSetup.sampleRate);
currentSetup.bufferSize = chooseBestBufferSize (newSetup.bufferSize);
error = currentAudioDevice->open (inputChannels,
outputChannels,
currentSetup.sampleRate,
currentSetup.bufferSize);
if (error.isEmpty())
{
currentDeviceType = currentAudioDevice->getTypeName();
currentAudioDevice->start (callbackHandler);
currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
for (int i = 0; i < availableDeviceTypes.size(); ++i)
if (availableDeviceTypes.getUnchecked (i)->getTypeName() == currentDeviceType)
*(lastDeviceTypeConfigs.getUnchecked (i)) = currentSetup;
if (treatAsChosenDevice)
updateXml();
}
else
{
deleteCurrentDevice();
}
return error;
}
double AudioDeviceManager::chooseBestSampleRate (double rate) const
{
jassert (currentAudioDevice != nullptr);
if (rate > 0)
for (int i = currentAudioDevice->getNumSampleRates(); --i >= 0;)
if (currentAudioDevice->getSampleRate (i) == rate)
return rate;
double lowestAbove44 = 0.0;
for (int i = currentAudioDevice->getNumSampleRates(); --i >= 0;)
{
const double sr = currentAudioDevice->getSampleRate (i);
if (sr >= 44100.0 && (lowestAbove44 < 1.0 || sr < lowestAbove44))
lowestAbove44 = sr;
}
if (lowestAbove44 > 0.0)
return lowestAbove44;
return currentAudioDevice->getSampleRate (0);
}
int AudioDeviceManager::chooseBestBufferSize (int bufferSize) const
{
jassert (currentAudioDevice != nullptr);
if (bufferSize > 0)
for (int i = currentAudioDevice->getNumBufferSizesAvailable(); --i >= 0;)
if (currentAudioDevice->getBufferSizeSamples(i) == bufferSize)
return bufferSize;
return currentAudioDevice->getDefaultBufferSize();
}
void AudioDeviceManager::stopDevice()
{
if (currentAudioDevice != nullptr)
currentAudioDevice->stop();
testSound = nullptr;
}
void AudioDeviceManager::closeAudioDevice()
{
stopDevice();
currentAudioDevice = nullptr;
}
void AudioDeviceManager::restartLastAudioDevice()
{
if (currentAudioDevice == nullptr)
{
if (currentSetup.inputDeviceName.isEmpty()
&& currentSetup.outputDeviceName.isEmpty())
{
// This method will only reload the last device that was running
// before closeAudioDevice() was called - you need to actually open
// one first, with setAudioDevice().
jassertfalse;
return;
}
AudioDeviceSetup s (currentSetup);
setAudioDeviceSetup (s, false);
}
}
void AudioDeviceManager::updateXml()
{
lastExplicitSettings = new XmlElement ("DEVICESETUP");
lastExplicitSettings->setAttribute ("deviceType", currentDeviceType);
lastExplicitSettings->setAttribute ("audioOutputDeviceName", currentSetup.outputDeviceName);
lastExplicitSettings->setAttribute ("audioInputDeviceName", currentSetup.inputDeviceName);
if (currentAudioDevice != nullptr)
{
lastExplicitSettings->setAttribute ("audioDeviceRate", currentAudioDevice->getCurrentSampleRate());
if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples())
lastExplicitSettings->setAttribute ("audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples());
if (! currentSetup.useDefaultInputChannels)
lastExplicitSettings->setAttribute ("audioDeviceInChans", currentSetup.inputChannels.toString (2));
if (! currentSetup.useDefaultOutputChannels)
lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2));
}
for (int i = 0; i < enabledMidiInputs.size(); ++i)
lastExplicitSettings->createNewChildElement ("MIDIINPUT")
->setAttribute ("name", enabledMidiInputs[i]->getName());
if (midiInsFromXml.size() > 0)
{
// Add any midi devices that have been enabled before, but which aren't currently
// open because the device has been disconnected.
const StringArray availableMidiDevices (MidiInput::getDevices());
for (int i = 0; i < midiInsFromXml.size(); ++i)
if (! availableMidiDevices.contains (midiInsFromXml[i], true))
lastExplicitSettings->createNewChildElement ("MIDIINPUT")
->setAttribute ("name", midiInsFromXml[i]);
}
if (defaultMidiOutputName.isNotEmpty())
lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputName);
}
//==============================================================================
void AudioDeviceManager::addAudioCallback (AudioIODeviceCallback* newCallback)
{
{
const ScopedLock sl (audioCallbackLock);
if (callbacks.contains (newCallback))
return;
}
if (currentAudioDevice != nullptr && newCallback != nullptr)
newCallback->audioDeviceAboutToStart (currentAudioDevice);
const ScopedLock sl (audioCallbackLock);
callbacks.add (newCallback);
}
void AudioDeviceManager::removeAudioCallback (AudioIODeviceCallback* callbackToRemove)
{
if (callbackToRemove != nullptr)
{
bool needsDeinitialising = currentAudioDevice != nullptr;
{
const ScopedLock sl (audioCallbackLock);
needsDeinitialising = needsDeinitialising && callbacks.contains (callbackToRemove);
callbacks.removeFirstMatchingValue (callbackToRemove);
}
if (needsDeinitialising)
callbackToRemove->audioDeviceStopped();
}
}
void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples)
{
const ScopedLock sl (audioCallbackLock);
if (inputLevelMeasurementEnabledCount.get() > 0 && numInputChannels > 0)
{
for (int j = 0; j < numSamples; ++j)
{
float s = 0;
for (int i = 0; i < numInputChannels; ++i)
s += std::abs (inputChannelData[i][j]);
s /= numInputChannels;
const double decayFactor = 0.99992;
if (s > inputLevel)
inputLevel = s;
else if (inputLevel > 0.001f)
inputLevel *= decayFactor;
else
inputLevel = 0;
}
}
else
{
inputLevel = 0;
}
if (callbacks.size() > 0)
{
const double callbackStartTime = Time::getMillisecondCounterHiRes();
tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true);
callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
outputChannelData, numOutputChannels, numSamples);
float** const tempChans = tempBuffer.getArrayOfChannels();
for (int i = callbacks.size(); --i > 0;)
{
callbacks.getUnchecked(i)->audioDeviceIOCallback (inputChannelData, numInputChannels,
tempChans, numOutputChannels, numSamples);
for (int chan = 0; chan < numOutputChannels; ++chan)
{
if (const float* const src = tempChans [chan])
if (float* const dst = outputChannelData [chan])
for (int j = 0; j < numSamples; ++j)
dst[j] += src[j];
}
}
const double msTaken = Time::getMillisecondCounterHiRes() - callbackStartTime;
const double filterAmount = 0.2;
cpuUsageMs += filterAmount * (msTaken - cpuUsageMs);
}
else
{
for (int i = 0; i < numOutputChannels; ++i)
zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples);
}
if (testSound != nullptr)
{
const int numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
const float* const src = testSound->getSampleData (0, testSoundPosition);
for (int i = 0; i < numOutputChannels; ++i)
for (int j = 0; j < numSamps; ++j)
outputChannelData [i][j] += src[j];
testSoundPosition += numSamps;
if (testSoundPosition >= testSound->getNumSamples())
testSound = nullptr;
}
}
void AudioDeviceManager::audioDeviceAboutToStartInt (AudioIODevice* const device)
{
cpuUsageMs = 0;
const double sampleRate = device->getCurrentSampleRate();
const int blockSize = device->getCurrentBufferSizeSamples();
if (sampleRate > 0.0 && blockSize > 0)
{
const double msPerBlock = 1000.0 * blockSize / sampleRate;
timeToCpuScale = (msPerBlock > 0.0) ? (1.0 / msPerBlock) : 0.0;
}
{
const ScopedLock sl (audioCallbackLock);
for (int i = callbacks.size(); --i >= 0;)
callbacks.getUnchecked(i)->audioDeviceAboutToStart (device);
}
sendChangeMessage();
}
void AudioDeviceManager::audioDeviceStoppedInt()
{
cpuUsageMs = 0;
timeToCpuScale = 0;
sendChangeMessage();
const ScopedLock sl (audioCallbackLock);
for (int i = callbacks.size(); --i >= 0;)
callbacks.getUnchecked(i)->audioDeviceStopped();
}
void AudioDeviceManager::audioDeviceErrorInt (const String& message)
{
const ScopedLock sl (audioCallbackLock);
for (int i = callbacks.size(); --i >= 0;)
callbacks.getUnchecked(i)->audioDeviceError (message);
}
double AudioDeviceManager::getCpuUsage() const
{
return jlimit (0.0, 1.0, timeToCpuScale * cpuUsageMs);
}
//==============================================================================
void AudioDeviceManager::setMidiInputEnabled (const String& name, const bool enabled)
{
if (enabled != isMidiInputEnabled (name))
{
if (enabled)
{
const int index = MidiInput::getDevices().indexOf (name);
if (index >= 0)
{
if (MidiInput* const midiIn = MidiInput::openDevice (index, callbackHandler))
{
enabledMidiInputs.add (midiIn);
midiIn->start();
}
}
}
else
{
for (int i = enabledMidiInputs.size(); --i >= 0;)
if (enabledMidiInputs[i]->getName() == name)
enabledMidiInputs.remove (i);
}
updateXml();
sendChangeMessage();
}
}
bool AudioDeviceManager::isMidiInputEnabled (const String& name) const
{
for (int i = enabledMidiInputs.size(); --i >= 0;)
if (enabledMidiInputs[i]->getName() == name)
return true;
return false;
}
void AudioDeviceManager::addMidiInputCallback (const String& name, MidiInputCallback* callbackToAdd)
{
removeMidiInputCallback (name, callbackToAdd);
if (name.isEmpty() || isMidiInputEnabled (name))
{
const ScopedLock sl (midiCallbackLock);
midiCallbacks.add (callbackToAdd);
midiCallbackDevices.add (name);
}
}
void AudioDeviceManager::removeMidiInputCallback (const String& name, MidiInputCallback* callbackToRemove)
{
for (int i = midiCallbacks.size(); --i >= 0;)
{
if (midiCallbackDevices[i] == name && midiCallbacks.getUnchecked(i) == callbackToRemove)
{
const ScopedLock sl (midiCallbackLock);
midiCallbacks.remove (i);
midiCallbackDevices.remove (i);
}
}
}
void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source, const MidiMessage& message)
{
if (! message.isActiveSense())
{
const bool isDefaultSource = (source == nullptr || source == enabledMidiInputs.getFirst());
const ScopedLock sl (midiCallbackLock);
for (int i = midiCallbackDevices.size(); --i >= 0;)
{
const String name (midiCallbackDevices[i]);
if ((isDefaultSource && name.isEmpty()) || (name.isNotEmpty() && name == source->getName()))
midiCallbacks.getUnchecked(i)->handleIncomingMidiMessage (source, message);
}
}
}
//==============================================================================
void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName)
{
if (defaultMidiOutputName != deviceName)
{
Array <AudioIODeviceCallback*> oldCallbacks;
{
const ScopedLock sl (audioCallbackLock);
oldCallbacks.swapWith (callbacks);
}
if (currentAudioDevice != nullptr)
for (int i = oldCallbacks.size(); --i >= 0;)
oldCallbacks.getUnchecked(i)->audioDeviceStopped();
defaultMidiOutput = nullptr;
defaultMidiOutputName = deviceName;
if (deviceName.isNotEmpty())
defaultMidiOutput = MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName));
if (currentAudioDevice != nullptr)
for (int i = oldCallbacks.size(); --i >= 0;)
oldCallbacks.getUnchecked(i)->audioDeviceAboutToStart (currentAudioDevice);
{
const ScopedLock sl (audioCallbackLock);
oldCallbacks.swapWith (callbacks);
}
updateXml();
sendChangeMessage();
}
}
//==============================================================================
void AudioDeviceManager::playTestSound()
{
{ // cunningly nested to swap, unlock and delete in that order.
ScopedPointer <AudioSampleBuffer> oldSound;
{
const ScopedLock sl (audioCallbackLock);
oldSound = testSound;
}
}
testSoundPosition = 0;
if (currentAudioDevice != nullptr)
{
const double sampleRate = currentAudioDevice->getCurrentSampleRate();
const int soundLength = (int) sampleRate;
AudioSampleBuffer* const newSound = new AudioSampleBuffer (1, soundLength);
float* samples = newSound->getSampleData (0);
const double frequency = 440.0;
const float amplitude = 0.5f;
const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency);
for (int i = 0; i < soundLength; ++i)
samples[i] = amplitude * (float) std::sin (i * phasePerSample);
newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f);
newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f);
const ScopedLock sl (audioCallbackLock);
testSound = newSound;
}
}
void AudioDeviceManager::enableInputLevelMeasurement (const bool enableMeasurement)
{
if (enableMeasurement)
++inputLevelMeasurementEnabledCount;
else
--inputLevelMeasurementEnabledCount;
inputLevel = 0;
}
double AudioDeviceManager::getCurrentInputLevel() const
{
jassert (inputLevelMeasurementEnabledCount.get() > 0); // you need to call enableInputLevelMeasurement() before using this!
return inputLevel;
}

+ 510
- 0
source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h View File

@@ -0,0 +1,510 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIODEVICEMANAGER_H_INCLUDED
#define JUCE_AUDIODEVICEMANAGER_H_INCLUDED
//==============================================================================
/**
Manages the state of some audio and midi i/o devices.
This class keeps tracks of a currently-selected audio device, through
with which it continuously streams data from an audio callback, as well as
one or more midi inputs.
The idea is that your application will create one global instance of this object,
and let it take care of creating and deleting specific types of audio devices
internally. So when the device is changed, your callbacks will just keep running
without having to worry about this.
The manager can save and reload all of its device settings as XML, which
makes it very easy for you to save and reload the audio setup of your
application.
And to make it easy to let the user change its settings, there's a component
to do just that - the AudioDeviceSelectorComponent class, which contains a set of
device selection/sample-rate/latency controls.
To use an AudioDeviceManager, create one, and use initialise() to set it up. Then
call addAudioCallback() to register your audio callback with it, and use that to process
your audio data.
The manager also acts as a handy hub for incoming midi messages, allowing a
listener to register for messages from either a specific midi device, or from whatever
the current default midi input device is. The listener then doesn't have to worry about
re-registering with different midi devices if they are changed or deleted.
And yet another neat trick is that amount of CPU time being used is measured and
available with the getCpuUsage() method.
The AudioDeviceManager is a ChangeBroadcaster, and will send a change message to
listeners whenever one of its settings is changed.
@see AudioDeviceSelectorComponent, AudioIODevice, AudioIODeviceType
*/
class JUCE_API AudioDeviceManager : public ChangeBroadcaster
{
public:
//==============================================================================
/** Creates a default AudioDeviceManager.
Initially no audio device will be selected. You should call the initialise() method
and register an audio callback with setAudioCallback() before it'll be able to
actually make any noise.
*/
AudioDeviceManager();
/** Destructor. */
~AudioDeviceManager();
//==============================================================================
/**
This structure holds a set of properties describing the current audio setup.
An AudioDeviceManager uses this class to save/load its current settings, and to
specify your preferred options when opening a device.
@see AudioDeviceManager::setAudioDeviceSetup(), AudioDeviceManager::initialise()
*/
struct JUCE_API AudioDeviceSetup
{
/** Creates an AudioDeviceSetup object.
The default constructor sets all the member variables to indicate default values.
You can then fill-in any values you want to before passing the object to
AudioDeviceManager::initialise().
*/
AudioDeviceSetup();
bool operator== (const AudioDeviceSetup& other) const;
/** The name of the audio device used for output.
The name has to be one of the ones listed by the AudioDeviceManager's currently
selected device type.
This may be the same as the input device.
An empty string indicates the default device.
*/
String outputDeviceName;
/** The name of the audio device used for input.
This may be the same as the output device.
An empty string indicates the default device.
*/
String inputDeviceName;
/** The current sample rate.
This rate is used for both the input and output devices.
A value of 0 indicates that you don't care what rate is used, and the
device will choose a sensible rate for you.
*/
double sampleRate;
/** The buffer size, in samples.
This buffer size is used for both the input and output devices.
A value of 0 indicates the default buffer size.
*/
int bufferSize;
/** The set of active input channels.
The bits that are set in this array indicate the channels of the
input device that are active.
If useDefaultInputChannels is true, this value is ignored.
*/
BigInteger inputChannels;
/** If this is true, it indicates that the inputChannels array
should be ignored, and instead, the device's default channels
should be used.
*/
bool useDefaultInputChannels;
/** The set of active output channels.
The bits that are set in this array indicate the channels of the
input device that are active.
If useDefaultOutputChannels is true, this value is ignored.
*/
BigInteger outputChannels;
/** If this is true, it indicates that the outputChannels array
should be ignored, and instead, the device's default channels
should be used.
*/
bool useDefaultOutputChannels;
};
//==============================================================================
/** Opens a set of audio devices ready for use.
This will attempt to open either a default audio device, or one that was
previously saved as XML.
@param numInputChannelsNeeded the maximum number of input channels your app would like to
use (the actual number of channels opened may be less than
the number requested)
@param numOutputChannelsNeeded the maximum number of output channels your app would like to
use (the actual number of channels opened may be less than
the number requested)
@param savedState either a previously-saved state that was produced
by createStateXml(), or nullptr if you want the manager
to choose the best device to open.
@param selectDefaultDeviceOnFailure if true, then if the device specified in the XML
fails to open, then a default device will be used
instead. If false, then on failure, no device is
opened.
@param preferredDefaultDeviceName if this is not empty, and there's a device with this
name, then that will be used as the default device
(assuming that there wasn't one specified in the XML).
The string can actually be a simple wildcard, containing "*"
and "?" characters
@param preferredSetupOptions if this is non-null, the structure will be used as the
set of preferred settings when opening the device. If you
use this parameter, the preferredDefaultDeviceName
field will be ignored
@returns an error message if anything went wrong, or an empty string if it worked ok.
*/
String initialise (int numInputChannelsNeeded,
int numOutputChannelsNeeded,
const XmlElement* savedState,
bool selectDefaultDeviceOnFailure,
const String& preferredDefaultDeviceName = String::empty,
const AudioDeviceSetup* preferredSetupOptions = 0);
/** Returns some XML representing the current state of the manager.
This stores the current device, its samplerate, block size, etc, and
can be restored later with initialise().
Note that this can return a null pointer if no settings have been explicitly changed
(i.e. if the device manager has just been left in its default state).
*/
XmlElement* createStateXml() const;
//==============================================================================
/** Returns the current device properties that are in use.
@see setAudioDeviceSetup
*/
void getAudioDeviceSetup (AudioDeviceSetup& setup);
/** Changes the current device or its settings.
If you want to change a device property, like the current sample rate or
block size, you can call getAudioDeviceSetup() to retrieve the current
settings, then tweak the appropriate fields in the AudioDeviceSetup structure,
and pass it back into this method to apply the new settings.
@param newSetup the settings that you'd like to use
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
settings will be taken as having been explicitly chosen by the
user, and the next time createStateXml() is called, these settings
will be returned. If it's false, then the device is treated as a
temporary or default device, and a call to createStateXml() will
return either the last settings that were made with treatAsChosenDevice
as true, or the last XML settings that were passed into initialise().
@returns an error message if anything went wrong, or an empty string if it worked ok.
@see getAudioDeviceSetup
*/
String setAudioDeviceSetup (const AudioDeviceSetup& newSetup,
bool treatAsChosenDevice);
/** Returns the currently-active audio device. */
AudioIODevice* getCurrentAudioDevice() const noexcept { return currentAudioDevice; }
/** Returns the type of audio device currently in use.
@see setCurrentAudioDeviceType
*/
String getCurrentAudioDeviceType() const { return currentDeviceType; }
/** Returns the currently active audio device type object.
Don't keep a copy of this pointer - it's owned by the device manager and could
change at any time.
*/
AudioIODeviceType* getCurrentDeviceTypeObject() const;
/** Changes the class of audio device being used.
This switches between, e.g. ASIO and DirectSound. On the Mac you probably won't ever call
this because there's only one type: CoreAudio.
For a list of types, see getAvailableDeviceTypes().
*/
void setCurrentAudioDeviceType (const String& type,
bool treatAsChosenDevice);
/** Closes the currently-open device.
You can call restartLastAudioDevice() later to reopen it in the same state
that it was just in.
*/
void closeAudioDevice();
/** Tries to reload the last audio device that was running.
Note that this only reloads the last device that was running before
closeAudioDevice() was called - it doesn't reload any kind of saved-state,
and can only be called after a device has been opened with SetAudioDevice().
If a device is already open, this call will do nothing.
*/
void restartLastAudioDevice();
//==============================================================================
/** Registers an audio callback to be used.
The manager will redirect callbacks from whatever audio device is currently
in use to all registered callback objects. If more than one callback is
active, they will all be given the same input data, and their outputs will
be summed.
If necessary, this method will invoke audioDeviceAboutToStart() on the callback
object before returning.
To remove a callback, use removeAudioCallback().
*/
void addAudioCallback (AudioIODeviceCallback* newCallback);
/** Deregisters a previously added callback.
If necessary, this method will invoke audioDeviceStopped() on the callback
object before returning.
@see addAudioCallback
*/
void removeAudioCallback (AudioIODeviceCallback* callback);
//==============================================================================
/** Returns the average proportion of available CPU being spent inside the audio callbacks.
Returns a value between 0 and 1.0
*/
double getCpuUsage() const;
//==============================================================================
/** Enables or disables a midi input device.
The list of devices can be obtained with the MidiInput::getDevices() method.
Any incoming messages from enabled input devices will be forwarded on to all the
listeners that have been registered with the addMidiInputCallback() method. They
can either register for messages from a particular device, or from just the
"default" midi input.
Routing the midi input via an AudioDeviceManager means that when a listener
registers for the default midi input, this default device can be changed by the
manager without the listeners having to know about it or re-register.
It also means that a listener can stay registered for a midi input that is disabled
or not present, so that when the input is re-enabled, the listener will start
receiving messages again.
@see addMidiInputCallback, isMidiInputEnabled
*/
void setMidiInputEnabled (const String& midiInputDeviceName, bool enabled);
/** Returns true if a given midi input device is being used.
@see setMidiInputEnabled
*/
bool isMidiInputEnabled (const String& midiInputDeviceName) const;
/** Registers a listener for callbacks when midi events arrive from a midi input.
The device name can be empty to indicate that it wants events from whatever the
current "default" device is. Or it can be the name of one of the midi input devices
(see MidiInput::getDevices() for the names).
Only devices which are enabled (see the setMidiInputEnabled() method) will have their
events forwarded on to listeners.
*/
void addMidiInputCallback (const String& midiInputDeviceName,
MidiInputCallback* callback);
/** Removes a listener that was previously registered with addMidiInputCallback().
*/
void removeMidiInputCallback (const String& midiInputDeviceName,
MidiInputCallback* callback);
//==============================================================================
/** Sets a midi output device to use as the default.
The list of devices can be obtained with the MidiOutput::getDevices() method.
The specified device will be opened automatically and can be retrieved with the
getDefaultMidiOutput() method.
Pass in an empty string to deselect all devices. For the default device, you
can use MidiOutput::getDevices() [MidiOutput::getDefaultDeviceIndex()].
@see getDefaultMidiOutput, getDefaultMidiOutputName
*/
void setDefaultMidiOutput (const String& deviceName);
/** Returns the name of the default midi output.
@see setDefaultMidiOutput, getDefaultMidiOutput
*/
String getDefaultMidiOutputName() const { return defaultMidiOutputName; }
/** Returns the current default midi output device.
If no device has been selected, or the device can't be opened, this will
return 0.
@see getDefaultMidiOutputName
*/
MidiOutput* getDefaultMidiOutput() const noexcept { return defaultMidiOutput; }
/** Returns a list of the types of device supported.
*/
const OwnedArray <AudioIODeviceType>& getAvailableDeviceTypes();
//==============================================================================
/** Creates a list of available types.
This will add a set of new AudioIODeviceType objects to the specified list, to
represent each available types of device.
You can override this if your app needs to do something specific, like avoid
using DirectSound devices, etc.
*/
virtual void createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& types);
/** Adds a new device type to the list of types.
The manager will take ownership of the object that is passed-in.
*/
void addAudioDeviceType (AudioIODeviceType* newDeviceType);
//==============================================================================
/** Plays a beep through the current audio device.
This is here to allow the audio setup UI panels to easily include a "test"
button so that the user can check where the audio is coming from.
*/
void playTestSound();
/** Turns on level-measuring.
When enabled, the device manager will measure the peak input level
across all channels, and you can get this level by calling getCurrentInputLevel().
This is mainly intended for audio setup UI panels to use to create a mic
level display, so that the user can check that they've selected the right
device.
A simple filter is used to make the level decay smoothly, but this is
only intended for giving rough feedback, and not for any kind of accurate
measurement.
*/
void enableInputLevelMeasurement (bool enableMeasurement);
/** Returns the current input level.
To use this, you must first enable it by calling enableInputLevelMeasurement().
See enableInputLevelMeasurement() for more info.
*/
double getCurrentInputLevel() const;
/** Returns the a lock that can be used to synchronise access to the audio callback.
Obviously while this is locked, you're blocking the audio thread from running, so
it must only be used for very brief periods when absolutely necessary.
*/
CriticalSection& getAudioCallbackLock() noexcept { return audioCallbackLock; }
/** Returns the a lock that can be used to synchronise access to the midi callback.
Obviously while this is locked, you're blocking the midi system from running, so
it must only be used for very brief periods when absolutely necessary.
*/
CriticalSection& getMidiCallbackLock() noexcept { return midiCallbackLock; }
private:
//==============================================================================
OwnedArray <AudioIODeviceType> availableDeviceTypes;
OwnedArray <AudioDeviceSetup> lastDeviceTypeConfigs;
AudioDeviceSetup currentSetup;
ScopedPointer <AudioIODevice> currentAudioDevice;
Array <AudioIODeviceCallback*> callbacks;
int numInputChansNeeded, numOutputChansNeeded;
String currentDeviceType;
BigInteger inputChannels, outputChannels;
ScopedPointer <XmlElement> lastExplicitSettings;
mutable bool listNeedsScanning;
bool useInputNames;
Atomic<int> inputLevelMeasurementEnabledCount;
double inputLevel;
ScopedPointer <AudioSampleBuffer> testSound;
int testSoundPosition;
AudioSampleBuffer tempBuffer;
StringArray midiInsFromXml;
OwnedArray <MidiInput> enabledMidiInputs;
Array <MidiInputCallback*> midiCallbacks;
StringArray midiCallbackDevices;
String defaultMidiOutputName;
ScopedPointer <MidiOutput> defaultMidiOutput;
CriticalSection audioCallbackLock, midiCallbackLock;
double cpuUsageMs, timeToCpuScale;
//==============================================================================
class CallbackHandler;
friend class CallbackHandler;
friend struct ContainerDeletePolicy<CallbackHandler>;
ScopedPointer<CallbackHandler> callbackHandler;
void audioDeviceIOCallbackInt (const float** inputChannelData, int totalNumInputChannels,
float** outputChannelData, int totalNumOutputChannels, int numSamples);
void audioDeviceAboutToStartInt (AudioIODevice*);
void audioDeviceStoppedInt();
void audioDeviceErrorInt (const String&);
void handleIncomingMidiMessageInt (MidiInput*, const MidiMessage&);
void audioDeviceListChanged();
String restartDevice (int blockSizeToUse, double sampleRateToUse,
const BigInteger& ins, const BigInteger& outs);
void stopDevice();
void updateXml();
void createDeviceTypesIfNeeded();
void scanDevicesIfNeeded();
void deleteCurrentDevice();
double chooseBestSampleRate (double preferred) const;
int chooseBestBufferSize (int preferred) const;
void insertDefaultDeviceNames (AudioDeviceSetup&) const;
AudioIODeviceType* findType (const String& inputName, const String& outputName);
AudioIODeviceType* findType (const String& typeName);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceManager)
};
#endif // JUCE_AUDIODEVICEMANAGER_H_INCLUDED

+ 48
- 0
source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.cpp View File

@@ -0,0 +1,48 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioIODevice::AudioIODevice (const String& deviceName, const String& typeName_)
: name (deviceName),
typeName (typeName_)
{
}
AudioIODevice::~AudioIODevice()
{
}
bool AudioIODevice::hasControlPanel() const
{
return false;
}
bool AudioIODevice::showControlPanel()
{
jassertfalse; // this should only be called for devices which return true from
// their hasControlPanel() method.
return false;
}
//==============================================================================
void AudioIODeviceCallback::audioDeviceError (const String&) {}

+ 332
- 0
source/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h View File

@@ -0,0 +1,332 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOIODEVICE_H_INCLUDED
#define JUCE_AUDIOIODEVICE_H_INCLUDED
class AudioIODevice;
//==============================================================================
/**
One of these is passed to an AudioIODevice object to stream the audio data
in and out.
The AudioIODevice will repeatedly call this class's audioDeviceIOCallback()
method on its own high-priority audio thread, when it needs to send or receive
the next block of data.
@see AudioIODevice, AudioDeviceManager
*/
class JUCE_API AudioIODeviceCallback
{
public:
/** Destructor. */
virtual ~AudioIODeviceCallback() {}
/** Processes a block of incoming and outgoing audio data.
The subclass's implementation should use the incoming audio for whatever
purposes it needs to, and must fill all the output channels with the next
block of output data before returning.
The channel data is arranged with the same array indices as the channel name
array returned by AudioIODevice::getOutputChannelNames(), but those channels
that aren't specified in AudioIODevice::open() will have a null pointer for their
associated channel, so remember to check for this.
@param inputChannelData a set of arrays containing the audio data for each
incoming channel - this data is valid until the function
returns. There will be one channel of data for each input
channel that was enabled when the audio device was opened
(see AudioIODevice::open())
@param numInputChannels the number of pointers to channel data in the
inputChannelData array.
@param outputChannelData a set of arrays which need to be filled with the data
that should be sent to each outgoing channel of the device.
There will be one channel of data for each output channel
that was enabled when the audio device was opened (see
AudioIODevice::open())
The initial contents of the array is undefined, so the
callback function must fill all the channels with zeros if
its output is silence. Failing to do this could cause quite
an unpleasant noise!
@param numOutputChannels the number of pointers to channel data in the
outputChannelData array.
@param numSamples the number of samples in each channel of the input and
output arrays. The number of samples will depend on the
audio device's buffer size and will usually remain constant,
although this isn't guaranteed, so make sure your code can
cope with reasonable changes in the buffer size from one
callback to the next.
*/
virtual void audioDeviceIOCallback (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples) = 0;
/** Called to indicate that the device is about to start calling back.
This will be called just before the audio callbacks begin, either when this
callback has just been added to an audio device, or after the device has been
restarted because of a sample-rate or block-size change.
You can use this opportunity to find out the sample rate and block size
that the device is going to use by calling the AudioIODevice::getCurrentSampleRate()
and AudioIODevice::getCurrentBufferSizeSamples() on the supplied pointer.
@param device the audio IO device that will be used to drive the callback.
Note that if you're going to store this this pointer, it is
only valid until the next time that audioDeviceStopped is called.
*/
virtual void audioDeviceAboutToStart (AudioIODevice* device) = 0;
/** Called to indicate that the device has stopped. */
virtual void audioDeviceStopped() = 0;
/** This can be overridden to be told if the device generates an error while operating.
Be aware that this could be called by any thread! And not all devices perform
this callback.
*/
virtual void audioDeviceError (const String& errorMessage);
};
//==============================================================================
/**
Base class for an audio device with synchronised input and output channels.
Subclasses of this are used to implement different protocols such as DirectSound,
ASIO, CoreAudio, etc.
To create one of these, you'll need to use the AudioIODeviceType class - see the
documentation for that class for more info.
For an easier way of managing audio devices and their settings, have a look at the
AudioDeviceManager class.
@see AudioIODeviceType, AudioDeviceManager
*/
class JUCE_API AudioIODevice
{
public:
/** Destructor. */
virtual ~AudioIODevice();
//==============================================================================
/** Returns the device's name, (as set in the constructor). */
const String& getName() const noexcept { return name; }
/** Returns the type of the device.
E.g. "CoreAudio", "ASIO", etc. - this comes from the AudioIODeviceType that created it.
*/
const String& getTypeName() const noexcept { return typeName; }
//==============================================================================
/** Returns the names of all the available output channels on this device.
To find out which of these are currently in use, call getActiveOutputChannels().
*/
virtual StringArray getOutputChannelNames() = 0;
/** Returns the names of all the available input channels on this device.
To find out which of these are currently in use, call getActiveInputChannels().
*/
virtual StringArray getInputChannelNames() = 0;
//==============================================================================
/** Returns the number of sample-rates this device supports.
To find out which rates are available on this device, use this method to
find out how many there are, and getSampleRate() to get the rates.
@see getSampleRate
*/
virtual int getNumSampleRates() = 0;
/** Returns one of the sample-rates this device supports.
To find out which rates are available on this device, use getNumSampleRates() to
find out how many there are, and getSampleRate() to get the individual rates.
The sample rate is set by the open() method.
(Note that for DirectSound some rates might not work, depending on combinations
of i/o channels that are being opened).
@see getNumSampleRates
*/
virtual double getSampleRate (int index) = 0;
/** Returns the number of sizes of buffer that are available.
@see getBufferSizeSamples, getDefaultBufferSize
*/
virtual int getNumBufferSizesAvailable() = 0;
/** Returns one of the possible buffer-sizes.
@param index the index of the buffer-size to use, from 0 to getNumBufferSizesAvailable() - 1
@returns a number of samples
@see getNumBufferSizesAvailable, getDefaultBufferSize
*/
virtual int getBufferSizeSamples (int index) = 0;
/** Returns the default buffer-size to use.
@returns a number of samples
@see getNumBufferSizesAvailable, getBufferSizeSamples
*/
virtual int getDefaultBufferSize() = 0;
//==============================================================================
/** Tries to open the device ready to play.
@param inputChannels a BigInteger in which a set bit indicates that the corresponding
input channel should be enabled
@param outputChannels a BigInteger in which a set bit indicates that the corresponding
output channel should be enabled
@param sampleRate the sample rate to try to use - to find out which rates are
available, see getNumSampleRates() and getSampleRate()
@param bufferSizeSamples the size of i/o buffer to use - to find out the available buffer
sizes, see getNumBufferSizesAvailable() and getBufferSizeSamples()
@returns an error description if there's a problem, or an empty string if it succeeds in
opening the device
@see close
*/
virtual String open (const BigInteger& inputChannels,
const BigInteger& outputChannels,
double sampleRate,
int bufferSizeSamples) = 0;
/** Closes and releases the device if it's open. */
virtual void close() = 0;
/** Returns true if the device is still open.
A device might spontaneously close itself if something goes wrong, so this checks if
it's still open.
*/
virtual bool isOpen() = 0;
/** Starts the device actually playing.
This must be called after the device has been opened.
@param callback the callback to use for streaming the data.
@see AudioIODeviceCallback, open
*/
virtual void start (AudioIODeviceCallback* callback) = 0;
/** Stops the device playing.
Once a device has been started, this will stop it. Any pending calls to the
callback class will be flushed before this method returns.
*/
virtual void stop() = 0;
/** Returns true if the device is still calling back.
The device might mysteriously stop, so this checks whether it's
still playing.
*/
virtual bool isPlaying() = 0;
/** Returns the last error that happened if anything went wrong. */
virtual String getLastError() = 0;
//==============================================================================
/** Returns the buffer size that the device is currently using.
If the device isn't actually open, this value doesn't really mean much.
*/
virtual int getCurrentBufferSizeSamples() = 0;
/** Returns the sample rate that the device is currently using.
If the device isn't actually open, this value doesn't really mean much.
*/
virtual double getCurrentSampleRate() = 0;
/** Returns the device's current physical bit-depth.
If the device isn't actually open, this value doesn't really mean much.
*/
virtual int getCurrentBitDepth() = 0;
/** Returns a mask showing which of the available output channels are currently
enabled.
@see getOutputChannelNames
*/
virtual BigInteger getActiveOutputChannels() const = 0;
/** Returns a mask showing which of the available input channels are currently
enabled.
@see getInputChannelNames
*/
virtual BigInteger getActiveInputChannels() const = 0;
/** Returns the device's output latency.
This is the delay in samples between a callback getting a block of data, and
that data actually getting played.
*/
virtual int getOutputLatencyInSamples() = 0;
/** Returns the device's input latency.
This is the delay in samples between some audio actually arriving at the soundcard,
and the callback getting passed this block of data.
*/
virtual int getInputLatencyInSamples() = 0;
//==============================================================================
/** True if this device can show a pop-up control panel for editing its settings.
This is generally just true of ASIO devices. If true, you can call showControlPanel()
to display it.
*/
virtual bool hasControlPanel() const;
/** Shows a device-specific control panel if there is one.
This should only be called for devices which return true from hasControlPanel().
*/
virtual bool showControlPanel();
//==============================================================================
protected:
/** Creates a device, setting its name and type member variables. */
AudioIODevice (const String& deviceName,
const String& typeName);
/** @internal */
String name, typeName;
};
#endif // JUCE_AUDIOIODEVICE_H_INCLUDED

+ 78
- 0
source/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp View File

@@ -0,0 +1,78 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioIODeviceType::AudioIODeviceType (const String& name)
: typeName (name)
{
}
AudioIODeviceType::~AudioIODeviceType()
{
}
//==============================================================================
void AudioIODeviceType::addListener (Listener* l) { listeners.add (l); }
void AudioIODeviceType::removeListener (Listener* l) { listeners.remove (l); }
void AudioIODeviceType::callDeviceChangeListeners()
{
listeners.call (&AudioIODeviceType::Listener::audioDeviceListChanged);
}
//==============================================================================
#if ! JUCE_MAC
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_CoreAudio() { return nullptr; }
#endif
#if ! JUCE_IOS
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_iOSAudio() { return nullptr; }
#endif
#if ! (JUCE_WINDOWS && JUCE_WASAPI)
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_WASAPI() { return nullptr; }
#endif
#if ! (JUCE_WINDOWS && JUCE_DIRECTSOUND)
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_DirectSound() { return nullptr; }
#endif
#if ! (JUCE_WINDOWS && JUCE_ASIO)
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_ASIO() { return nullptr; }
#endif
#if ! (JUCE_LINUX && JUCE_ALSA)
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_ALSA() { return nullptr; }
#endif
#if ! (JUCE_LINUX && JUCE_JACK)
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK() { return nullptr; }
#endif
#if ! JUCE_ANDROID
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Android() { return nullptr; }
#endif
#if ! (JUCE_ANDROID && JUCE_USE_ANDROID_OPENSLES)
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_OpenSLES() { return nullptr; }
#endif

+ 182
- 0
source/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h View File

@@ -0,0 +1,182 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOIODEVICETYPE_H_INCLUDED
#define JUCE_AUDIOIODEVICETYPE_H_INCLUDED
//==============================================================================
/**
Represents a type of audio driver, such as DirectSound, ASIO, CoreAudio, etc.
To get a list of available audio driver types, use the AudioDeviceManager::createAudioDeviceTypes()
method. Each of the objects returned can then be used to list the available
devices of that type. E.g.
@code
OwnedArray <AudioIODeviceType> types;
myAudioDeviceManager.createAudioDeviceTypes (types);
for (int i = 0; i < types.size(); ++i)
{
String typeName (types[i]->getTypeName()); // This will be things like "DirectSound", "CoreAudio", etc.
types[i]->scanForDevices(); // This must be called before getting the list of devices
StringArray deviceNames (types[i]->getDeviceNames()); // This will now return a list of available devices of this type
for (int j = 0; j < deviceNames.size(); ++j)
{
AudioIODevice* device = types[i]->createDevice (deviceNames [j]);
...
}
}
@endcode
For an easier way of managing audio devices and their settings, have a look at the
AudioDeviceManager class.
@see AudioIODevice, AudioDeviceManager
*/
class JUCE_API AudioIODeviceType
{
public:
//==============================================================================
/** Returns the name of this type of driver that this object manages.
This will be something like "DirectSound", "ASIO", "CoreAudio", "ALSA", etc.
*/
const String& getTypeName() const noexcept { return typeName; }
//==============================================================================
/** Refreshes the object's cached list of known devices.
This must be called at least once before calling getDeviceNames() or any of
the other device creation methods.
*/
virtual void scanForDevices() = 0;
/** Returns the list of available devices of this type.
The scanForDevices() method must have been called to create this list.
@param wantInputNames only really used by DirectSound where devices are split up
into inputs and outputs, this indicates whether to use
the input or output name to refer to a pair of devices.
*/
virtual StringArray getDeviceNames (bool wantInputNames = false) const = 0;
/** Returns the name of the default device.
This will be one of the names from the getDeviceNames() list.
@param forInput if true, this means that a default input device should be
returned; if false, it should return the default output
*/
virtual int getDefaultDeviceIndex (bool forInput) const = 0;
/** Returns the index of a given device in the list of device names.
If asInput is true, it shows the index in the inputs list, otherwise it
looks for it in the outputs list.
*/
virtual int getIndexOfDevice (AudioIODevice* device, bool asInput) const = 0;
/** Returns true if two different devices can be used for the input and output.
*/
virtual bool hasSeparateInputsAndOutputs() const = 0;
/** Creates one of the devices of this type.
The deviceName must be one of the strings returned by getDeviceNames(), and
scanForDevices() must have been called before this method is used.
*/
virtual AudioIODevice* createDevice (const String& outputDeviceName,
const String& inputDeviceName) = 0;
//==============================================================================
/**
A class for receiving events when audio devices are inserted or removed.
You can register a AudioIODeviceType::Listener with an~AudioIODeviceType object
using the AudioIODeviceType::addListener() method, and it will be called when
devices of that type are added or removed.
@see AudioIODeviceType::addListener, AudioIODeviceType::removeListener
*/
class Listener
{
public:
virtual ~Listener() {}
/** Called when the list of available audio devices changes. */
virtual void audioDeviceListChanged() = 0;
};
/** Adds a listener that will be called when this type of device is added or
removed from the system.
*/
void addListener (Listener* listener);
/** Removes a listener that was previously added with addListener(). */
void removeListener (Listener* listener);
//==============================================================================
/** Destructor. */
virtual ~AudioIODeviceType();
//==============================================================================
/** Creates a CoreAudio device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_CoreAudio();
/** Creates an iOS device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_iOSAudio();
/** Creates a WASAPI device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_WASAPI();
/** Creates a DirectSound device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_DirectSound();
/** Creates an ASIO device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_ASIO();
/** Creates an ALSA device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_ALSA();
/** Creates a JACK device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_JACK();
/** Creates an Android device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_Android();
/** Creates an Android OpenSLES device type if it's available on this platform, or returns null. */
static AudioIODeviceType* createAudioIODeviceType_OpenSLES();
protected:
explicit AudioIODeviceType (const String& typeName);
/** Synchronously calls all the registered device list change listeners. */
void callDeviceChangeListeners();
private:
String typeName;
ListenerList<Listener> listeners;
JUCE_DECLARE_NON_COPYABLE (AudioIODeviceType)
};
#endif // JUCE_AUDIOIODEVICETYPE_H_INCLUDED

+ 61
- 0
source/modules/juce_audio_devices/audio_io/juce_SystemAudioVolume.h View File

@@ -0,0 +1,61 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_SYSTEMAUDIOVOLUME_H_INCLUDED
#define JUCE_SYSTEMAUDIOVOLUME_H_INCLUDED
//==============================================================================
/**
Contains functions to control the system's master volume.
*/
class JUCE_API SystemAudioVolume
{
public:
//==============================================================================
/** Returns the operating system's current volume level in the range 0 to 1.0 */
static float JUCE_CALLTYPE getGain();
/** Attempts to set the operating system's current volume level.
@param newGain the level, between 0 and 1.0
@returns true if the operation succeeds
*/
static bool JUCE_CALLTYPE setGain (float newGain);
/** Returns true if the system's audio output is currently muted. */
static bool JUCE_CALLTYPE isMuted();
/** Attempts to mute the operating system's audio output.
@param shouldBeMuted true if you want it to be muted
@returns true if the operation succeeds
*/
static bool JUCE_CALLTYPE setMuted (bool shouldBeMuted);
private:
SystemAudioVolume(); // Don't instantiate this class, just call its static fns.
JUCE_DECLARE_NON_COPYABLE (SystemAudioVolume)
};
#endif // JUCE_SYSTEMAUDIOVOLUME_H_INCLUDED

+ 226
- 0
source/modules/juce_audio_devices/juce_audio_devices.cpp View File

@@ -0,0 +1,226 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if defined (JUCE_AUDIO_DEVICES_H_INCLUDED) && ! JUCE_AMALGAMATED_INCLUDE
/* When you add this cpp file to your project, you mustn't include it in a file where you've
already included any other headers - just put it inside a file on its own, possibly with your config
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
header files that the compiler may be using.
*/
#error "Incorrect use of JUCE cpp file"
#endif
// Your project must contain an AppConfig.h file with your project-specific settings in it,
// and your header search path must make it accessible to the module's files.
#include "AppConfig.h"
#include "../juce_core/native/juce_BasicNativeHeaders.h"
#include "juce_audio_devices.h"
//==============================================================================
#if JUCE_MAC
#define Point CarbonDummyPointName
#define Component CarbonDummyCompName
#import <CoreAudio/AudioHardware.h>
#import <CoreMIDI/MIDIServices.h>
#import <DiscRecording/DiscRecording.h>
#import <AudioToolbox/AudioServices.h>
#undef Point
#undef Component
#elif JUCE_IOS
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreMIDI/MIDIServices.h>
//==============================================================================
#elif JUCE_WINDOWS
#if JUCE_WASAPI
#include <MMReg.h>
#endif
#if JUCE_ASIO
/* This is very frustrating - we only need to use a handful of definitions from
a couple of the header files in Steinberg's ASIO SDK, and it'd be easy to copy
about 30 lines of code into this cpp file to create a fully stand-alone ASIO
implementation...
..unfortunately that would break Steinberg's license agreement for use of
their SDK, so I'm not allowed to do this.
This means that anyone who wants to use JUCE's ASIO abilities will have to:
1) Agree to Steinberg's licensing terms and download the ASIO SDK
(see www.steinberg.net/Steinberg/Developers.asp).
2) Enable this code with a global definition #define JUCE_ASIO 1.
3) Make sure that your header search path contains the iasiodrv.h file that
comes with the SDK. (Only about a handful of the SDK header files are actually
needed - so to simplify things, you could just copy these into your JUCE directory).
*/
#include <iasiodrv.h>
#endif
#if JUCE_USE_CDBURNER
/* You'll need the Platform SDK for these headers - if you don't have it and don't
need to use CD-burning, then you might just want to set the JUCE_USE_CDBURNER flag
to 0, to avoid these includes.
*/
#include <imapi.h>
#include <imapierror.h>
#endif
//==============================================================================
#elif JUCE_LINUX
#if JUCE_ALSA
/* Got an include error here? If so, you've either not got ALSA installed, or you've
not got your paths set up correctly to find its header files.
The package you need to install to get ASLA support is "libasound2-dev".
If you don't have the ALSA library and don't want to build Juce with audio support,
just set the JUCE_ALSA flag to 0.
*/
#include <alsa/asoundlib.h>
#endif
#if JUCE_JACK
/* Got an include error here? If so, you've either not got jack-audio-connection-kit
installed, or you've not got your paths set up correctly to find its header files.
The package you need to install to get JACK support is "libjack-dev".
If you don't have the jack-audio-connection-kit library and don't want to build
Juce with low latency audio support, just set the JUCE_JACK flag to 0.
*/
#include <jack/jack.h>
#endif
#undef SIZEOF
//==============================================================================
#elif JUCE_ANDROID
#if JUCE_USE_ANDROID_OPENSLES
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#endif
#endif
namespace juce
{
#include "audio_io/juce_AudioDeviceManager.cpp"
#include "audio_io/juce_AudioIODevice.cpp"
#include "audio_io/juce_AudioIODeviceType.cpp"
#include "midi_io/juce_MidiMessageCollector.cpp"
#include "midi_io/juce_MidiOutput.cpp"
#include "audio_cd/juce_AudioCDReader.cpp"
#include "sources/juce_AudioSourcePlayer.cpp"
#include "sources/juce_AudioTransportSource.cpp"
#include "native/juce_MidiDataConcatenator.h"
//==============================================================================
#if JUCE_MAC
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "native/juce_mac_CoreAudio.cpp"
#include "native/juce_mac_CoreMidi.cpp"
#if JUCE_USE_CDREADER
#include "native/juce_mac_AudioCDReader.mm"
#endif
#if JUCE_USE_CDBURNER
#include "native/juce_mac_AudioCDBurner.mm"
#endif
//==============================================================================
#elif JUCE_IOS
#include "native/juce_ios_Audio.cpp"
#include "native/juce_mac_CoreMidi.cpp"
//==============================================================================
#elif JUCE_WINDOWS
#include "../juce_core/native/juce_win32_ComSmartPtr.h"
#include "../juce_events/native/juce_win32_HiddenMessageWindow.h"
#if JUCE_WASAPI
#include "native/juce_win32_WASAPI.cpp"
#endif
#if JUCE_DIRECTSOUND
#include "native/juce_win32_DirectSound.cpp"
#endif
#include "native/juce_win32_Midi.cpp"
#if JUCE_ASIO
#include "native/juce_win32_ASIO.cpp"
#endif
#if JUCE_USE_CDREADER
#include "native/juce_win32_AudioCDReader.cpp"
#endif
#if JUCE_USE_CDBURNER
#include "native/juce_win32_AudioCDBurner.cpp"
#endif
//==============================================================================
#elif JUCE_LINUX
#if JUCE_ALSA
#include "native/juce_linux_ALSA.cpp"
#endif
#include "native/juce_linux_Midi.cpp"
#if JUCE_JACK
#include "native/juce_linux_JackAudio.cpp"
#endif
#if JUCE_USE_CDREADER
#include "native/juce_linux_AudioCDReader.cpp"
#endif
//==============================================================================
#elif JUCE_ANDROID
#include "../juce_core/native/juce_android_JNIHelpers.h"
#include "native/juce_android_Audio.cpp"
#include "native/juce_android_Midi.cpp"
#if JUCE_USE_ANDROID_OPENSLES
#include "native/juce_android_OpenSL.cpp"
#endif
#endif
#if ! JUCE_SYSTEMAUDIOVOL_IMPLEMENTED
// None of these methods are available. (On Windows you might need to enable WASAPI for this)
float JUCE_CALLTYPE SystemAudioVolume::getGain() { jassertfalse; return 0.0f; }
bool JUCE_CALLTYPE SystemAudioVolume::setGain (float) { jassertfalse; return false; }
bool JUCE_CALLTYPE SystemAudioVolume::isMuted() { jassertfalse; return false; }
bool JUCE_CALLTYPE SystemAudioVolume::setMuted (bool) { jassertfalse; return false; }
#endif
}

+ 117
- 0
source/modules/juce_audio_devices/juce_audio_devices.h View File

@@ -0,0 +1,117 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIO_DEVICES_H_INCLUDED
#define JUCE_AUDIO_DEVICES_H_INCLUDED
#include "../juce_events/juce_events.h"
#include "../juce_audio_basics/juce_audio_basics.h"
#include "../juce_audio_formats/juce_audio_formats.h"
//=============================================================================
/** Config: JUCE_ASIO
Enables ASIO audio devices (MS Windows only).
Turning this on means that you'll need to have the Steinberg ASIO SDK installed
on your Windows build machine.
See the comments in the ASIOAudioIODevice class's header file for more
info about this.
*/
#ifndef JUCE_ASIO
#define JUCE_ASIO 0
#endif
/** Config: JUCE_WASAPI
Enables WASAPI audio devices (Windows Vista and above).
*/
#ifndef JUCE_WASAPI
#define JUCE_WASAPI 1
#endif
/** Config: JUCE_DIRECTSOUND
Enables DirectSound audio (MS Windows only).
*/
#ifndef JUCE_DIRECTSOUND
#define JUCE_DIRECTSOUND 1
#endif
/** Config: JUCE_ALSA
Enables ALSA audio devices (Linux only).
*/
#ifndef JUCE_ALSA
#define JUCE_ALSA 1
#endif
/** Config: JUCE_JACK
Enables JACK audio devices (Linux only).
*/
#ifndef JUCE_JACK
#define JUCE_JACK 0
#endif
/** Config: JUCE_USE_ANDROID_OPENSLES
Enables OpenSLES devices (Android only).
*/
#ifndef JUCE_USE_ANDROID_OPENSLES
#if JUCE_ANDROID_API_VERSION > 8
#define JUCE_USE_ANDROID_OPENSLES 1
#else
#define JUCE_USE_ANDROID_OPENSLES 0
#endif
#endif
//=============================================================================
/** Config: JUCE_USE_CDREADER
Enables the AudioCDReader class (on supported platforms).
*/
#ifndef JUCE_USE_CDREADER
#define JUCE_USE_CDREADER 0
#endif
/** Config: JUCE_USE_CDBURNER
Enables the AudioCDBurner class (on supported platforms).
*/
#ifndef JUCE_USE_CDBURNER
#define JUCE_USE_CDBURNER 0
#endif
//=============================================================================
namespace juce
{
#include "audio_io/juce_AudioIODevice.h"
#include "audio_io/juce_AudioIODeviceType.h"
#include "audio_io/juce_SystemAudioVolume.h"
#include "midi_io/juce_MidiInput.h"
#include "midi_io/juce_MidiMessageCollector.h"
#include "midi_io/juce_MidiOutput.h"
#include "sources/juce_AudioSourcePlayer.h"
#include "sources/juce_AudioTransportSource.h"
#include "audio_cd/juce_AudioCDBurner.h"
#include "audio_cd/juce_AudioCDReader.h"
#include "audio_io/juce_AudioDeviceManager.h"
}
#endif // JUCE_AUDIO_DEVICES_H_INCLUDED

+ 25
- 0
source/modules/juce_audio_devices/juce_audio_devices.mm View File

@@ -0,0 +1,25 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#include "juce_audio_devices.cpp"

+ 28
- 0
source/modules/juce_audio_devices/juce_module_info View File

@@ -0,0 +1,28 @@
{
"id": "juce_audio_devices",
"name": "JUCE audio and midi I/O device classes",
"version": "2.1.3",
"description": "Classes to play and record from audio and midi i/o devices.",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",
"dependencies": [ { "id": "juce_audio_basics", "version": "matching" },
{ "id": "juce_audio_formats", "version": "matching" },
{ "id": "juce_events", "version": "matching" } ],
"include": "juce_audio_devices.h",
"compile": [ { "file": "juce_audio_devices.cpp", "target": "! xcode" },
{ "file": "juce_audio_devices.mm", "target": "xcode" } ],
"browse": [ "audio_io/*",
"midi_io/*",
"sources/*",
"audio_cd/*",
"native/*" ],
"OSXFrameworks": "CoreAudio CoreMIDI DiscRecording",
"iOSFrameworks": "AudioToolbox CoreMIDI",
"LinuxLibs": "asound",
"mingwLibs": "winmm"
}

+ 182
- 0
source/modules/juce_audio_devices/midi_io/juce_MidiInput.h View File

@@ -0,0 +1,182 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_MIDIINPUT_H_INCLUDED
#define JUCE_MIDIINPUT_H_INCLUDED
class MidiInput;
//==============================================================================
/**
Receives incoming messages from a physical MIDI input device.
This class is overridden to handle incoming midi messages. See the MidiInput
class for more details.
@see MidiInput
*/
class JUCE_API MidiInputCallback
{
public:
/** Destructor. */
virtual ~MidiInputCallback() {}
/** Receives an incoming message.
A MidiInput object will call this method when a midi event arrives. It'll be
called on a high-priority system thread, so avoid doing anything time-consuming
in here, and avoid making any UI calls. You might find the MidiBuffer class helpful
for queueing incoming messages for use later.
@param source the MidiInput object that generated the message
@param message the incoming message. The message's timestamp is set to a value
equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the
time when the message arrived.
*/
virtual void handleIncomingMidiMessage (MidiInput* source,
const MidiMessage& message) = 0;
/** Notification sent each time a packet of a multi-packet sysex message arrives.
If a long sysex message is broken up into multiple packets, this callback is made
for each packet that arrives until the message is finished, at which point
the normal handleIncomingMidiMessage() callback will be made with the entire
message.
The message passed in will contain the start of a sysex, but won't be finished
with the terminating 0xf7 byte.
*/
virtual void handlePartialSysexMessage (MidiInput* source,
const uint8* messageData,
int numBytesSoFar,
double timestamp)
{
// (this bit is just to avoid compiler warnings about unused variables)
(void) source; (void) messageData; (void) numBytesSoFar; (void) timestamp;
}
};
//==============================================================================
/**
Represents a midi input device.
To create one of these, use the static getDevices() method to find out what inputs are
available, and then use the openDevice() method to try to open one.
@see MidiOutput
*/
class JUCE_API MidiInput
{
public:
//==============================================================================
/** Returns a list of the available midi input devices.
You can open one of the devices by passing its index into the
openDevice() method.
@see getDefaultDeviceIndex, openDevice
*/
static StringArray getDevices();
/** Returns the index of the default midi input device to use.
This refers to the index in the list returned by getDevices().
*/
static int getDefaultDeviceIndex();
/** Tries to open one of the midi input devices.
This will return a MidiInput object if it manages to open it. You can then
call start() and stop() on this device, and delete it when no longer needed.
If the device can't be opened, this will return a null pointer.
@param deviceIndex the index of a device from the list returned by getDevices()
@param callback the object that will receive the midi messages from this device.
@see MidiInputCallback, getDevices
*/
static MidiInput* openDevice (int deviceIndex,
MidiInputCallback* callback);
#if JUCE_LINUX || JUCE_MAC || JUCE_IOS || DOXYGEN
/** This will try to create a new midi input device (Not available on Windows).
This will attempt to create a new midi input device with the specified name,
for other apps to connect to.
Returns nullptr if a device can't be created.
@param deviceName the name to use for the new device
@param callback the object that will receive the midi messages from this device.
*/
static MidiInput* createNewDevice (const String& deviceName,
MidiInputCallback* callback);
#endif
//==============================================================================
/** Destructor. */
virtual ~MidiInput();
/** Returns the name of this device. */
const String& getName() const noexcept { return name; }
/** Allows you to set a custom name for the device, in case you don't like the name
it was given when created.
*/
void setName (const String& newName) noexcept { name = newName; }
//==============================================================================
/** Starts the device running.
After calling this, the device will start sending midi messages to the
MidiInputCallback object that was specified when the openDevice() method
was called.
@see stop
*/
virtual void start();
/** Stops the device running.
@see start
*/
virtual void stop();
protected:
//==============================================================================
String name;
void* internal;
explicit MidiInput (const String& name);
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput)
};
#endif // JUCE_MIDIINPUT_H_INCLUDED

+ 153
- 0
source/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp View File

@@ -0,0 +1,153 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
MidiMessageCollector::MidiMessageCollector()
: lastCallbackTime (0),
sampleRate (44100.0001)
{
}
MidiMessageCollector::~MidiMessageCollector()
{
}
//==============================================================================
void MidiMessageCollector::reset (const double sampleRate_)
{
jassert (sampleRate_ > 0);
const ScopedLock sl (midiCallbackLock);
sampleRate = sampleRate_;
incomingMessages.clear();
lastCallbackTime = Time::getMillisecondCounterHiRes();
}
void MidiMessageCollector::addMessageToQueue (const MidiMessage& message)
{
// you need to call reset() to set the correct sample rate before using this object
jassert (sampleRate != 44100.0001);
// the messages that come in here need to be time-stamped correctly - see MidiInput
// for details of what the number should be.
jassert (message.getTimeStamp() != 0);
const ScopedLock sl (midiCallbackLock);
const int sampleNumber
= (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate);
incomingMessages.addEvent (message, sampleNumber);
// if the messages don't get used for over a second, we'd better
// get rid of any old ones to avoid the queue getting too big
if (sampleNumber > sampleRate)
incomingMessages.clear (0, sampleNumber - (int) sampleRate);
}
void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer,
const int numSamples)
{
// you need to call reset() to set the correct sample rate before using this object
jassert (sampleRate != 44100.0001);
jassert (numSamples > 0);
const double timeNow = Time::getMillisecondCounterHiRes();
const double msElapsed = timeNow - lastCallbackTime;
const ScopedLock sl (midiCallbackLock);
lastCallbackTime = timeNow;
if (! incomingMessages.isEmpty())
{
int numSourceSamples = jmax (1, roundToInt (msElapsed * 0.001 * sampleRate));
int startSample = 0;
int scale = 1 << 16;
const uint8* midiData;
int numBytes, samplePosition;
MidiBuffer::Iterator iter (incomingMessages);
if (numSourceSamples > numSamples)
{
// if our list of events is longer than the buffer we're being
// asked for, scale them down to squeeze them all in..
const int maxBlockLengthToUse = numSamples << 5;
if (numSourceSamples > maxBlockLengthToUse)
{
startSample = numSourceSamples - maxBlockLengthToUse;
numSourceSamples = maxBlockLengthToUse;
iter.setNextSamplePosition (startSample);
}
scale = (numSamples << 10) / numSourceSamples;
while (iter.getNextEvent (midiData, numBytes, samplePosition))
{
samplePosition = ((samplePosition - startSample) * scale) >> 10;
destBuffer.addEvent (midiData, numBytes,
jlimit (0, numSamples - 1, samplePosition));
}
}
else
{
// if our event list is shorter than the number we need, put them
// towards the end of the buffer
startSample = numSamples - numSourceSamples;
while (iter.getNextEvent (midiData, numBytes, samplePosition))
{
destBuffer.addEvent (midiData, numBytes,
jlimit (0, numSamples - 1, samplePosition + startSample));
}
}
incomingMessages.clear();
}
}
//==============================================================================
void MidiMessageCollector::handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity)
{
MidiMessage m (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity));
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
addMessageToQueue (m);
}
void MidiMessageCollector::handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber)
{
MidiMessage m (MidiMessage::noteOff (midiChannel, midiNoteNumber));
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
addMessageToQueue (m);
}
void MidiMessageCollector::handleIncomingMidiMessage (MidiInput*, const MidiMessage& message)
{
addMessageToQueue (message);
}

+ 104
- 0
source/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.h View File

@@ -0,0 +1,104 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_MIDIMESSAGECOLLECTOR_H_INCLUDED
#define JUCE_MIDIMESSAGECOLLECTOR_H_INCLUDED
//==============================================================================
/**
Collects incoming realtime MIDI messages and turns them into blocks suitable for
processing by a block-based audio callback.
The class can also be used as either a MidiKeyboardStateListener or a MidiInputCallback
so it can easily use a midi input or keyboard component as its source.
@see MidiMessage, MidiInput
*/
class JUCE_API MidiMessageCollector : public MidiKeyboardStateListener,
public MidiInputCallback
{
public:
//==============================================================================
/** Creates a MidiMessageCollector. */
MidiMessageCollector();
/** Destructor. */
~MidiMessageCollector();
//==============================================================================
/** Clears any messages from the queue.
You need to call this method before starting to use the collector, so that
it knows the correct sample rate to use.
*/
void reset (double sampleRate);
/** Takes an incoming real-time message and adds it to the queue.
The message's timestamp is taken, and it will be ready for retrieval as part
of the block returned by the next call to removeNextBlockOfMessages().
This method is fully thread-safe when overlapping calls are made with
removeNextBlockOfMessages().
*/
void addMessageToQueue (const MidiMessage& message);
/** Removes all the pending messages from the queue as a buffer.
This will also correct the messages' timestamps to make sure they're in
the range 0 to numSamples - 1.
This call should be made regularly by something like an audio processing
callback, because the time that it happens is used in calculating the
midi event positions.
This method is fully thread-safe when overlapping calls are made with
addMessageToQueue().
Precondition: numSamples must be greater than 0.
*/
void removeNextBlockOfMessages (MidiBuffer& destBuffer, int numSamples);
//==============================================================================
/** @internal */
void handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) override;
/** @internal */
void handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber) override;
/** @internal */
void handleIncomingMidiMessage (MidiInput*, const MidiMessage&) override;
private:
//==============================================================================
double lastCallbackTime;
CriticalSection midiCallbackLock;
MidiBuffer incomingMessages;
double sampleRate;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiMessageCollector)
};
#endif // JUCE_MIDIMESSAGECOLLECTOR_H_INCLUDED

+ 162
- 0
source/modules/juce_audio_devices/midi_io/juce_MidiOutput.cpp View File

@@ -0,0 +1,162 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
struct MidiOutput::PendingMessage
{
PendingMessage (const void* const data, const int len, const double timeStamp)
: message (data, len, timeStamp)
{}
MidiMessage message;
PendingMessage* next;
};
MidiOutput::MidiOutput()
: Thread ("midi out"),
internal (nullptr),
firstMessage (nullptr)
{
}
void MidiOutput::sendBlockOfMessages (const MidiBuffer& buffer,
const double millisecondCounterToStartAt,
double samplesPerSecondForBuffer)
{
// You've got to call startBackgroundThread() for this to actually work..
jassert (isThreadRunning());
// this needs to be a value in the future - RTFM for this method!
jassert (millisecondCounterToStartAt > 0);
const double timeScaleFactor = 1000.0 / samplesPerSecondForBuffer;
MidiBuffer::Iterator i (buffer);
const uint8* data;
int len, time;
while (i.getNextEvent (data, len, time))
{
const double eventTime = millisecondCounterToStartAt + timeScaleFactor * time;
PendingMessage* const m = new PendingMessage (data, len, eventTime);
const ScopedLock sl (lock);
if (firstMessage == nullptr || firstMessage->message.getTimeStamp() > eventTime)
{
m->next = firstMessage;
firstMessage = m;
}
else
{
PendingMessage* mm = firstMessage;
while (mm->next != nullptr && mm->next->message.getTimeStamp() <= eventTime)
mm = mm->next;
m->next = mm->next;
mm->next = m;
}
}
notify();
}
void MidiOutput::clearAllPendingMessages()
{
const ScopedLock sl (lock);
while (firstMessage != nullptr)
{
PendingMessage* const m = firstMessage;
firstMessage = firstMessage->next;
delete m;
}
}
void MidiOutput::startBackgroundThread()
{
startThread (9);
}
void MidiOutput::stopBackgroundThread()
{
stopThread (5000);
}
void MidiOutput::run()
{
while (! threadShouldExit())
{
uint32 now = Time::getMillisecondCounter();
uint32 eventTime = 0;
uint32 timeToWait = 500;
PendingMessage* message;
{
const ScopedLock sl (lock);
message = firstMessage;
if (message != nullptr)
{
eventTime = (uint32) roundToInt (message->message.getTimeStamp());
if (eventTime > now + 20)
{
timeToWait = eventTime - (now + 20);
message = nullptr;
}
else
{
firstMessage = message->next;
}
}
}
if (message != nullptr)
{
const ScopedPointer<PendingMessage> messageDeleter (message);
if (eventTime > now)
{
Time::waitForMillisecondCounter (eventTime);
if (threadShouldExit())
break;
}
if (eventTime > now - 200)
sendMessageNow (message->message);
}
else
{
jassert (timeToWait < 1000 * 30);
wait ((int) timeToWait);
}
}
clearAllPendingMessages();
}

+ 147
- 0
source/modules/juce_audio_devices/midi_io/juce_MidiOutput.h View File

@@ -0,0 +1,147 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_MIDIOUTPUT_H_INCLUDED
#define JUCE_MIDIOUTPUT_H_INCLUDED
//==============================================================================
/**
Controls a physical MIDI output device.
To create one of these, use the static getDevices() method to get a list of the
available output devices, then use the openDevice() method to try to open one.
@see MidiInput
*/
class JUCE_API MidiOutput : private Thread
{
public:
//==============================================================================
/** Returns a list of the available midi output devices.
You can open one of the devices by passing its index into the
openDevice() method.
@see getDefaultDeviceIndex, openDevice
*/
static StringArray getDevices();
/** Returns the index of the default midi output device to use.
This refers to the index in the list returned by getDevices().
*/
static int getDefaultDeviceIndex();
/** Tries to open one of the midi output devices.
This will return a MidiOutput object if it manages to open it. You can then
send messages to this device, and delete it when no longer needed.
If the device can't be opened, this will return a null pointer.
@param deviceIndex the index of a device from the list returned by getDevices()
@see getDevices
*/
static MidiOutput* openDevice (int deviceIndex);
#if JUCE_LINUX || JUCE_MAC || JUCE_IOS || DOXYGEN
/** This will try to create a new midi output device (Not available on Windows).
This will attempt to create a new midi output device that other apps can connect
to and use as their midi input.
Returns nullptr if a device can't be created.
@param deviceName the name to use for the new device
*/
static MidiOutput* createNewDevice (const String& deviceName);
#endif
//==============================================================================
/** Destructor. */
virtual ~MidiOutput();
/** Makes this device output a midi message.
@see MidiMessage
*/
virtual void sendMessageNow (const MidiMessage& message);
//==============================================================================
/** This lets you supply a block of messages that will be sent out at some point
in the future.
The MidiOutput class has an internal thread that can send out timestamped
messages - this appends a set of messages to its internal buffer, ready for
sending.
This will only work if you've already started the thread with startBackgroundThread().
A time is supplied, at which the block of messages should be sent. This time uses
the same time base as Time::getMillisecondCounter(), and must be in the future.
The samplesPerSecondForBuffer parameter indicates the number of samples per second
used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the
samplesPerSecondForBuffer value is needed to convert this sample position to a
real time.
*/
virtual void sendBlockOfMessages (const MidiBuffer& buffer,
double millisecondCounterToStartAt,
double samplesPerSecondForBuffer);
/** Gets rid of any midi messages that had been added by sendBlockOfMessages().
*/
virtual void clearAllPendingMessages();
/** Starts up a background thread so that the device can send blocks of data.
Call this to get the device ready, before using sendBlockOfMessages().
*/
virtual void startBackgroundThread();
/** Stops the background thread, and clears any pending midi events.
@see startBackgroundThread
*/
virtual void stopBackgroundThread();
protected:
//==============================================================================
void* internal;
CriticalSection lock;
struct PendingMessage;
PendingMessage* firstMessage;
MidiOutput();
void run() override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput)
};
#endif // JUCE_MIDIOUTPUT_H_INCLUDED

+ 175
- 0
source/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h View File

@@ -0,0 +1,175 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_MIDIDATACONCATENATOR_H_INCLUDED
#define JUCE_MIDIDATACONCATENATOR_H_INCLUDED
//==============================================================================
/**
Helper class that takes chunks of incoming midi bytes, packages them into
messages, and dispatches them to a midi callback.
*/
class MidiDataConcatenator
{
public:
//==============================================================================
MidiDataConcatenator (const int initialBufferSize)
: pendingData ((size_t) initialBufferSize),
pendingDataTime (0), pendingBytes (0), runningStatus (0)
{
}
void reset()
{
pendingBytes = 0;
runningStatus = 0;
pendingDataTime = 0;
}
template <typename UserDataType, typename CallbackType>
void pushMidiData (const void* inputData, int numBytes, double time,
UserDataType* input, CallbackType& callback)
{
const uint8* d = static_cast <const uint8*> (inputData);
while (numBytes > 0)
{
if (pendingBytes > 0 || d[0] == 0xf0)
{
processSysex (d, numBytes, time, input, callback);
runningStatus = 0;
}
else
{
int len = 0;
uint8 data[3];
while (numBytes > 0)
{
// If there's a realtime message embedded in the middle of
// the normal message, handle it now..
if (*d >= 0xf8 && *d <= 0xfe)
{
const MidiMessage m (*d++, time);
callback.handleIncomingMidiMessage (input, m);
--numBytes;
}
else
{
if (len == 0 && *d < 0x80 && runningStatus >= 0x80)
data[len++] = runningStatus;
data[len++] = *d++;
--numBytes;
if (len >= MidiMessage::getMessageLengthFromFirstByte (data[0]))
break;
}
}
if (len > 0)
{
int used = 0;
const MidiMessage m (data, len, used, 0, time);
if (used <= 0)
break; // malformed message..
jassert (used == len);
callback.handleIncomingMidiMessage (input, m);
runningStatus = data[0];
}
}
}
}
private:
template <typename UserDataType, typename CallbackType>
void processSysex (const uint8*& d, int& numBytes, double time,
UserDataType* input, CallbackType& callback)
{
if (*d == 0xf0)
{
pendingBytes = 0;
pendingDataTime = time;
}
pendingData.ensureSize ((size_t) (pendingBytes + numBytes), false);
uint8* totalMessage = static_cast<uint8*> (pendingData.getData());
uint8* dest = totalMessage + pendingBytes;
do
{
if (pendingBytes > 0 && *d >= 0x80)
{
if (*d >= 0xfa || *d == 0xf8)
{
callback.handleIncomingMidiMessage (input, MidiMessage (*d, time));
++d;
--numBytes;
}
else
{
if (*d == 0xf7)
{
*dest++ = *d++;
pendingBytes++;
--numBytes;
}
break;
}
}
else
{
*dest++ = *d++;
pendingBytes++;
--numBytes;
}
}
while (numBytes > 0);
if (pendingBytes > 0)
{
if (totalMessage [pendingBytes - 1] == 0xf7)
{
callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime));
pendingBytes = 0;
}
else
{
callback.handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime);
}
}
}
MemoryBlock pendingData;
double pendingDataTime;
int pendingBytes;
uint8 runningStatus;
JUCE_DECLARE_NON_COPYABLE (MidiDataConcatenator)
};
#endif // JUCE_MIDIDATACONCATENATOR_H_INCLUDED

+ 443
- 0
source/modules/juce_audio_devices/native/juce_android_Audio.cpp View File

@@ -0,0 +1,443 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
STATICMETHOD (getMinBufferSize, "getMinBufferSize", "(III)I") \
STATICMETHOD (getNativeOutputSampleRate, "getNativeOutputSampleRate", "(I)I") \
METHOD (constructor, "<init>", "(IIIIII)V") \
METHOD (getState, "getState", "()I") \
METHOD (play, "play", "()V") \
METHOD (stop, "stop", "()V") \
METHOD (release, "release", "()V") \
METHOD (flush, "flush", "()V") \
METHOD (write, "write", "([SII)I") \
DECLARE_JNI_CLASS (AudioTrack, "android/media/AudioTrack");
#undef JNI_CLASS_MEMBERS
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
STATICMETHOD (getMinBufferSize, "getMinBufferSize", "(III)I") \
METHOD (constructor, "<init>", "(IIIII)V") \
METHOD (getState, "getState", "()I") \
METHOD (startRecording, "startRecording", "()V") \
METHOD (stop, "stop", "()V") \
METHOD (read, "read", "([SII)I") \
METHOD (release, "release", "()V") \
DECLARE_JNI_CLASS (AudioRecord, "android/media/AudioRecord");
#undef JNI_CLASS_MEMBERS
//==============================================================================
enum
{
CHANNEL_OUT_STEREO = 12,
CHANNEL_IN_STEREO = 12,
CHANNEL_IN_MONO = 16,
ENCODING_PCM_16BIT = 2,
STREAM_MUSIC = 3,
MODE_STREAM = 1,
STATE_UNINITIALIZED = 0
};
const char* const javaAudioTypeName = "Android Audio";
//==============================================================================
class AndroidAudioIODevice : public AudioIODevice,
public Thread
{
public:
//==============================================================================
AndroidAudioIODevice (const String& deviceName)
: AudioIODevice (deviceName, javaAudioTypeName),
Thread ("audio"),
minBufferSizeOut (0), minBufferSizeIn (0), callback (0), sampleRate (0),
numClientInputChannels (0), numDeviceInputChannels (0), numDeviceInputChannelsAvailable (2),
numClientOutputChannels (0), numDeviceOutputChannels (0),
actualBufferSize (0), isRunning (false),
inputChannelBuffer (1, 1),
outputChannelBuffer (1, 1)
{
JNIEnv* env = getEnv();
sampleRate = env->CallStaticIntMethod (AudioTrack, AudioTrack.getNativeOutputSampleRate, MODE_STREAM);
minBufferSizeOut = (int) env->CallStaticIntMethod (AudioTrack, AudioTrack.getMinBufferSize, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT);
minBufferSizeIn = (int) env->CallStaticIntMethod (AudioRecord, AudioRecord.getMinBufferSize, sampleRate, CHANNEL_IN_STEREO, ENCODING_PCM_16BIT);
if (minBufferSizeIn <= 0)
{
minBufferSizeIn = env->CallStaticIntMethod (AudioRecord, AudioRecord.getMinBufferSize, sampleRate, CHANNEL_IN_MONO, ENCODING_PCM_16BIT);
if (minBufferSizeIn > 0)
numDeviceInputChannelsAvailable = 1;
else
numDeviceInputChannelsAvailable = 0;
}
DBG ("Audio device - min buffers: " << minBufferSizeOut << ", " << minBufferSizeIn << "; "
<< sampleRate << " Hz; input chans: " << numDeviceInputChannelsAvailable);
}
~AndroidAudioIODevice()
{
close();
}
StringArray getOutputChannelNames()
{
StringArray s;
s.add ("Left");
s.add ("Right");
return s;
}
StringArray getInputChannelNames()
{
StringArray s;
if (numDeviceInputChannelsAvailable == 2)
{
s.add ("Left");
s.add ("Right");
}
else if (numDeviceInputChannelsAvailable == 1)
{
s.add ("Audio Input");
}
return s;
}
int getNumSampleRates() { return 1;}
double getSampleRate (int index) { return sampleRate; }
int getDefaultBufferSize() { return 2048; }
int getNumBufferSizesAvailable() { return 50; }
int getBufferSizeSamples (int index)
{
int n = 16;
for (int i = 0; i < index; ++i)
n += n < 64 ? 16
: (n < 512 ? 32
: (n < 1024 ? 64
: (n < 2048 ? 128 : 256)));
return n;
}
String open (const BigInteger& inputChannels,
const BigInteger& outputChannels,
double requestedSampleRate,
int bufferSize)
{
close();
if (sampleRate != (int) requestedSampleRate)
return "Sample rate not allowed";
lastError = String::empty;
int preferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
numDeviceInputChannels = 0;
numDeviceOutputChannels = 0;
activeOutputChans = outputChannels;
activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
numClientOutputChannels = activeOutputChans.countNumberOfSetBits();
activeInputChans = inputChannels;
activeInputChans.setRange (2, activeInputChans.getHighestBit(), false);
numClientInputChannels = activeInputChans.countNumberOfSetBits();
actualBufferSize = preferredBufferSize;
inputChannelBuffer.setSize (2, actualBufferSize);
inputChannelBuffer.clear();
outputChannelBuffer.setSize (2, actualBufferSize);
outputChannelBuffer.clear();
JNIEnv* env = getEnv();
if (numClientOutputChannels > 0)
{
numDeviceOutputChannels = 2;
outputDevice = GlobalRef (env->NewObject (AudioTrack, AudioTrack.constructor,
STREAM_MUSIC, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT,
(jint) (minBufferSizeOut * numDeviceOutputChannels * sizeof (int16)), MODE_STREAM));
if (env->CallIntMethod (outputDevice, AudioTrack.getState) != STATE_UNINITIALIZED)
isRunning = true;
else
outputDevice.clear(); // failed to open the device
}
if (numClientInputChannels > 0 && numDeviceInputChannelsAvailable > 0)
{
numDeviceInputChannels = jmin (numClientInputChannels, numDeviceInputChannelsAvailable);
inputDevice = GlobalRef (env->NewObject (AudioRecord, AudioRecord.constructor,
0 /* (default audio source) */, sampleRate,
numDeviceInputChannelsAvailable > 1 ? CHANNEL_IN_STEREO : CHANNEL_IN_MONO,
ENCODING_PCM_16BIT,
(jint) (minBufferSizeIn * numDeviceInputChannels * sizeof (int16))));
if (env->CallIntMethod (inputDevice, AudioRecord.getState) != STATE_UNINITIALIZED)
isRunning = true;
else
inputDevice.clear(); // failed to open the device
}
if (isRunning)
{
if (outputDevice != nullptr)
env->CallVoidMethod (outputDevice, AudioTrack.play);
if (inputDevice != nullptr)
env->CallVoidMethod (inputDevice, AudioRecord.startRecording);
startThread (8);
}
else
{
closeDevices();
}
return lastError;
}
void close()
{
if (isRunning)
{
stopThread (2000);
isRunning = false;
closeDevices();
}
}
int getOutputLatencyInSamples() { return (minBufferSizeOut * 3) / 4; }
int getInputLatencyInSamples() { return (minBufferSizeIn * 3) / 4; }
bool isOpen() { return isRunning; }
int getCurrentBufferSizeSamples() { return actualBufferSize; }
int getCurrentBitDepth() { return 16; }
double getCurrentSampleRate() { return sampleRate; }
BigInteger getActiveOutputChannels() const { return activeOutputChans; }
BigInteger getActiveInputChannels() const { return activeInputChans; }
String getLastError() { return lastError; }
bool isPlaying() { return isRunning && callback != 0; }
void start (AudioIODeviceCallback* newCallback)
{
if (isRunning && callback != newCallback)
{
if (newCallback != nullptr)
newCallback->audioDeviceAboutToStart (this);
const ScopedLock sl (callbackLock);
callback = newCallback;
}
}
void stop()
{
if (isRunning)
{
AudioIODeviceCallback* lastCallback;
{
const ScopedLock sl (callbackLock);
lastCallback = callback;
callback = nullptr;
}
if (lastCallback != nullptr)
lastCallback->audioDeviceStopped();
}
}
void run() override
{
JNIEnv* env = getEnv();
jshortArray audioBuffer = env->NewShortArray (actualBufferSize * jmax (numDeviceOutputChannels, numDeviceInputChannels));
while (! threadShouldExit())
{
if (inputDevice != nullptr)
{
jint numRead = env->CallIntMethod (inputDevice, AudioRecord.read, audioBuffer, 0, actualBufferSize * numDeviceInputChannels);
if (numRead < actualBufferSize * numDeviceInputChannels)
{
DBG ("Audio read under-run! " << numRead);
}
jshort* const src = env->GetShortArrayElements (audioBuffer, 0);
for (int chan = 0; chan < inputChannelBuffer.getNumChannels(); ++chan)
{
AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> d (inputChannelBuffer.getSampleData (chan));
if (chan < numDeviceInputChannels)
{
AudioData::Pointer <AudioData::Int16, AudioData::NativeEndian, AudioData::Interleaved, AudioData::Const> s (src + chan, numDeviceInputChannels);
d.convertSamples (s, actualBufferSize);
}
else
{
d.clearSamples (actualBufferSize);
}
}
env->ReleaseShortArrayElements (audioBuffer, src, 0);
}
if (threadShouldExit())
break;
{
const ScopedLock sl (callbackLock);
if (callback != nullptr)
{
callback->audioDeviceIOCallback ((const float**) inputChannelBuffer.getArrayOfChannels(), numClientInputChannels,
outputChannelBuffer.getArrayOfChannels(), numClientOutputChannels,
actualBufferSize);
}
else
{
outputChannelBuffer.clear();
}
}
if (outputDevice != nullptr)
{
if (threadShouldExit())
break;
jshort* const dest = env->GetShortArrayElements (audioBuffer, 0);
for (int chan = 0; chan < numDeviceOutputChannels; ++chan)
{
AudioData::Pointer <AudioData::Int16, AudioData::NativeEndian, AudioData::Interleaved, AudioData::NonConst> d (dest + chan, numDeviceOutputChannels);
const float* const sourceChanData = outputChannelBuffer.getSampleData (jmin (chan, outputChannelBuffer.getNumChannels() - 1));
AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> s (sourceChanData);
d.convertSamples (s, actualBufferSize);
}
env->ReleaseShortArrayElements (audioBuffer, dest, 0);
jint numWritten = env->CallIntMethod (outputDevice, AudioTrack.write, audioBuffer, 0, actualBufferSize * numDeviceOutputChannels);
if (numWritten < actualBufferSize * numDeviceOutputChannels)
{
DBG ("Audio write underrun! " << numWritten);
}
}
}
}
int minBufferSizeOut, minBufferSizeIn;
private:
//==================================================================================================
CriticalSection callbackLock;
AudioIODeviceCallback* callback;
jint sampleRate;
int numClientInputChannels, numDeviceInputChannels, numDeviceInputChannelsAvailable;
int numClientOutputChannels, numDeviceOutputChannels;
int actualBufferSize;
bool isRunning;
String lastError;
BigInteger activeOutputChans, activeInputChans;
GlobalRef outputDevice, inputDevice;
AudioSampleBuffer inputChannelBuffer, outputChannelBuffer;
void closeDevices()
{
if (outputDevice != nullptr)
{
outputDevice.callVoidMethod (AudioTrack.stop);
outputDevice.callVoidMethod (AudioTrack.release);
outputDevice.clear();
}
if (inputDevice != nullptr)
{
inputDevice.callVoidMethod (AudioRecord.stop);
inputDevice.callVoidMethod (AudioRecord.release);
inputDevice.clear();
}
}
JUCE_DECLARE_NON_COPYABLE (AndroidAudioIODevice)
};
//==============================================================================
class AndroidAudioIODeviceType : public AudioIODeviceType
{
public:
AndroidAudioIODeviceType() : AudioIODeviceType (javaAudioTypeName) {}
//==============================================================================
void scanForDevices() {}
StringArray getDeviceNames (bool wantInputNames) const { return StringArray (javaAudioTypeName); }
int getDefaultDeviceIndex (bool forInput) const { return 0; }
int getIndexOfDevice (AudioIODevice* device, bool asInput) const { return device != nullptr ? 0 : -1; }
bool hasSeparateInputsAndOutputs() const { return false; }
AudioIODevice* createDevice (const String& outputDeviceName,
const String& inputDeviceName)
{
ScopedPointer<AndroidAudioIODevice> dev;
if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
{
dev = new AndroidAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName);
if (dev->getCurrentSampleRate() <= 0 || dev->getDefaultBufferSize() <= 0)
dev = nullptr;
}
return dev.release();
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidAudioIODeviceType)
};
//==============================================================================
extern bool isOpenSLAvailable();
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Android()
{
#if JUCE_USE_ANDROID_OPENSLES
if (isOpenSLAvailable())
return nullptr;
#endif
return new AndroidAudioIODeviceType();
}

+ 84
- 0
source/modules/juce_audio_devices/native/juce_android_Midi.cpp View File

@@ -0,0 +1,84 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
StringArray MidiOutput::getDevices()
{
StringArray devices;
return devices;
}
int MidiOutput::getDefaultDeviceIndex()
{
return 0;
}
MidiOutput* MidiOutput::openDevice (int index)
{
return nullptr;
}
MidiOutput::~MidiOutput()
{
}
void MidiOutput::sendMessageNow (const MidiMessage&)
{
}
//==============================================================================
MidiInput::MidiInput (const String& name_)
: name (name_),
internal (0)
{
}
MidiInput::~MidiInput()
{
}
void MidiInput::start()
{
}
void MidiInput::stop()
{
}
int MidiInput::getDefaultDeviceIndex()
{
return 0;
}
StringArray MidiInput::getDevices()
{
StringArray devs;
return devs;
}
MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
{
return nullptr;
}

+ 622
- 0
source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp View File

@@ -0,0 +1,622 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
const char* const openSLTypeName = "Android OpenSL";
bool isOpenSLAvailable()
{
DynamicLibrary library;
return library.open ("libOpenSLES.so");
}
const unsigned short openSLRates[] = { 8000, 16000, 32000, 44100, 48000 };
const unsigned short openSLBufferSizes[] = { 256, 512, 768, 1024, 1280, 1600 }; // must all be multiples of the block size
//==============================================================================
class OpenSLAudioIODevice : public AudioIODevice,
public Thread
{
public:
OpenSLAudioIODevice (const String& deviceName)
: AudioIODevice (deviceName, openSLTypeName),
Thread ("OpenSL"),
callback (nullptr), sampleRate (0), deviceOpen (false),
inputBuffer (2, 2), outputBuffer (2, 2)
{
// OpenSL has piss-poor support for determining latency, so the only way I can find to
// get a number for this is by asking the AudioTrack/AudioRecord classes..
AndroidAudioIODevice javaDevice (String::empty);
// this is a total guess about how to calculate the latency, but seems to vaguely agree
// with the devices I've tested.. YMMV
inputLatency = ((javaDevice.minBufferSizeIn * 2) / 3);
outputLatency = ((javaDevice.minBufferSizeOut * 2) / 3);
const int longestLatency = jmax (inputLatency, outputLatency);
const int totalLatency = inputLatency + outputLatency;
inputLatency = ((longestLatency * inputLatency) / totalLatency) & ~15;
outputLatency = ((longestLatency * outputLatency) / totalLatency) & ~15;
}
~OpenSLAudioIODevice()
{
close();
}
bool openedOk() const { return engine.outputMixObject != nullptr; }
StringArray getOutputChannelNames()
{
StringArray s;
s.add ("Left");
s.add ("Right");
return s;
}
StringArray getInputChannelNames()
{
StringArray s;
s.add ("Audio Input");
return s;
}
int getNumSampleRates() { return numElementsInArray (openSLRates); }
double getSampleRate (int index)
{
jassert (index >= 0 && index < getNumSampleRates());
return (int) openSLRates [index];
}
int getDefaultBufferSize() { return 1024; }
int getNumBufferSizesAvailable() { return numElementsInArray (openSLBufferSizes); }
int getBufferSizeSamples (int index)
{
jassert (index >= 0 && index < getNumBufferSizesAvailable());
return (int) openSLBufferSizes [index];
}
String open (const BigInteger& inputChannels,
const BigInteger& outputChannels,
double requestedSampleRate,
int bufferSize)
{
close();
lastError = String::empty;
sampleRate = (int) requestedSampleRate;
int preferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
activeOutputChans = outputChannels;
activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
numOutputChannels = activeOutputChans.countNumberOfSetBits();
activeInputChans = inputChannels;
activeInputChans.setRange (1, activeInputChans.getHighestBit(), false);
numInputChannels = activeInputChans.countNumberOfSetBits();
actualBufferSize = preferredBufferSize;
inputBuffer.setSize (jmax (1, numInputChannels), actualBufferSize);
outputBuffer.setSize (jmax (1, numOutputChannels), actualBufferSize);
outputBuffer.clear();
recorder = engine.createRecorder (numInputChannels, sampleRate);
player = engine.createPlayer (numOutputChannels, sampleRate);
startThread (8);
deviceOpen = true;
return lastError;
}
void close()
{
stop();
stopThread (6000);
deviceOpen = false;
recorder = nullptr;
player = nullptr;
}
int getOutputLatencyInSamples() { return outputLatency; }
int getInputLatencyInSamples() { return inputLatency; }
bool isOpen() { return deviceOpen; }
int getCurrentBufferSizeSamples() { return actualBufferSize; }
int getCurrentBitDepth() { return 16; }
double getCurrentSampleRate() { return sampleRate; }
BigInteger getActiveOutputChannels() const { return activeOutputChans; }
BigInteger getActiveInputChannels() const { return activeInputChans; }
String getLastError() { return lastError; }
bool isPlaying() { return callback != nullptr; }
void start (AudioIODeviceCallback* newCallback)
{
stop();
if (deviceOpen && callback != newCallback)
{
if (newCallback != nullptr)
newCallback->audioDeviceAboutToStart (this);
setCallback (newCallback);
}
}
void stop()
{
if (AudioIODeviceCallback* const oldCallback = setCallback (nullptr))
oldCallback->audioDeviceStopped();
}
void run() override
{
if (recorder != nullptr) recorder->start();
if (player != nullptr) player->start();
while (! threadShouldExit())
{
if (player != nullptr) player->writeBuffer (outputBuffer, *this);
if (recorder != nullptr) recorder->readNextBlock (inputBuffer, *this);
const ScopedLock sl (callbackLock);
if (callback != nullptr)
{
callback->audioDeviceIOCallback (numInputChannels > 0 ? (const float**) inputBuffer.getArrayOfChannels() : nullptr,
numInputChannels,
numOutputChannels > 0 ? outputBuffer.getArrayOfChannels() : nullptr,
numOutputChannels,
actualBufferSize);
}
else
{
outputBuffer.clear();
}
}
}
private:
//==================================================================================================
CriticalSection callbackLock;
AudioIODeviceCallback* callback;
int actualBufferSize, sampleRate;
int inputLatency, outputLatency;
bool deviceOpen;
String lastError;
BigInteger activeOutputChans, activeInputChans;
int numInputChannels, numOutputChannels;
AudioSampleBuffer inputBuffer, outputBuffer;
struct Player;
struct Recorder;
AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
{
const ScopedLock sl (callbackLock);
AudioIODeviceCallback* const oldCallback = callback;
callback = newCallback;
return oldCallback;
}
//==================================================================================================
struct Engine
{
Engine()
: engineObject (nullptr), engineInterface (nullptr), outputMixObject (nullptr)
{
if (library.open ("libOpenSLES.so"))
{
typedef SLresult (*CreateEngineFunc) (SLObjectItf*, SLuint32, const SLEngineOption*, SLuint32, const SLInterfaceID*, const SLboolean*);
if (CreateEngineFunc createEngine = (CreateEngineFunc) library.getFunction ("slCreateEngine"))
{
check (createEngine (&engineObject, 0, nullptr, 0, nullptr, nullptr));
SLInterfaceID* SL_IID_ENGINE = (SLInterfaceID*) library.getFunction ("SL_IID_ENGINE");
SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
SL_IID_PLAY = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY");
SL_IID_RECORD = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD");
check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE));
check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface));
check ((*engineInterface)->CreateOutputMix (engineInterface, &outputMixObject, 0, nullptr, nullptr));
check ((*outputMixObject)->Realize (outputMixObject, SL_BOOLEAN_FALSE));
}
}
}
~Engine()
{
if (outputMixObject != nullptr) (*outputMixObject)->Destroy (outputMixObject);
if (engineObject != nullptr) (*engineObject)->Destroy (engineObject);
}
Player* createPlayer (const int numChannels, const int sampleRate)
{
if (numChannels <= 0)
return nullptr;
ScopedPointer<Player> player (new Player (numChannels, sampleRate, *this));
return player->openedOk() ? player.release() : nullptr;
}
Recorder* createRecorder (const int numChannels, const int sampleRate)
{
if (numChannels <= 0)
return nullptr;
ScopedPointer<Recorder> recorder (new Recorder (numChannels, sampleRate, *this));
return recorder->openedOk() ? recorder.release() : nullptr;
}
SLObjectItf engineObject;
SLEngineItf engineInterface;
SLObjectItf outputMixObject;
SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
SLInterfaceID* SL_IID_PLAY;
SLInterfaceID* SL_IID_RECORD;
private:
DynamicLibrary library;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Engine)
};
//==================================================================================================
struct BufferList
{
BufferList (const int numChannels_)
: numChannels (numChannels_), bufferSpace (numChannels_ * numSamples * numBuffers), nextBlock (0)
{
}
int16* waitForFreeBuffer (Thread& threadToCheck)
{
while (numBlocksOut.get() == numBuffers)
{
dataArrived.wait (1);
if (threadToCheck.threadShouldExit())
return nullptr;
}
return getNextBuffer();
}
int16* getNextBuffer()
{
if (++nextBlock == numBuffers)
nextBlock = 0;
return bufferSpace + nextBlock * numChannels * numSamples;
}
void bufferReturned() { --numBlocksOut; dataArrived.signal(); }
void bufferSent() { ++numBlocksOut; dataArrived.signal(); }
int getBufferSizeBytes() const { return numChannels * numSamples * sizeof (int16); }
const int numChannels;
enum { numSamples = 256, numBuffers = 16 };
private:
HeapBlock<int16> bufferSpace;
int nextBlock;
Atomic<int> numBlocksOut;
WaitableEvent dataArrived;
};
//==================================================================================================
struct Player
{
Player (int numChannels, int sampleRate, Engine& engine)
: playerObject (nullptr), playerPlay (nullptr), playerBufferQueue (nullptr),
bufferList (numChannels)
{
jassert (numChannels == 2);
SLDataFormat_PCM pcmFormat =
{
SL_DATAFORMAT_PCM,
numChannels,
sampleRate * 1000, // (sample rate units are millihertz)
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN
};
SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, bufferList.numBuffers };
SLDataSource audioSrc = { &bufferQueue, &pcmFormat };
SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, engine.outputMixObject };
SLDataSink audioSink = { &outputMix, nullptr };
// (SL_IID_BUFFERQUEUE is not guaranteed to remain future-proof, so use SL_IID_ANDROIDSIMPLEBUFFERQUEUE)
const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean flags[] = { SL_BOOLEAN_TRUE };
check ((*engine.engineInterface)->CreateAudioPlayer (engine.engineInterface, &playerObject, &audioSrc, &audioSink,
1, interfaceIDs, flags));
check ((*playerObject)->Realize (playerObject, SL_BOOLEAN_FALSE));
check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_PLAY, &playerPlay));
check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &playerBufferQueue));
check ((*playerBufferQueue)->RegisterCallback (playerBufferQueue, staticCallback, this));
}
~Player()
{
if (playerPlay != nullptr)
check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_STOPPED));
if (playerBufferQueue != nullptr)
check ((*playerBufferQueue)->Clear (playerBufferQueue));
if (playerObject != nullptr)
(*playerObject)->Destroy (playerObject);
}
bool openedOk() const noexcept { return playerBufferQueue != nullptr; }
void start()
{
jassert (openedOk());
check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_PLAYING));
}
void writeBuffer (const AudioSampleBuffer& buffer, Thread& thread)
{
jassert (buffer.getNumChannels() == bufferList.numChannels);
jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
int offset = 0;
int numSamples = buffer.getNumSamples();
while (numSamples > 0)
{
int16* const destBuffer = bufferList.waitForFreeBuffer (thread);
if (destBuffer == nullptr)
break;
for (int i = 0; i < bufferList.numChannels; ++i)
{
typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> DstSampleType;
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SrcSampleType;
DstSampleType dstData (destBuffer + i, bufferList.numChannels);
SrcSampleType srcData (buffer.getSampleData (i, offset));
dstData.convertSamples (srcData, bufferList.numSamples);
}
check ((*playerBufferQueue)->Enqueue (playerBufferQueue, destBuffer, bufferList.getBufferSizeBytes()));
bufferList.bufferSent();
numSamples -= bufferList.numSamples;
offset += bufferList.numSamples;
}
}
private:
SLObjectItf playerObject;
SLPlayItf playerPlay;
SLAndroidSimpleBufferQueueItf playerBufferQueue;
BufferList bufferList;
static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context)
{
jassert (queue == static_cast <Player*> (context)->playerBufferQueue); (void) queue;
static_cast <Player*> (context)->bufferList.bufferReturned();
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Player)
};
//==================================================================================================
struct Recorder
{
Recorder (int numChannels, int sampleRate, Engine& engine)
: recorderObject (nullptr), recorderRecord (nullptr), recorderBufferQueue (nullptr),
bufferList (numChannels)
{
jassert (numChannels == 1); // STEREO doesn't always work!!
SLDataFormat_PCM pcmFormat =
{
SL_DATAFORMAT_PCM,
numChannels,
sampleRate * 1000, // (sample rate units are millihertz)
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
(numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
SL_BYTEORDER_LITTLEENDIAN
};
SLDataLocator_IODevice ioDevice = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
SLDataSource audioSrc = { &ioDevice, nullptr };
SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, bufferList.numBuffers };
SLDataSink audioSink = { &bufferQueue, &pcmFormat };
const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean flags[] = { SL_BOOLEAN_TRUE };
if (check ((*engine.engineInterface)->CreateAudioRecorder (engine.engineInterface, &recorderObject, &audioSrc,
&audioSink, 1, interfaceIDs, flags)))
{
if (check ((*recorderObject)->Realize (recorderObject, SL_BOOLEAN_FALSE)))
{
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord));
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue));
check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this));
check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
for (int i = bufferList.numBuffers; --i >= 0;)
{
int16* const buffer = bufferList.getNextBuffer();
jassert (buffer != nullptr);
enqueueBuffer (buffer);
}
}
}
}
~Recorder()
{
if (recorderRecord != nullptr)
check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
if (recorderBufferQueue != nullptr)
check ((*recorderBufferQueue)->Clear (recorderBufferQueue));
if (recorderObject != nullptr)
(*recorderObject)->Destroy (recorderObject);
}
bool openedOk() const noexcept { return recorderBufferQueue != nullptr; }
void start()
{
jassert (openedOk());
check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_RECORDING));
}
void readNextBlock (AudioSampleBuffer& buffer, Thread& thread)
{
jassert (buffer.getNumChannels() == bufferList.numChannels);
jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
jassert ((buffer.getNumSamples() % bufferList.numSamples) == 0);
int offset = 0;
int numSamples = buffer.getNumSamples();
while (numSamples > 0)
{
int16* const srcBuffer = bufferList.waitForFreeBuffer (thread);
if (srcBuffer == nullptr)
break;
for (int i = 0; i < bufferList.numChannels; ++i)
{
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DstSampleType;
typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const> SrcSampleType;
DstSampleType dstData (buffer.getSampleData (i, offset));
SrcSampleType srcData (srcBuffer + i, bufferList.numChannels);
dstData.convertSamples (srcData, bufferList.numSamples);
}
enqueueBuffer (srcBuffer);
numSamples -= bufferList.numSamples;
offset += bufferList.numSamples;
}
}
private:
SLObjectItf recorderObject;
SLRecordItf recorderRecord;
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
BufferList bufferList;
void enqueueBuffer (int16* buffer)
{
check ((*recorderBufferQueue)->Enqueue (recorderBufferQueue, buffer, bufferList.getBufferSizeBytes()));
bufferList.bufferSent();
}
static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context)
{
jassert (queue == static_cast <Recorder*> (context)->recorderBufferQueue); (void) queue;
static_cast <Recorder*> (context)->bufferList.bufferReturned();
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Recorder)
};
//==============================================================================
Engine engine;
ScopedPointer<Player> player;
ScopedPointer<Recorder> recorder;
//==============================================================================
static bool check (const SLresult result)
{
jassert (result == SL_RESULT_SUCCESS);
return result == SL_RESULT_SUCCESS;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice)
};
//==============================================================================
class OpenSLAudioDeviceType : public AudioIODeviceType
{
public:
OpenSLAudioDeviceType() : AudioIODeviceType (openSLTypeName) {}
//==============================================================================
void scanForDevices() {}
StringArray getDeviceNames (bool wantInputNames) const { return StringArray (openSLTypeName); }
int getDefaultDeviceIndex (bool forInput) const { return 0; }
int getIndexOfDevice (AudioIODevice* device, bool asInput) const { return device != nullptr ? 0 : -1; }
bool hasSeparateInputsAndOutputs() const { return false; }
AudioIODevice* createDevice (const String& outputDeviceName,
const String& inputDeviceName)
{
ScopedPointer<OpenSLAudioIODevice> dev;
if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
{
dev = new OpenSLAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName);
if (! dev->openedOk())
dev = nullptr;
}
return dev.release();
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType)
};
//==============================================================================
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_OpenSLES()
{
return isOpenSLAvailable() ? new OpenSLAudioDeviceType() : nullptr;
}

+ 555
- 0
source/modules/juce_audio_devices/native/juce_ios_Audio.cpp View File

@@ -0,0 +1,555 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
class iOSAudioIODevice : public AudioIODevice
{
public:
iOSAudioIODevice (const String& deviceName)
: AudioIODevice (deviceName, "Audio"),
actualBufferSize (0),
isRunning (false),
audioUnit (0),
callback (nullptr),
floatData (1, 2)
{
getSessionHolder().activeDevices.add (this);
numInputChannels = 2;
numOutputChannels = 2;
preferredBufferSize = 0;
updateDeviceInfo();
}
~iOSAudioIODevice()
{
getSessionHolder().activeDevices.removeFirstMatchingValue (this);
close();
}
StringArray getOutputChannelNames()
{
StringArray s;
s.add ("Left");
s.add ("Right");
return s;
}
StringArray getInputChannelNames()
{
StringArray s;
if (audioInputIsAvailable)
{
s.add ("Left");
s.add ("Right");
}
return s;
}
int getNumSampleRates() { return 1; }
double getSampleRate (int index) { return sampleRate; }
int getNumBufferSizesAvailable() { return 6; }
int getBufferSizeSamples (int index) { return 1 << (jlimit (0, 5, index) + 6); }
int getDefaultBufferSize() { return 1024; }
String open (const BigInteger& inputChannels,
const BigInteger& outputChannels,
double sampleRate,
int bufferSize)
{
close();
lastError = String::empty;
preferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
// xxx set up channel mapping
activeOutputChans = outputChannels;
activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
numOutputChannels = activeOutputChans.countNumberOfSetBits();
monoOutputChannelNumber = activeOutputChans.findNextSetBit (0);
activeInputChans = inputChannels;
activeInputChans.setRange (2, activeInputChans.getHighestBit(), false);
numInputChannels = activeInputChans.countNumberOfSetBits();
monoInputChannelNumber = activeInputChans.findNextSetBit (0);
AudioSessionSetActive (true);
UInt32 audioCategory = (numInputChannels > 0 && audioInputIsAvailable) ? kAudioSessionCategory_PlayAndRecord
: kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (audioCategory), &audioCategory);
if (audioCategory == kAudioSessionCategory_PlayAndRecord)
{
// (note: mustn't set this until after the audio category property has been set)
UInt32 allowBluetoothInput = 1;
AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,
sizeof (allowBluetoothInput), &allowBluetoothInput);
}
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, routingChangedStatic, this);
fixAudioRouteIfSetToReceiver();
updateDeviceInfo();
Float32 bufferDuration = preferredBufferSize / sampleRate;
AudioSessionSetProperty (kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof (bufferDuration), &bufferDuration);
actualBufferSize = preferredBufferSize;
prepareFloatBuffers (actualBufferSize);
isRunning = true;
routingChanged (nullptr); // creates and starts the AU
lastError = audioUnit != 0 ? "" : "Couldn't open the device";
return lastError;
}
void close()
{
if (isRunning)
{
isRunning = false;
AudioSessionRemovePropertyListenerWithUserData (kAudioSessionProperty_AudioRouteChange, routingChangedStatic, this);
AudioSessionSetActive (false);
if (audioUnit != 0)
{
AudioComponentInstanceDispose (audioUnit);
audioUnit = 0;
}
}
}
bool isOpen() { return isRunning; }
int getCurrentBufferSizeSamples() { return actualBufferSize; }
double getCurrentSampleRate() { return sampleRate; }
int getCurrentBitDepth() { return 16; }
BigInteger getActiveOutputChannels() const { return activeOutputChans; }
BigInteger getActiveInputChannels() const { return activeInputChans; }
int getOutputLatencyInSamples() { return 0; } //xxx
int getInputLatencyInSamples() { return 0; } //xxx
void start (AudioIODeviceCallback* newCallback)
{
if (isRunning && callback != newCallback)
{
if (newCallback != nullptr)
newCallback->audioDeviceAboutToStart (this);
const ScopedLock sl (callbackLock);
callback = newCallback;
}
}
void stop()
{
if (isRunning)
{
AudioIODeviceCallback* lastCallback;
{
const ScopedLock sl (callbackLock);
lastCallback = callback;
callback = nullptr;
}
if (lastCallback != nullptr)
lastCallback->audioDeviceStopped();
}
}
bool isPlaying() { return isRunning && callback != nullptr; }
String getLastError() { return lastError; }
private:
//==================================================================================================
CriticalSection callbackLock;
Float64 sampleRate;
int numInputChannels, numOutputChannels;
int preferredBufferSize, actualBufferSize;
bool isRunning;
String lastError;
AudioStreamBasicDescription format;
AudioUnit audioUnit;
UInt32 audioInputIsAvailable;
AudioIODeviceCallback* callback;
BigInteger activeOutputChans, activeInputChans;
AudioSampleBuffer floatData;
float* inputChannels[3];
float* outputChannels[3];
bool monoInputChannelNumber, monoOutputChannelNumber;
void prepareFloatBuffers (int bufferSize)
{
if (numInputChannels + numOutputChannels > 0)
{
floatData.setSize (numInputChannels + numOutputChannels, bufferSize);
zeromem (inputChannels, sizeof (inputChannels));
zeromem (outputChannels, sizeof (outputChannels));
for (int i = 0; i < numInputChannels; ++i)
inputChannels[i] = floatData.getSampleData (i);
for (int i = 0; i < numOutputChannels; ++i)
outputChannels[i] = floatData.getSampleData (i + numInputChannels);
}
}
//==================================================================================================
OSStatus process (AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time,
const UInt32 numFrames, AudioBufferList* data)
{
OSStatus err = noErr;
if (audioInputIsAvailable && numInputChannels > 0)
err = AudioUnitRender (audioUnit, flags, time, 1, numFrames, data);
const ScopedLock sl (callbackLock);
if (callback != nullptr)
{
// This shouldn't ever get triggered, but please let me know if it does!
jassert (numFrames <= floatData.getNumSamples());
if (audioInputIsAvailable && numInputChannels > 0)
{
short* shortData = (short*) data->mBuffers[0].mData;
if (numInputChannels >= 2)
{
for (UInt32 i = 0; i < numFrames; ++i)
{
inputChannels[0][i] = *shortData++ * (1.0f / 32768.0f);
inputChannels[1][i] = *shortData++ * (1.0f / 32768.0f);
}
}
else
{
if (monoInputChannelNumber > 0)
++shortData;
for (UInt32 i = 0; i < numFrames; ++i)
{
inputChannels[0][i] = *shortData++ * (1.0f / 32768.0f);
++shortData;
}
}
}
else
{
for (int i = numInputChannels; --i >= 0;)
zeromem (inputChannels[i], sizeof (float) * numFrames);
}
callback->audioDeviceIOCallback ((const float**) inputChannels, numInputChannels,
outputChannels, numOutputChannels, (int) numFrames);
short* shortData = (short*) data->mBuffers[0].mData;
int n = 0;
if (numOutputChannels >= 2)
{
for (UInt32 i = 0; i < numFrames; ++i)
{
shortData [n++] = (short) (outputChannels[0][i] * 32767.0f);
shortData [n++] = (short) (outputChannels[1][i] * 32767.0f);
}
}
else if (numOutputChannels == 1)
{
for (UInt32 i = 0; i < numFrames; ++i)
{
const short s = (short) (outputChannels[monoOutputChannelNumber][i] * 32767.0f);
shortData [n++] = s;
shortData [n++] = s;
}
}
else
{
zeromem (data->mBuffers[0].mData, 2 * sizeof (short) * numFrames);
}
}
else
{
zeromem (data->mBuffers[0].mData, 2 * sizeof (short) * numFrames);
}
return err;
}
void updateDeviceInfo()
{
UInt32 size = sizeof (sampleRate);
AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareSampleRate, &size, &sampleRate);
size = sizeof (audioInputIsAvailable);
AudioSessionGetProperty (kAudioSessionProperty_AudioInputAvailable, &size, &audioInputIsAvailable);
}
void routingChanged (const void* propertyValue)
{
if (! isRunning)
return;
if (propertyValue != nullptr)
{
CFDictionaryRef routeChangeDictionary = (CFDictionaryRef) propertyValue;
CFNumberRef routeChangeReasonRef = (CFNumberRef) CFDictionaryGetValue (routeChangeDictionary,
CFSTR (kAudioSession_AudioRouteChangeKey_Reason));
SInt32 routeChangeReason;
CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);
if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable)
{
const ScopedLock sl (callbackLock);
if (callback != nullptr)
callback->audioDeviceError ("Old device unavailable");
}
}
updateDeviceInfo();
createAudioUnit();
AudioSessionSetActive (true);
if (audioUnit != 0)
{
UInt32 formatSize = sizeof (format);
AudioUnitGetProperty (audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &format, &formatSize);
Float32 bufferDuration = preferredBufferSize / sampleRate;
UInt32 bufferDurationSize = sizeof (bufferDuration);
AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareIOBufferDuration, &bufferDurationSize, &bufferDuration);
actualBufferSize = (int) (sampleRate * bufferDuration + 0.5);
AudioOutputUnitStart (audioUnit);
}
}
//==================================================================================================
struct AudioSessionHolder
{
AudioSessionHolder()
{
AudioSessionInitialize (0, 0, interruptionListenerCallback, this);
}
static void interruptionListenerCallback (void* client, UInt32 interruptionType)
{
const Array <iOSAudioIODevice*>& activeDevices = static_cast <AudioSessionHolder*> (client)->activeDevices;
for (int i = activeDevices.size(); --i >= 0;)
activeDevices.getUnchecked(i)->interruptionListener (interruptionType);
}
Array <iOSAudioIODevice*> activeDevices;
};
static AudioSessionHolder& getSessionHolder()
{
static AudioSessionHolder audioSessionHolder;
return audioSessionHolder;
}
void interruptionListener (const UInt32 interruptionType)
{
if (interruptionType == kAudioSessionBeginInterruption)
{
isRunning = false;
AudioOutputUnitStop (audioUnit);
AudioSessionSetActive (false);
const ScopedLock sl (callbackLock);
if (callback != nullptr)
callback->audioDeviceError ("iOS audio session interruption");
}
if (interruptionType == kAudioSessionEndInterruption)
{
isRunning = true;
AudioSessionSetActive (true);
AudioOutputUnitStart (audioUnit);
}
}
//==================================================================================================
static OSStatus processStatic (void* client, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time,
UInt32 /*busNumber*/, UInt32 numFrames, AudioBufferList* data)
{
return static_cast <iOSAudioIODevice*> (client)->process (flags, time, numFrames, data);
}
static void routingChangedStatic (void* client, AudioSessionPropertyID, UInt32 /*inDataSize*/, const void* propertyValue)
{
static_cast <iOSAudioIODevice*> (client)->routingChanged (propertyValue);
}
//==================================================================================================
void resetFormat (const int numChannels) noexcept
{
zerostruct (format);
format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kAudioFormatFlagsNativeEndian;
format.mBitsPerChannel = 8 * sizeof (short);
format.mChannelsPerFrame = numChannels;
format.mFramesPerPacket = 1;
format.mBytesPerFrame = format.mBytesPerPacket = numChannels * sizeof (short);
}
bool createAudioUnit()
{
if (audioUnit != 0)
{
AudioComponentInstanceDispose (audioUnit);
audioUnit = 0;
}
resetFormat (2);
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
AudioComponent comp = AudioComponentFindNext (0, &desc);
AudioComponentInstanceNew (comp, &audioUnit);
if (audioUnit == 0)
return false;
if (numInputChannels > 0)
{
const UInt32 one = 1;
AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof (one));
}
{
AudioChannelLayout layout;
layout.mChannelBitmap = 0;
layout.mNumberChannelDescriptions = 0;
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Input, 0, &layout, sizeof (layout));
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Output, 0, &layout, sizeof (layout));
}
{
AURenderCallbackStruct inputProc;
inputProc.inputProc = processStatic;
inputProc.inputProcRefCon = this;
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &inputProc, sizeof (inputProc));
}
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, sizeof (format));
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &format, sizeof (format));
AudioUnitInitialize (audioUnit);
return true;
}
// If the routing is set to go through the receiver (i.e. the speaker, but quiet), this re-routes it
// to make it loud. Needed because by default when using an input + output, the output is kept quiet.
static void fixAudioRouteIfSetToReceiver()
{
CFStringRef audioRoute = 0;
UInt32 propertySize = sizeof (audioRoute);
if (AudioSessionGetProperty (kAudioSessionProperty_AudioRoute, &propertySize, &audioRoute) == noErr)
{
NSString* route = (NSString*) audioRoute;
//DBG ("audio route: " + nsStringToJuce (route));
if ([route hasPrefix: @"Receiver"])
{
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof (audioRouteOverride), &audioRouteOverride);
}
CFRelease (audioRoute);
}
}
JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice)
};
//==============================================================================
class iOSAudioIODeviceType : public AudioIODeviceType
{
public:
iOSAudioIODeviceType() : AudioIODeviceType ("iOS Audio")
{
}
void scanForDevices() {}
StringArray getDeviceNames (bool wantInputNames) const
{
return StringArray ("iOS Audio");
}
int getDefaultDeviceIndex (bool forInput) const
{
return 0;
}
int getIndexOfDevice (AudioIODevice* device, bool asInput) const
{
return device != nullptr ? 0 : -1;
}
bool hasSeparateInputsAndOutputs() const { return false; }
AudioIODevice* createDevice (const String& outputDeviceName,
const String& inputDeviceName)
{
if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
return new iOSAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName);
return nullptr;
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSAudioIODeviceType)
};
//==============================================================================
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_iOSAudio()
{
return new iOSAudioIODeviceType();
}

+ 1237
- 0
source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp
File diff suppressed because it is too large
View File


+ 77
- 0
source/modules/juce_audio_devices/native/juce_linux_AudioCDReader.cpp View File

@@ -0,0 +1,77 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioCDReader::AudioCDReader()
: AudioFormatReader (0, "CD Audio")
{
}
StringArray AudioCDReader::getAvailableCDNames()
{
StringArray names;
return names;
}
AudioCDReader* AudioCDReader::createReaderForCD (const int index)
{
return nullptr;
}
AudioCDReader::~AudioCDReader()
{
}
void AudioCDReader::refreshTrackLengths()
{
}
bool AudioCDReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples)
{
return false;
}
bool AudioCDReader::isCDStillPresent() const
{
return false;
}
bool AudioCDReader::isTrackAudio (int trackNum) const
{
return false;
}
void AudioCDReader::enableIndexScanning (bool b)
{
}
int AudioCDReader::getLastIndex() const
{
return 0;
}
Array<int> AudioCDReader::findIndexesInTrack (const int trackNumber)
{
return Array<int>();
}

+ 590
- 0
source/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp View File

@@ -0,0 +1,590 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
//==============================================================================
static void* juce_libjackHandle = nullptr;
static void* juce_loadJackFunction (const char* const name)
{
if (juce_libjackHandle == nullptr)
return nullptr;
return dlsym (juce_libjackHandle, name);
}
#define JUCE_DECL_JACK_FUNCTION(return_type, fn_name, argument_types, arguments) \
return_type fn_name argument_types \
{ \
typedef return_type (*fn_type) argument_types; \
static fn_type fn = (fn_type) juce_loadJackFunction (#fn_name); \
return (fn != nullptr) ? ((*fn) arguments) : (return_type) 0; \
}
#define JUCE_DECL_VOID_JACK_FUNCTION(fn_name, argument_types, arguments) \
void fn_name argument_types \
{ \
typedef void (*fn_type) argument_types; \
static fn_type fn = (fn_type) juce_loadJackFunction (#fn_name); \
if (fn != nullptr) (*fn) arguments; \
}
//==============================================================================
JUCE_DECL_JACK_FUNCTION (jack_client_t*, jack_client_open, (const char* client_name, jack_options_t options, jack_status_t* status, ...), (client_name, options, status));
JUCE_DECL_JACK_FUNCTION (int, jack_client_close, (jack_client_t *client), (client));
JUCE_DECL_JACK_FUNCTION (int, jack_activate, (jack_client_t* client), (client));
JUCE_DECL_JACK_FUNCTION (int, jack_deactivate, (jack_client_t* client), (client));
JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_get_buffer_size, (jack_client_t* client), (client));
JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_get_sample_rate, (jack_client_t* client), (client));
JUCE_DECL_VOID_JACK_FUNCTION (jack_on_shutdown, (jack_client_t* client, void (*function)(void* arg), void* arg), (client, function, arg));
JUCE_DECL_JACK_FUNCTION (void* , jack_port_get_buffer, (jack_port_t* port, jack_nframes_t nframes), (port, nframes));
JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_port_get_total_latency, (jack_client_t* client, jack_port_t* port), (client, port));
JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_register, (jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size), (client, port_name, port_type, flags, buffer_size));
JUCE_DECL_VOID_JACK_FUNCTION (jack_set_error_function, (void (*func)(const char*)), (func));
JUCE_DECL_JACK_FUNCTION (int, jack_set_process_callback, (jack_client_t* client, JackProcessCallback process_callback, void* arg), (client, process_callback, arg));
JUCE_DECL_JACK_FUNCTION (const char**, jack_get_ports, (jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags), (client, port_name_pattern, type_name_pattern, flags));
JUCE_DECL_JACK_FUNCTION (int, jack_connect, (jack_client_t* client, const char* source_port, const char* destination_port), (client, source_port, destination_port));
JUCE_DECL_JACK_FUNCTION (const char*, jack_port_name, (const jack_port_t* port), (port));
JUCE_DECL_JACK_FUNCTION (void*, jack_set_port_connect_callback, (jack_client_t* client, JackPortConnectCallback connect_callback, void* arg), (client, connect_callback, arg));
JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_by_id, (jack_client_t* client, jack_port_id_t port_id), (client, port_id));
JUCE_DECL_JACK_FUNCTION (int, jack_port_connected, (const jack_port_t* port), (port));
JUCE_DECL_JACK_FUNCTION (int, jack_port_connected_to, (const jack_port_t* port, const char* port_name), (port, port_name));
#if JUCE_DEBUG
#define JACK_LOGGING_ENABLED 1
#endif
#if JACK_LOGGING_ENABLED
namespace
{
void jack_Log (const String& s)
{
std::cerr << s << std::endl;
}
const char* getJackErrorMessage (const jack_status_t status)
{
if (status & JackServerFailed
|| status & JackServerError) return "Unable to connect to JACK server";
if (status & JackVersionError) return "Client's protocol version does not match";
if (status & JackInvalidOption) return "The operation contained an invalid or unsupported option";
if (status & JackNameNotUnique) return "The desired client name was not unique";
if (status & JackNoSuchClient) return "Requested client does not exist";
if (status & JackInitFailure) return "Unable to initialize client";
return nullptr;
}
}
#define JUCE_JACK_LOG_STATUS(x) { if (const char* m = getJackErrorMessage (x)) jack_Log (m); }
#define JUCE_JACK_LOG(x) jack_Log(x)
#else
#define JUCE_JACK_LOG_STATUS(x) {}
#define JUCE_JACK_LOG(x) {}
#endif
//==============================================================================
#ifndef JUCE_JACK_CLIENT_NAME
#define JUCE_JACK_CLIENT_NAME "JUCEJack"
#endif
struct JackPortIterator
{
JackPortIterator (jack_client_t* const client, const bool forInput)
: ports (nullptr), index (-1)
{
if (client != nullptr)
ports = juce::jack_get_ports (client, nullptr, nullptr,
forInput ? JackPortIsOutput : JackPortIsInput);
// (NB: This looks like it's the wrong way round, but it is correct!)
}
~JackPortIterator()
{
::free (ports);
}
bool next()
{
if (ports == nullptr || ports [index + 1] == nullptr)
return false;
name = CharPointer_UTF8 (ports[++index]);
clientName = name.upToFirstOccurrenceOf (":", false, false);
return true;
}
const char** ports;
int index;
String name;
String clientName;
};
class JackAudioIODeviceType;
static Array<JackAudioIODeviceType*> activeDeviceTypes;
//==============================================================================
class JackAudioIODevice : public AudioIODevice
{
public:
JackAudioIODevice (const String& deviceName,
const String& inId,
const String& outId)
: AudioIODevice (deviceName, "JACK"),
inputId (inId),
outputId (outId),
deviceIsOpen (false),
callback (nullptr),
totalNumberOfInputChannels (0),
totalNumberOfOutputChannels (0)
{
jassert (deviceName.isNotEmpty());
jack_status_t status;
client = juce::jack_client_open (JUCE_JACK_CLIENT_NAME, JackNoStartServer, &status);
if (client == nullptr)
{
JUCE_JACK_LOG_STATUS (status);
}
else
{
juce::jack_set_error_function (errorCallback);
// open input ports
const StringArray inputChannels (getInputChannelNames());
for (int i = 0; i < inputChannels.size(); ++i)
{
String inputName;
inputName << "in_" << ++totalNumberOfInputChannels;
inputPorts.add (juce::jack_port_register (client, inputName.toUTF8(),
JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0));
}
// open output ports
const StringArray outputChannels (getOutputChannelNames());
for (int i = 0; i < outputChannels.size (); ++i)
{
String outputName;
outputName << "out_" << ++totalNumberOfOutputChannels;
outputPorts.add (juce::jack_port_register (client, outputName.toUTF8(),
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0));
}
inChans.calloc (totalNumberOfInputChannels + 2);
outChans.calloc (totalNumberOfOutputChannels + 2);
}
}
~JackAudioIODevice()
{
close();
if (client != nullptr)
{
juce::jack_client_close (client);
client = nullptr;
}
}
StringArray getChannelNames (bool forInput) const
{
StringArray names;
for (JackPortIterator i (client, forInput); i.next();)
if (i.clientName == getName())
names.add (i.name.fromFirstOccurrenceOf (":", false, false));
return names;
}
StringArray getOutputChannelNames() { return getChannelNames (false); }
StringArray getInputChannelNames() { return getChannelNames (true); }
int getNumSampleRates() { return client != nullptr ? 1 : 0; }
double getSampleRate (int /*index*/) { return client != nullptr ? juce::jack_get_sample_rate (client) : 0; }
int getNumBufferSizesAvailable() { return client != nullptr ? 1 : 0; }
int getBufferSizeSamples (int /*index*/) { return getDefaultBufferSize(); }
int getDefaultBufferSize() { return client != nullptr ? juce::jack_get_buffer_size (client) : 0; }
String open (const BigInteger& inputChannels, const BigInteger& outputChannels,
double /* sampleRate */, int /* bufferSizeSamples */)
{
if (client == nullptr)
{
lastError = "No JACK client running";
return lastError;
}
lastError = String::empty;
close();
juce::jack_set_process_callback (client, processCallback, this);
juce::jack_set_port_connect_callback (client, portConnectCallback, this);
juce::jack_on_shutdown (client, shutdownCallback, this);
juce::jack_activate (client);
deviceIsOpen = true;
if (! inputChannels.isZero())
{
for (JackPortIterator i (client, true); i.next();)
{
if (inputChannels [i.index] && i.clientName == getName())
{
int error = juce::jack_connect (client, i.ports[i.index], juce::jack_port_name ((jack_port_t*) inputPorts[i.index]));
if (error != 0)
JUCE_JACK_LOG ("Cannot connect input port " + String (i.index) + " (" + i.name + "), error " + String (error));
}
}
}
if (! outputChannels.isZero())
{
for (JackPortIterator i (client, false); i.next();)
{
if (outputChannels [i.index] && i.clientName == getName())
{
int error = juce::jack_connect (client, juce::jack_port_name ((jack_port_t*) outputPorts[i.index]), i.ports[i.index]);
if (error != 0)
JUCE_JACK_LOG ("Cannot connect output port " + String (i.index) + " (" + i.name + "), error " + String (error));
}
}
}
return lastError;
}
void close()
{
stop();
if (client != nullptr)
{
juce::jack_deactivate (client);
juce::jack_set_process_callback (client, processCallback, nullptr);
juce::jack_set_port_connect_callback (client, portConnectCallback, nullptr);
juce::jack_on_shutdown (client, shutdownCallback, nullptr);
}
deviceIsOpen = false;
}
void start (AudioIODeviceCallback* newCallback)
{
if (deviceIsOpen && newCallback != callback)
{
if (newCallback != nullptr)
newCallback->audioDeviceAboutToStart (this);
AudioIODeviceCallback* const oldCallback = callback;
{
const ScopedLock sl (callbackLock);
callback = newCallback;
}
if (oldCallback != nullptr)
oldCallback->audioDeviceStopped();
}
}
void stop()
{
start (nullptr);
}
bool isOpen() { return deviceIsOpen; }
bool isPlaying() { return callback != nullptr; }
int getCurrentBufferSizeSamples() { return getBufferSizeSamples (0); }
double getCurrentSampleRate() { return getSampleRate (0); }
int getCurrentBitDepth() { return 32; }
String getLastError() { return lastError; }
BigInteger getActiveOutputChannels() const { return activeOutputChannels; }
BigInteger getActiveInputChannels() const { return activeInputChannels; }
int getOutputLatencyInSamples()
{
int latency = 0;
for (int i = 0; i < outputPorts.size(); i++)
latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) outputPorts [i]));
return latency;
}
int getInputLatencyInSamples()
{
int latency = 0;
for (int i = 0; i < inputPorts.size(); i++)
latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) inputPorts [i]));
return latency;
}
String inputId, outputId;
private:
void process (const int numSamples)
{
int numActiveInChans = 0, numActiveOutChans = 0;
for (int i = 0; i < totalNumberOfInputChannels; ++i)
{
if (activeInputChannels[i])
if (jack_default_audio_sample_t* in
= (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) inputPorts.getUnchecked(i), numSamples))
inChans [numActiveInChans++] = (float*) in;
}
for (int i = 0; i < totalNumberOfOutputChannels; ++i)
{
if (activeOutputChannels[i])
if (jack_default_audio_sample_t* out
= (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) outputPorts.getUnchecked(i), numSamples))
outChans [numActiveOutChans++] = (float*) out;
}
const ScopedLock sl (callbackLock);
if (callback != nullptr)
{
if ((numActiveInChans + numActiveOutChans) > 0)
callback->audioDeviceIOCallback (const_cast <const float**> (inChans.getData()), numActiveInChans,
outChans, numActiveOutChans, numSamples);
}
else
{
for (int i = 0; i < numActiveOutChans; ++i)
zeromem (outChans[i], sizeof (float) * numSamples);
}
}
static int processCallback (jack_nframes_t nframes, void* callbackArgument)
{
if (callbackArgument != nullptr)
((JackAudioIODevice*) callbackArgument)->process (nframes);
return 0;
}
void updateActivePorts()
{
BigInteger newOutputChannels, newInputChannels;
for (int i = 0; i < outputPorts.size(); ++i)
if (juce::jack_port_connected ((jack_port_t*) outputPorts.getUnchecked(i)))
newOutputChannels.setBit (i);
for (int i = 0; i < inputPorts.size(); ++i)
if (juce::jack_port_connected ((jack_port_t*) inputPorts.getUnchecked(i)))
newInputChannels.setBit (i);
if (newOutputChannels != activeOutputChannels
|| newInputChannels != activeInputChannels)
{
AudioIODeviceCallback* const oldCallback = callback;
stop();
activeOutputChannels = newOutputChannels;
activeInputChannels = newInputChannels;
if (oldCallback != nullptr)
start (oldCallback);
sendDeviceChangedCallback();
}
}
static void portConnectCallback (jack_port_id_t, jack_port_id_t, int, void* arg)
{
if (JackAudioIODevice* device = static_cast <JackAudioIODevice*> (arg))
device->updateActivePorts();
}
static void threadInitCallback (void* /* callbackArgument */)
{
JUCE_JACK_LOG ("JackAudioIODevice::initialise");
}
static void shutdownCallback (void* callbackArgument)
{
JUCE_JACK_LOG ("JackAudioIODevice::shutdown");
if (JackAudioIODevice* device = (JackAudioIODevice*) callbackArgument)
{
device->client = nullptr;
device->close();
}
}
static void errorCallback (const char* msg)
{
JUCE_JACK_LOG ("JackAudioIODevice::errorCallback " + String (msg));
}
static void sendDeviceChangedCallback();
bool deviceIsOpen;
jack_client_t* client;
String lastError;
AudioIODeviceCallback* callback;
CriticalSection callbackLock;
HeapBlock <float*> inChans, outChans;
int totalNumberOfInputChannels;
int totalNumberOfOutputChannels;
Array<void*> inputPorts, outputPorts;
BigInteger activeInputChannels, activeOutputChannels;
};
//==============================================================================
class JackAudioIODeviceType : public AudioIODeviceType
{
public:
JackAudioIODeviceType()
: AudioIODeviceType ("JACK"),
hasScanned (false)
{
activeDeviceTypes.add (this);
}
~JackAudioIODeviceType()
{
activeDeviceTypes.removeFirstMatchingValue (this);
}
void scanForDevices()
{
hasScanned = true;
inputNames.clear();
inputIds.clear();
outputNames.clear();
outputIds.clear();
if (juce_libjackHandle == nullptr)
{
juce_libjackHandle = dlopen ("libjack.so", RTLD_LAZY);
if (juce_libjackHandle == nullptr)
return;
}
jack_status_t status;
// open a dummy client
if (jack_client_t* const client = juce::jack_client_open ("JuceJackDummy", JackNoStartServer, &status))
{
// scan for output devices
for (JackPortIterator i (client, false); i.next();)
{
if (i.clientName != (JUCE_JACK_CLIENT_NAME) && ! inputNames.contains (i.clientName))
{
inputNames.add (i.clientName);
inputIds.add (i.ports [i.index]);
}
}
// scan for input devices
for (JackPortIterator i (client, true); i.next();)
{
if (i.clientName != (JUCE_JACK_CLIENT_NAME) && ! outputNames.contains (i.clientName))
{
outputNames.add (i.clientName);
outputIds.add (i.ports [i.index]);
}
}
juce::jack_client_close (client);
}
else
{
JUCE_JACK_LOG_STATUS (status);
}
}
StringArray getDeviceNames (bool wantInputNames) const
{
jassert (hasScanned); // need to call scanForDevices() before doing this
return wantInputNames ? inputNames : outputNames;
}
int getDefaultDeviceIndex (bool /* forInput */) const
{
jassert (hasScanned); // need to call scanForDevices() before doing this
return 0;
}
bool hasSeparateInputsAndOutputs() const { return true; }
int getIndexOfDevice (AudioIODevice* device, bool asInput) const
{
jassert (hasScanned); // need to call scanForDevices() before doing this
if (JackAudioIODevice* d = dynamic_cast <JackAudioIODevice*> (device))
return asInput ? inputIds.indexOf (d->inputId)
: outputIds.indexOf (d->outputId);
return -1;
}
AudioIODevice* createDevice (const String& outputDeviceName,
const String& inputDeviceName)
{
jassert (hasScanned); // need to call scanForDevices() before doing this
const int inputIndex = inputNames.indexOf (inputDeviceName);
const int outputIndex = outputNames.indexOf (outputDeviceName);
if (inputIndex >= 0 || outputIndex >= 0)
return new JackAudioIODevice (outputIndex >= 0 ? outputDeviceName
: inputDeviceName,
inputIds [inputIndex],
outputIds [outputIndex]);
return nullptr;
}
void portConnectionChange() { callDeviceChangeListeners(); }
private:
StringArray inputNames, outputNames, inputIds, outputIds;
bool hasScanned;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JackAudioIODeviceType)
};
void JackAudioIODevice::sendDeviceChangedCallback()
{
for (int i = activeDeviceTypes.size(); --i >= 0;)
if (JackAudioIODeviceType* d = activeDeviceTypes[i])
d->portConnectionChange();
}
//==============================================================================
AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK()
{
return new JackAudioIODeviceType();
}

+ 610
- 0
source/modules/juce_audio_devices/native/juce_linux_Midi.cpp View File

@@ -0,0 +1,610 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_ALSA
// You can define these strings in your app if you want to override the default names:
#ifndef JUCE_ALSA_MIDI_INPUT_NAME
#define JUCE_ALSA_MIDI_INPUT_NAME "Juce Midi Input"
#endif
#ifndef JUCE_ALSA_MIDI_OUTPUT_NAME
#define JUCE_ALSA_MIDI_OUTPUT_NAME "Juce Midi Output"
#endif
//==============================================================================
namespace
{
class AlsaPortAndCallback;
//==============================================================================
class AlsaClient : public ReferenceCountedObject
{
public:
typedef ReferenceCountedObjectPtr<AlsaClient> Ptr;
AlsaClient (bool forInput)
: input (forInput), handle (nullptr)
{
snd_seq_open (&handle, "default", forInput ? SND_SEQ_OPEN_INPUT
: SND_SEQ_OPEN_OUTPUT, 0);
}
~AlsaClient()
{
if (handle != nullptr)
{
snd_seq_close (handle);
handle = nullptr;
}
jassert (activeCallbacks.size() == 0);
if (inputThread)
{
inputThread->stopThread (3000);
inputThread = nullptr;
}
}
bool isInput() const noexcept { return input; }
void setName (const String& name)
{
snd_seq_set_client_name (handle, name.toUTF8());
}
void registerCallback (AlsaPortAndCallback* cb)
{
if (cb != nullptr)
{
{
const ScopedLock sl (callbackLock);
activeCallbacks.add (cb);
if (inputThread == nullptr)
inputThread = new MidiInputThread (*this);
}
inputThread->startThread();
}
}
void unregisterCallback (AlsaPortAndCallback* cb)
{
const ScopedLock sl (callbackLock);
jassert (activeCallbacks.contains (cb));
activeCallbacks.removeAllInstancesOf (cb);
if (activeCallbacks.size() == 0 && inputThread->isThreadRunning())
inputThread->signalThreadShouldExit();
}
void handleIncomingMidiMessage (const MidiMessage& message, int port);
snd_seq_t* get() const noexcept { return handle; }
private:
bool input;
snd_seq_t* handle;
Array<AlsaPortAndCallback*> activeCallbacks;
CriticalSection callbackLock;
//==============================================================================
class MidiInputThread : public Thread
{
public:
MidiInputThread (AlsaClient& c)
: Thread ("Juce MIDI Input"), client (c)
{
jassert (client.input && client.get() != nullptr);
}
void run() override
{
const int maxEventSize = 16 * 1024;
snd_midi_event_t* midiParser;
snd_seq_t* seqHandle = client.get();
if (snd_midi_event_new (maxEventSize, &midiParser) >= 0)
{
const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN);
HeapBlock<pollfd> pfd (numPfds);
snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN);
HeapBlock <uint8> buffer (maxEventSize);
while (! threadShouldExit())
{
if (poll (pfd, numPfds, 100) > 0) // there was a "500" here which is a bit long when we exit the program and have to wait for a timeout on this poll call
{
if (threadShouldExit())
break;
snd_seq_nonblock (seqHandle, 1);
do
{
snd_seq_event_t* inputEvent = nullptr;
if (snd_seq_event_input (seqHandle, &inputEvent) >= 0)
{
// xxx what about SYSEXes that are too big for the buffer?
const int numBytes = snd_midi_event_decode (midiParser, buffer,
maxEventSize, inputEvent);
snd_midi_event_reset_decode (midiParser);
if (numBytes > 0)
{
const MidiMessage message ((const uint8*) buffer, numBytes,
Time::getMillisecondCounter() * 0.001);
client.handleIncomingMidiMessage (message, inputEvent->dest.port);
}
snd_seq_free_event (inputEvent);
}
}
while (snd_seq_event_input_pending (seqHandle, 0) > 0);
}
}
snd_midi_event_free (midiParser);
}
};
private:
AlsaClient& client;
};
ScopedPointer<MidiInputThread> inputThread;
};
static AlsaClient::Ptr globalAlsaSequencerIn()
{
static AlsaClient::Ptr global (new AlsaClient (true));
return global;
}
static AlsaClient::Ptr globalAlsaSequencerOut()
{
static AlsaClient::Ptr global (new AlsaClient (false));
return global;
}
static AlsaClient::Ptr globalAlsaSequencer (bool input)
{
return input ? globalAlsaSequencerIn()
: globalAlsaSequencerOut();
}
//==============================================================================
// represents an input or output port of the supplied AlsaClient
class AlsaPort
{
public:
AlsaPort() noexcept : portId (-1) {}
AlsaPort (const AlsaClient::Ptr& c, int port) noexcept : client (c), portId (port) {}
void createPort (const AlsaClient::Ptr& c, const String& name, bool forInput)
{
client = c;
if (snd_seq_t* handle = client->get())
portId = snd_seq_create_simple_port (handle, name.toUTF8(),
forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
: (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
SND_SEQ_PORT_TYPE_MIDI_GENERIC);
}
void deletePort()
{
if (isValid())
{
snd_seq_delete_simple_port (client->get(), portId);
portId = -1;
}
}
void connectWith (int sourceClient, int sourcePort)
{
if (client->isInput())
snd_seq_connect_from (client->get(), portId, sourceClient, sourcePort);
else
snd_seq_connect_to (client->get(), portId, sourceClient, sourcePort);
}
bool isValid() const noexcept
{
return client != nullptr && client->get() != nullptr && portId >= 0;
}
AlsaClient::Ptr client;
int portId;
};
//==============================================================================
class AlsaPortAndCallback
{
public:
AlsaPortAndCallback (AlsaPort p, MidiInput* in, MidiInputCallback* cb)
: port (p), midiInput (in), callback (cb), callbackEnabled (false)
{
}
~AlsaPortAndCallback()
{
enableCallback (false);
port.deletePort();
}
void enableCallback (bool enable)
{
if (callbackEnabled != enable)
{
callbackEnabled = enable;
if (enable)
port.client->registerCallback (this);
else
port.client->unregisterCallback (this);
}
}
void handleIncomingMidiMessage (const MidiMessage& message) const
{
callback->handleIncomingMidiMessage (midiInput, message);
}
private:
AlsaPort port;
MidiInput* midiInput;
MidiInputCallback* callback;
bool callbackEnabled;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlsaPortAndCallback)
};
void AlsaClient::handleIncomingMidiMessage (const MidiMessage& message, int port)
{
const ScopedLock sl (callbackLock);
if (AlsaPortAndCallback* const cb = activeCallbacks[port])
cb->handleIncomingMidiMessage (message);
}
//==============================================================================
static AlsaPort iterateMidiClient (const AlsaClient::Ptr& seq,
snd_seq_client_info_t* clientInfo,
const bool forInput,
StringArray& deviceNamesFound,
const int deviceIndexToOpen)
{
AlsaPort port;
snd_seq_t* seqHandle = seq->get();
snd_seq_port_info_t* portInfo = nullptr;
if (snd_seq_port_info_malloc (&portInfo) == 0)
{
int numPorts = snd_seq_client_info_get_num_ports (clientInfo);
const int client = snd_seq_client_info_get_client (clientInfo);
snd_seq_port_info_set_client (portInfo, client);
snd_seq_port_info_set_port (portInfo, -1);
while (--numPorts >= 0)
{
if (snd_seq_query_next_port (seqHandle, portInfo) == 0
&& (snd_seq_port_info_get_capability (portInfo) & (forInput ? SND_SEQ_PORT_CAP_READ
: SND_SEQ_PORT_CAP_WRITE)) != 0)
{
deviceNamesFound.add (snd_seq_client_info_get_name (clientInfo));
if (deviceNamesFound.size() == deviceIndexToOpen + 1)
{
const int sourcePort = snd_seq_port_info_get_port (portInfo);
const int sourceClient = snd_seq_client_info_get_client (clientInfo);
if (sourcePort != -1)
{
const String name (forInput ? JUCE_ALSA_MIDI_INPUT_NAME
: JUCE_ALSA_MIDI_OUTPUT_NAME);
seq->setName (name);
port.createPort (seq, name, forInput);
port.connectWith (sourceClient, sourcePort);
}
}
}
}
snd_seq_port_info_free (portInfo);
}
return port;
}
static AlsaPort iterateMidiDevices (const bool forInput,
StringArray& deviceNamesFound,
const int deviceIndexToOpen)
{
AlsaPort port;
const AlsaClient::Ptr client (globalAlsaSequencer (forInput));
if (snd_seq_t* const seqHandle = client->get())
{
snd_seq_system_info_t* systemInfo = nullptr;
snd_seq_client_info_t* clientInfo = nullptr;
if (snd_seq_system_info_malloc (&systemInfo) == 0)
{
if (snd_seq_system_info (seqHandle, systemInfo) == 0
&& snd_seq_client_info_malloc (&clientInfo) == 0)
{
int numClients = snd_seq_system_info_get_cur_clients (systemInfo);
while (--numClients >= 0 && ! port.isValid())
if (snd_seq_query_next_client (seqHandle, clientInfo) == 0)
port = iterateMidiClient (client, clientInfo, forInput,
deviceNamesFound, deviceIndexToOpen);
snd_seq_client_info_free (clientInfo);
}
snd_seq_system_info_free (systemInfo);
}
}
deviceNamesFound.appendNumbersToDuplicates (true, true);
return port;
}
AlsaPort createMidiDevice (const bool forInput, const String& deviceNameToOpen)
{
AlsaPort port;
AlsaClient::Ptr client (new AlsaClient (forInput));
if (client->get())
{
client->setName (deviceNameToOpen + (forInput ? " Input" : " Output"));
port.createPort (client, forInput ? "in" : "out", forInput);
}
return port;
}
//==============================================================================
class MidiOutputDevice
{
public:
MidiOutputDevice (MidiOutput* const output, const AlsaPort& p)
: midiOutput (output), port (p),
maxEventSize (16 * 1024)
{
jassert (port.isValid() && midiOutput != nullptr);
snd_midi_event_new (maxEventSize, &midiParser);
}
~MidiOutputDevice()
{
snd_midi_event_free (midiParser);
port.deletePort();
}
void sendMessageNow (const MidiMessage& message)
{
if (message.getRawDataSize() > maxEventSize)
{
maxEventSize = message.getRawDataSize();
snd_midi_event_free (midiParser);
snd_midi_event_new (maxEventSize, &midiParser);
}
snd_seq_event_t event;
snd_seq_ev_clear (&event);
long numBytes = (long) message.getRawDataSize();
const uint8* data = message.getRawData();
snd_seq_t* seqHandle = port.client->get();
while (numBytes > 0)
{
const long numSent = snd_midi_event_encode (midiParser, data, numBytes, &event);
if (numSent <= 0)
break;
numBytes -= numSent;
data += numSent;
snd_seq_ev_set_source (&event, 0);
snd_seq_ev_set_subs (&event);
snd_seq_ev_set_direct (&event);
snd_seq_event_output (seqHandle, &event);
}
snd_seq_drain_output (seqHandle);
snd_midi_event_reset_encode (midiParser);
}
private:
MidiOutput* const midiOutput;
AlsaPort port;
snd_midi_event_t* midiParser;
int maxEventSize;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutputDevice);
};
} // namespace
StringArray MidiOutput::getDevices()
{
StringArray devices;
iterateMidiDevices (false, devices, -1);
return devices;
}
int MidiOutput::getDefaultDeviceIndex()
{
return 0;
}
MidiOutput* MidiOutput::openDevice (int deviceIndex)
{
MidiOutput* newDevice = nullptr;
StringArray devices;
AlsaPort port (iterateMidiDevices (false, devices, deviceIndex));
if (port.isValid())
{
newDevice = new MidiOutput();
newDevice->internal = new MidiOutputDevice (newDevice, port);
}
return newDevice;
}
MidiOutput* MidiOutput::createNewDevice (const String& deviceName)
{
MidiOutput* newDevice = nullptr;
AlsaPort port (createMidiDevice (false, deviceName));
if (port.isValid())
{
newDevice = new MidiOutput();
newDevice->internal = new MidiOutputDevice (newDevice, port);
}
return newDevice;
}
MidiOutput::~MidiOutput()
{
delete static_cast <MidiOutputDevice*> (internal);
}
void MidiOutput::sendMessageNow (const MidiMessage& message)
{
static_cast <MidiOutputDevice*> (internal)->sendMessageNow (message);
}
//==============================================================================
MidiInput::MidiInput (const String& nm)
: name (nm), internal (nullptr)
{
}
MidiInput::~MidiInput()
{
stop();
delete static_cast <AlsaPortAndCallback*> (internal);
}
void MidiInput::start()
{
static_cast<AlsaPortAndCallback*> (internal)->enableCallback (true);
}
void MidiInput::stop()
{
static_cast<AlsaPortAndCallback*> (internal)->enableCallback (false);
}
int MidiInput::getDefaultDeviceIndex()
{
return 0;
}
StringArray MidiInput::getDevices()
{
StringArray devices;
iterateMidiDevices (true, devices, -1);
return devices;
}
MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback)
{
MidiInput* newDevice = nullptr;
StringArray devices;
AlsaPort port (iterateMidiDevices (true, devices, deviceIndex));
if (port.isValid())
{
newDevice = new MidiInput (devices [deviceIndex]);
newDevice->internal = new AlsaPortAndCallback (port, newDevice, callback);
}
return newDevice;
}
MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback)
{
MidiInput* newDevice = nullptr;
AlsaPort port (createMidiDevice (true, deviceName));
if (port.isValid())
{
newDevice = new MidiInput (deviceName);
newDevice->internal = new AlsaPortAndCallback (port, newDevice, callback);
}
return newDevice;
}
//==============================================================================
#else
// (These are just stub functions if ALSA is unavailable...)
StringArray MidiOutput::getDevices() { return StringArray(); }
int MidiOutput::getDefaultDeviceIndex() { return 0; }
MidiOutput* MidiOutput::openDevice (int) { return nullptr; }
MidiOutput* MidiOutput::createNewDevice (const String&) { return nullptr; }
MidiOutput::~MidiOutput() {}
void MidiOutput::sendMessageNow (const MidiMessage&) {}
MidiInput::MidiInput (const String& nm) : name (nm), internal (nullptr) {}
MidiInput::~MidiInput() {}
void MidiInput::start() {}
void MidiInput::stop() {}
int MidiInput::getDefaultDeviceIndex() { return 0; }
StringArray MidiInput::getDevices() { return StringArray(); }
MidiInput* MidiInput::openDevice (int, MidiInputCallback*) { return nullptr; }
MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { return nullptr; }
#endif

+ 491
- 0
source/modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm View File

@@ -0,0 +1,491 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
const int kilobytesPerSecond1x = 176;
struct AudioTrackProducerClass : public ObjCClass <NSObject>
{
AudioTrackProducerClass() : ObjCClass <NSObject> ("JUCEAudioTrackProducer_")
{
addIvar<AudioSourceHolder*> ("source");
addMethod (@selector (initWithAudioSourceHolder:), initWithAudioSourceHolder, "@@:^v");
addMethod (@selector (cleanupTrackAfterBurn:), cleanupTrackAfterBurn, "v@:@");
addMethod (@selector (cleanupTrackAfterVerification:), cleanupTrackAfterVerification, "c@:@");
addMethod (@selector (estimateLengthOfTrack:), estimateLengthOfTrack, "Q@:@");
addMethod (@selector (prepareTrack:forBurn:toMedia:), prepareTrack, "c@:@@@");
addMethod (@selector (prepareTrackForVerification:), prepareTrackForVerification, "c@:@");
addMethod (@selector (produceDataForTrack:intoBuffer:length:atAddress:blockSize:ioFlags:),
produceDataForTrack, "I@:@^cIQI^I");
addMethod (@selector (producePreGapForTrack:intoBuffer:length:atAddress:blockSize:ioFlags:),
produceDataForTrack, "I@:@^cIQI^I");
addMethod (@selector (verifyDataForTrack:intoBuffer:length:atAddress:blockSize:ioFlags:),
produceDataForTrack, "I@:@^cIQI^I");
registerClass();
}
struct AudioSourceHolder
{
AudioSourceHolder (AudioSource* source_, int numFrames)
: source (source_), readPosition (0), lengthInFrames (numFrames)
{
}
~AudioSourceHolder()
{
if (source != nullptr)
source->releaseResources();
}
ScopedPointer<AudioSource> source;
int readPosition, lengthInFrames;
};
private:
static id initWithAudioSourceHolder (id self, SEL, AudioSourceHolder* source)
{
self = sendSuperclassMessage (self, @selector (init));
object_setInstanceVariable (self, "source", source);
return self;
}
static AudioSourceHolder* getSource (id self)
{
return getIvar<AudioSourceHolder*> (self, "source");
}
static void dealloc (id self, SEL)
{
delete getSource (self);
sendSuperclassMessage (self, @selector (dealloc));
}
static void cleanupTrackAfterBurn (id self, SEL, DRTrack*) {}
static BOOL cleanupTrackAfterVerification (id self, SEL, DRTrack*) { return true; }
static uint64_t estimateLengthOfTrack (id self, SEL, DRTrack*)
{
return getSource (self)->lengthInFrames;
}
static BOOL prepareTrack (id self, SEL, DRTrack*, DRBurn*, NSDictionary*)
{
if (AudioSourceHolder* const source = getSource (self))
{
source->source->prepareToPlay (44100 / 75, 44100);
source->readPosition = 0;
}
return true;
}
static BOOL prepareTrackForVerification (id self, SEL, DRTrack*)
{
if (AudioSourceHolder* const source = getSource (self))
source->source->prepareToPlay (44100 / 75, 44100);
return true;
}
static uint32_t produceDataForTrack (id self, SEL, DRTrack*, char* buffer,
uint32_t bufferLength, uint64_t /*address*/,
uint32_t /*blockSize*/, uint32_t* /*flags*/)
{
if (AudioSourceHolder* const source = getSource (self))
{
const int numSamples = jmin ((int) bufferLength / 4,
(source->lengthInFrames * (44100 / 75)) - source->readPosition);
if (numSamples > 0)
{
AudioSampleBuffer tempBuffer (2, numSamples);
AudioSourceChannelInfo info (tempBuffer);
source->source->getNextAudioBlock (info);
typedef AudioData::Pointer <AudioData::Int16,
AudioData::LittleEndian,
AudioData::Interleaved,
AudioData::NonConst> CDSampleFormat;
typedef AudioData::Pointer <AudioData::Float32,
AudioData::NativeEndian,
AudioData::NonInterleaved,
AudioData::Const> SourceSampleFormat;
CDSampleFormat left (buffer, 2);
left.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (0)), numSamples);
CDSampleFormat right (buffer + 2, 2);
right.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (1)), numSamples);
source->readPosition += numSamples;
}
return numSamples * 4;
}
return 0;
}
static uint32_t producePreGapForTrack (id self, SEL, DRTrack*, char* buffer,
uint32_t bufferLength, uint64_t /*address*/,
uint32_t /*blockSize*/, uint32_t* /*flags*/)
{
zeromem (buffer, bufferLength);
return bufferLength;
}
static BOOL verifyDataForTrack (id self, SEL, DRTrack*, const char*,
uint32_t /*bufferLength*/, uint64_t /*address*/,
uint32_t /*blockSize*/, uint32_t* /*flags*/)
{
return true;
}
};
struct OpenDiskDevice
{
OpenDiskDevice (DRDevice* device_)
: device (device_),
tracks ([[NSMutableArray alloc] init]),
underrunProtection (true)
{
}
~OpenDiskDevice()
{
[tracks release];
}
void addSourceTrack (AudioSource* source, int numSamples)
{
if (source != nullptr)
{
const int numFrames = (numSamples + 587) / 588;
static AudioTrackProducerClass cls;
NSObject* producer = [cls.createInstance() performSelector: @selector (initWithAudioSourceHolder:)
withObject: (id) new AudioTrackProducerClass::AudioSourceHolder (source, numFrames)];
DRTrack* track = [[DRTrack alloc] initWithProducer: producer];
{
NSMutableDictionary* p = [[track properties] mutableCopy];
[p setObject: [DRMSF msfWithFrames: numFrames] forKey: DRTrackLengthKey];
[p setObject: [NSNumber numberWithUnsignedShort: 2352] forKey: DRBlockSizeKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRDataFormKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRBlockTypeKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRTrackModeKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRSessionFormatKey];
[track setProperties: p];
[p release];
}
[tracks addObject: track];
[track release];
[producer release];
}
}
String burn (AudioCDBurner::BurnProgressListener* listener,
bool shouldEject, bool peformFakeBurnForTesting, int burnSpeed)
{
DRBurn* burn = [DRBurn burnForDevice: device];
if (! [device acquireExclusiveAccess])
return "Couldn't open or write to the CD device";
[device acquireMediaReservation];
NSMutableDictionary* d = [[burn properties] mutableCopy];
[d autorelease];
[d setObject: [NSNumber numberWithBool: peformFakeBurnForTesting] forKey: DRBurnTestingKey];
[d setObject: [NSNumber numberWithBool: false] forKey: DRBurnVerifyDiscKey];
[d setObject: (shouldEject ? DRBurnCompletionActionEject : DRBurnCompletionActionMount) forKey: DRBurnCompletionActionKey];
if (burnSpeed > 0)
[d setObject: [NSNumber numberWithFloat: burnSpeed * kilobytesPerSecond1x] forKey: DRBurnRequestedSpeedKey];
if (! underrunProtection)
[d setObject: [NSNumber numberWithBool: false] forKey: DRBurnUnderrunProtectionKey];
[burn setProperties: d];
[burn writeLayout: tracks];
for (;;)
{
Thread::sleep (300);
float progress = [[[burn status] objectForKey: DRStatusPercentCompleteKey] floatValue];
if (listener != nullptr && listener->audioCDBurnProgress (progress))
{
[burn abort];
return "User cancelled the write operation";
}
if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateFailed])
return "Write operation failed";
if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateDone])
break;
NSString* err = (NSString*) [[[burn status] objectForKey: DRErrorStatusKey]
objectForKey: DRErrorStatusErrorStringKey];
if ([err length] > 0)
return CharPointer_UTF8 ([err UTF8String]);
}
[device releaseMediaReservation];
[device releaseExclusiveAccess];
return String::empty;
}
DRDevice* device;
NSMutableArray* tracks;
bool underrunProtection;
};
//==============================================================================
class AudioCDBurner::Pimpl : public Timer
{
public:
Pimpl (AudioCDBurner& owner_, const int deviceIndex)
: device (0), owner (owner_)
{
DRDevice* dev = [[DRDevice devices] objectAtIndex: deviceIndex];
if (dev != nil)
{
device = new OpenDiskDevice (dev);
lastState = getDiskState();
startTimer (1000);
}
}
~Pimpl()
{
stopTimer();
}
void timerCallback() override
{
const DiskState state = getDiskState();
if (state != lastState)
{
lastState = state;
owner.sendChangeMessage();
}
}
DiskState getDiskState() const
{
if ([device->device isValid])
{
NSDictionary* status = [device->device status];
NSString* state = [status objectForKey: DRDeviceMediaStateKey];
if ([state isEqualTo: DRDeviceMediaStateNone])
{
if ([[status objectForKey: DRDeviceIsTrayOpenKey] boolValue])
return trayOpen;
return noDisc;
}
if ([state isEqualTo: DRDeviceMediaStateMediaPresent])
{
if ([[[status objectForKey: DRDeviceMediaInfoKey] objectForKey: DRDeviceMediaBlocksFreeKey] intValue] > 0)
return writableDiskPresent;
else
return readOnlyDiskPresent;
}
}
return unknown;
}
bool openTray() { return [device->device isValid] && [device->device ejectMedia]; }
Array<int> getAvailableWriteSpeeds() const
{
Array<int> results;
if ([device->device isValid])
{
NSArray* speeds = [[[device->device status] objectForKey: DRDeviceMediaInfoKey] objectForKey: DRDeviceBurnSpeedsKey];
for (unsigned int i = 0; i < [speeds count]; ++i)
{
const int kbPerSec = [[speeds objectAtIndex: i] intValue];
results.add (kbPerSec / kilobytesPerSecond1x);
}
}
return results;
}
bool setBufferUnderrunProtection (const bool shouldBeEnabled)
{
if ([device->device isValid])
{
device->underrunProtection = shouldBeEnabled;
return shouldBeEnabled && [[[device->device status] objectForKey: DRDeviceCanUnderrunProtectCDKey] boolValue];
}
return false;
}
int getNumAvailableAudioBlocks() const
{
return [[[[device->device status] objectForKey: DRDeviceMediaInfoKey]
objectForKey: DRDeviceMediaBlocksFreeKey] intValue];
}
ScopedPointer<OpenDiskDevice> device;
private:
DiskState lastState;
AudioCDBurner& owner;
};
//==============================================================================
AudioCDBurner::AudioCDBurner (const int deviceIndex)
{
pimpl = new Pimpl (*this, deviceIndex);
}
AudioCDBurner::~AudioCDBurner()
{
}
AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
{
ScopedPointer <AudioCDBurner> b (new AudioCDBurner (deviceIndex));
if (b->pimpl->device == nil)
b = 0;
return b.release();
}
namespace
{
NSArray* findDiskBurnerDevices()
{
NSMutableArray* results = [NSMutableArray array];
NSArray* devs = [DRDevice devices];
for (int i = 0; i < [devs count]; ++i)
{
NSDictionary* dic = [[devs objectAtIndex: i] info];
NSString* name = [dic valueForKey: DRDeviceProductNameKey];
if (name != nil)
[results addObject: name];
}
return results;
}
}
StringArray AudioCDBurner::findAvailableDevices()
{
NSArray* names = findDiskBurnerDevices();
StringArray s;
for (unsigned int i = 0; i < [names count]; ++i)
s.add (CharPointer_UTF8 ([[names objectAtIndex: i] UTF8String]));
return s;
}
AudioCDBurner::DiskState AudioCDBurner::getDiskState() const
{
return pimpl->getDiskState();
}
bool AudioCDBurner::isDiskPresent() const
{
return getDiskState() == writableDiskPresent;
}
bool AudioCDBurner::openTray()
{
return pimpl->openTray();
}
AudioCDBurner::DiskState AudioCDBurner::waitUntilStateChange (int timeOutMilliseconds)
{
const int64 timeout = Time::currentTimeMillis() + timeOutMilliseconds;
DiskState oldState = getDiskState();
DiskState newState = oldState;
while (newState == oldState && Time::currentTimeMillis() < timeout)
{
newState = getDiskState();
Thread::sleep (100);
}
return newState;
}
Array<int> AudioCDBurner::getAvailableWriteSpeeds() const
{
return pimpl->getAvailableWriteSpeeds();
}
bool AudioCDBurner::setBufferUnderrunProtection (const bool shouldBeEnabled)
{
return pimpl->setBufferUnderrunProtection (shouldBeEnabled);
}
int AudioCDBurner::getNumAvailableAudioBlocks() const
{
return pimpl->getNumAvailableAudioBlocks();
}
bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamps)
{
if ([pimpl->device->device isValid])
{
pimpl->device->addSourceTrack (source, numSamps);
return true;
}
return false;
}
String AudioCDBurner::burn (AudioCDBurner::BurnProgressListener* listener,
bool ejectDiscAfterwards,
bool performFakeBurnForTesting,
int writeSpeed)
{
if ([pimpl->device->device isValid])
return pimpl->device->burn (listener, ejectDiscAfterwards, performFakeBurnForTesting, writeSpeed);
return "Couldn't open or write to the CD device";
}

+ 261
- 0
source/modules/juce_audio_devices/native/juce_mac_AudioCDReader.mm View File

@@ -0,0 +1,261 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
namespace CDReaderHelpers
{
inline const XmlElement* getElementForKey (const XmlElement& xml, const String& key)
{
forEachXmlChildElementWithTagName (xml, child, "key")
if (child->getAllSubText().trim() == key)
return child->getNextElement();
return nullptr;
}
static int getIntValueForKey (const XmlElement& xml, const String& key, int defaultValue = -1)
{
const XmlElement* const block = getElementForKey (xml, key);
return block != nullptr ? block->getAllSubText().trim().getIntValue() : defaultValue;
}
// Get the track offsets for a CD given an XmlElement representing its TOC.Plist.
// Returns NULL on success, otherwise a const char* representing an error.
static const char* getTrackOffsets (XmlDocument& xmlDocument, Array<int>& offsets)
{
const ScopedPointer<XmlElement> xml (xmlDocument.getDocumentElement());
if (xml == nullptr)
return "Couldn't parse XML in file";
const XmlElement* const dict = xml->getChildByName ("dict");
if (dict == nullptr)
return "Couldn't get top level dictionary";
const XmlElement* const sessions = getElementForKey (*dict, "Sessions");
if (sessions == nullptr)
return "Couldn't find sessions key";
const XmlElement* const session = sessions->getFirstChildElement();
if (session == nullptr)
return "Couldn't find first session";
const int leadOut = getIntValueForKey (*session, "Leadout Block");
if (leadOut < 0)
return "Couldn't find Leadout Block";
const XmlElement* const trackArray = getElementForKey (*session, "Track Array");
if (trackArray == nullptr)
return "Couldn't find Track Array";
forEachXmlChildElement (*trackArray, track)
{
const int trackValue = getIntValueForKey (*track, "Start Block");
if (trackValue < 0)
return "Couldn't find Start Block in the track";
offsets.add (trackValue * AudioCDReader::samplesPerFrame - 88200);
}
offsets.add (leadOut * AudioCDReader::samplesPerFrame - 88200);
return nullptr;
}
static void findDevices (Array<File>& cds)
{
File volumes ("/Volumes");
volumes.findChildFiles (cds, File::findDirectories, false);
for (int i = cds.size(); --i >= 0;)
if (! cds.getReference(i).getChildFile (".TOC.plist").exists())
cds.remove (i);
}
struct TrackSorter
{
static int getCDTrackNumber (const File& file)
{
return file.getFileName().initialSectionContainingOnly ("0123456789").getIntValue();
}
static int compareElements (const File& first, const File& second)
{
const int firstTrack = getCDTrackNumber (first);
const int secondTrack = getCDTrackNumber (second);
jassert (firstTrack > 0 && secondTrack > 0);
return firstTrack - secondTrack;
}
};
}
//==============================================================================
StringArray AudioCDReader::getAvailableCDNames()
{
Array<File> cds;
CDReaderHelpers::findDevices (cds);
StringArray names;
for (int i = 0; i < cds.size(); ++i)
names.add (cds.getReference(i).getFileName());
return names;
}
AudioCDReader* AudioCDReader::createReaderForCD (const int index)
{
Array<File> cds;
CDReaderHelpers::findDevices (cds);
if (cds[index].exists())
return new AudioCDReader (cds[index]);
return nullptr;
}
AudioCDReader::AudioCDReader (const File& volume)
: AudioFormatReader (0, "CD Audio"),
volumeDir (volume),
currentReaderTrack (-1),
reader (0)
{
sampleRate = 44100.0;
bitsPerSample = 16;
numChannels = 2;
usesFloatingPointData = false;
refreshTrackLengths();
}
AudioCDReader::~AudioCDReader()
{
}
void AudioCDReader::refreshTrackLengths()
{
tracks.clear();
trackStartSamples.clear();
lengthInSamples = 0;
volumeDir.findChildFiles (tracks, File::findFiles | File::ignoreHiddenFiles, false, "*.aiff");
CDReaderHelpers::TrackSorter sorter;
tracks.sort (sorter);
const File toc (volumeDir.getChildFile (".TOC.plist"));
if (toc.exists())
{
XmlDocument doc (toc);
const char* error = CDReaderHelpers::getTrackOffsets (doc, trackStartSamples);
(void) error; // could be logged..
lengthInSamples = trackStartSamples.getLast() - trackStartSamples.getFirst();
}
}
bool AudioCDReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples)
{
while (numSamples > 0)
{
int track = -1;
for (int i = 0; i < trackStartSamples.size() - 1; ++i)
{
if (startSampleInFile < trackStartSamples.getUnchecked (i + 1))
{
track = i;
break;
}
}
if (track < 0)
return false;
if (track != currentReaderTrack)
{
reader = nullptr;
if (FileInputStream* const in = tracks [track].createInputStream())
{
BufferedInputStream* const bin = new BufferedInputStream (in, 65536, true);
AiffAudioFormat format;
reader = format.createReaderFor (bin, true);
if (reader == nullptr)
currentReaderTrack = -1;
else
currentReaderTrack = track;
}
}
if (reader == nullptr)
return false;
const int startPos = (int) (startSampleInFile - trackStartSamples.getUnchecked (track));
const int numAvailable = (int) jmin ((int64) numSamples, reader->lengthInSamples - startPos);
reader->readSamples (destSamples, numDestChannels, startOffsetInDestBuffer, startPos, numAvailable);
numSamples -= numAvailable;
startSampleInFile += numAvailable;
}
return true;
}
bool AudioCDReader::isCDStillPresent() const
{
return volumeDir.exists();
}
void AudioCDReader::ejectDisk()
{
JUCE_AUTORELEASEPOOL
{
[[NSWorkspace sharedWorkspace] unmountAndEjectDeviceAtPath: juceStringToNS (volumeDir.getFullPathName())];
}
}
bool AudioCDReader::isTrackAudio (int trackNum) const
{
return tracks [trackNum].hasFileExtension (".aiff");
}
void AudioCDReader::enableIndexScanning (bool)
{
// any way to do this on a Mac??
}
int AudioCDReader::getLastIndex() const
{
return 0;
}
Array<int> AudioCDReader::findIndexesInTrack (const int /*trackNumber*/)
{
return Array<int>();
}

+ 1336
- 0
source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
File diff suppressed because it is too large
View File


+ 528
- 0
source/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp View File

@@ -0,0 +1,528 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_LOG_COREMIDI_ERRORS
#define JUCE_LOG_COREMIDI_ERRORS 1
#endif
namespace CoreMidiHelpers
{
static bool checkError (const OSStatus err, const int lineNum)
{
if (err == noErr)
return true;
#if JUCE_LOG_COREMIDI_ERRORS
Logger::writeToLog ("CoreMIDI error: " + String (lineNum) + " - " + String::toHexString ((int) err));
#endif
(void) lineNum;
return false;
}
#undef CHECK_ERROR
#define CHECK_ERROR(a) CoreMidiHelpers::checkError (a, __LINE__)
//==============================================================================
static String getMidiObjectName (MIDIObjectRef entity)
{
String result;
CFStringRef str = nullptr;
MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str);
if (str != nullptr)
{
result = String::fromCFString (str);
CFRelease (str);
}
return result;
}
static String getEndpointName (MIDIEndpointRef endpoint, bool isExternal)
{
String result (getMidiObjectName (endpoint));
MIDIEntityRef entity = 0; // NB: don't attempt to use nullptr for refs - it fails in some types of build.
MIDIEndpointGetEntity (endpoint, &entity);
if (entity == 0)
return result; // probably virtual
if (result.isEmpty())
result = getMidiObjectName (entity); // endpoint name is empty - try the entity
// now consider the device's name
MIDIDeviceRef device = 0;
MIDIEntityGetDevice (entity, &device);
if (device != 0)
{
const String deviceName (getMidiObjectName (device));
if (deviceName.isNotEmpty())
{
// if an external device has only one entity, throw away
// the endpoint name and just use the device name
if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2)
{
result = deviceName;
}
else if (! result.startsWithIgnoreCase (deviceName))
{
// prepend the device name to the entity name
result = (deviceName + " " + result).trimEnd();
}
}
}
return result;
}
static String getConnectedEndpointName (MIDIEndpointRef endpoint)
{
String result;
// Does the endpoint have connections?
CFDataRef connections = nullptr;
int numConnections = 0;
MIDIObjectGetDataProperty (endpoint, kMIDIPropertyConnectionUniqueID, &connections);
if (connections != nullptr)
{
numConnections = ((int) CFDataGetLength (connections)) / (int) sizeof (MIDIUniqueID);
if (numConnections > 0)
{
const SInt32* pid = reinterpret_cast <const SInt32*> (CFDataGetBytePtr (connections));
for (int i = 0; i < numConnections; ++i, ++pid)
{
MIDIUniqueID uid = (MIDIUniqueID) ByteOrder::swapIfLittleEndian ((uint32) *pid);
MIDIObjectRef connObject;
MIDIObjectType connObjectType;
OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType);
if (err == noErr)
{
String s;
if (connObjectType == kMIDIObjectType_ExternalSource
|| connObjectType == kMIDIObjectType_ExternalDestination)
{
// Connected to an external device's endpoint (10.3 and later).
s = getEndpointName (static_cast <MIDIEndpointRef> (connObject), true);
}
else
{
// Connected to an external device (10.2) (or something else, catch-all)
s = getMidiObjectName (connObject);
}
if (s.isNotEmpty())
{
if (result.isNotEmpty())
result += ", ";
result += s;
}
}
}
}
CFRelease (connections);
}
if (result.isEmpty()) // Here, either the endpoint had no connections, or we failed to obtain names for them.
result = getEndpointName (endpoint, false);
return result;
}
static StringArray findDevices (const bool forInput)
{
const ItemCount num = forInput ? MIDIGetNumberOfSources()
: MIDIGetNumberOfDestinations();
StringArray s;
for (ItemCount i = 0; i < num; ++i)
{
MIDIEndpointRef dest = forInput ? MIDIGetSource (i)
: MIDIGetDestination (i);
String name;
if (dest != 0)
name = getConnectedEndpointName (dest);
if (name.isEmpty())
name = "<error>";
s.add (name);
}
return s;
}
static void globalSystemChangeCallback (const MIDINotification*, void*)
{
// TODO.. Should pass-on this notification..
}
static String getGlobalMidiClientName()
{
if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
return app->getApplicationName();
return "JUCE";
}
static MIDIClientRef getGlobalMidiClient()
{
static MIDIClientRef globalMidiClient = 0;
if (globalMidiClient == 0)
{
// Since OSX 10.6, the MIDIClientCreate function will only work
// correctly when called from the message thread!
jassert (MessageManager::getInstance()->isThisTheMessageThread());
CFStringRef name = getGlobalMidiClientName().toCFString();
CHECK_ERROR (MIDIClientCreate (name, &globalSystemChangeCallback, nullptr, &globalMidiClient));
CFRelease (name);
}
return globalMidiClient;
}
//==============================================================================
class MidiPortAndEndpoint
{
public:
MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep)
: port (p), endPoint (ep)
{
}
~MidiPortAndEndpoint()
{
if (port != 0)
MIDIPortDispose (port);
if (port == 0 && endPoint != 0) // if port == nullptr, it means we created the endpoint, so it's safe to delete it
MIDIEndpointDispose (endPoint);
}
void send (const MIDIPacketList* const packets)
{
if (port != 0)
MIDISend (port, endPoint, packets);
else
MIDIReceived (endPoint, packets);
}
MIDIPortRef port;
MIDIEndpointRef endPoint;
};
//==============================================================================
class MidiPortAndCallback;
CriticalSection callbackLock;
Array<MidiPortAndCallback*> activeCallbacks;
class MidiPortAndCallback
{
public:
MidiPortAndCallback (MidiInputCallback& cb)
: input (nullptr), active (false), callback (cb), concatenator (2048)
{
}
~MidiPortAndCallback()
{
active = false;
{
const ScopedLock sl (callbackLock);
activeCallbacks.removeFirstMatchingValue (this);
}
if (portAndEndpoint != 0 && portAndEndpoint->port != 0)
CHECK_ERROR (MIDIPortDisconnectSource (portAndEndpoint->port, portAndEndpoint->endPoint));
}
void handlePackets (const MIDIPacketList* const pktlist)
{
const double time = Time::getMillisecondCounterHiRes() * 0.001;
const ScopedLock sl (callbackLock);
if (activeCallbacks.contains (this) && active)
{
const MIDIPacket* packet = &pktlist->packet[0];
for (unsigned int i = 0; i < pktlist->numPackets; ++i)
{
concatenator.pushMidiData (packet->data, (int) packet->length, time,
input, callback);
packet = MIDIPacketNext (packet);
}
}
}
MidiInput* input;
ScopedPointer<MidiPortAndEndpoint> portAndEndpoint;
volatile bool active;
private:
MidiInputCallback& callback;
MidiDataConcatenator concatenator;
};
static void midiInputProc (const MIDIPacketList* pktlist, void* readProcRefCon, void* /*srcConnRefCon*/)
{
static_cast <MidiPortAndCallback*> (readProcRefCon)->handlePackets (pktlist);
}
}
//==============================================================================
StringArray MidiOutput::getDevices() { return CoreMidiHelpers::findDevices (false); }
int MidiOutput::getDefaultDeviceIndex() { return 0; }
MidiOutput* MidiOutput::openDevice (int index)
{
MidiOutput* mo = nullptr;
if (isPositiveAndBelow (index, (int) MIDIGetNumberOfDestinations()))
{
MIDIEndpointRef endPoint = MIDIGetDestination ((ItemCount) index);
CFStringRef pname;
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname)))
{
MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient();
MIDIPortRef port;
if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname, &port)))
{
mo = new MidiOutput();
mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint);
}
CFRelease (pname);
}
}
return mo;
}
MidiOutput* MidiOutput::createNewDevice (const String& deviceName)
{
MidiOutput* mo = nullptr;
MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient();
MIDIEndpointRef endPoint;
CFStringRef name = deviceName.toCFString();
if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name, &endPoint)))
{
mo = new MidiOutput();
mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint);
}
CFRelease (name);
return mo;
}
MidiOutput::~MidiOutput()
{
delete static_cast<CoreMidiHelpers::MidiPortAndEndpoint*> (internal);
}
void MidiOutput::sendMessageNow (const MidiMessage& message)
{
#if JUCE_IOS
const MIDITimeStamp timeStamp = mach_absolute_time();
#else
const MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
#endif
HeapBlock <MIDIPacketList> allocatedPackets;
MIDIPacketList stackPacket;
MIDIPacketList* packetToSend = &stackPacket;
const size_t dataSize = (size_t) message.getRawDataSize();
if (message.isSysEx())
{
const int maxPacketSize = 256;
int pos = 0, bytesLeft = (int) dataSize;
const int numPackets = (bytesLeft + maxPacketSize - 1) / maxPacketSize;
allocatedPackets.malloc ((size_t) (32 * (size_t) numPackets + dataSize), 1);
packetToSend = allocatedPackets;
packetToSend->numPackets = (UInt32) numPackets;
MIDIPacket* p = packetToSend->packet;
for (int i = 0; i < numPackets; ++i)
{
p->timeStamp = timeStamp;
p->length = (UInt16) jmin (maxPacketSize, bytesLeft);
memcpy (p->data, message.getRawData() + pos, p->length);
pos += p->length;
bytesLeft -= p->length;
p = MIDIPacketNext (p);
}
}
else if (dataSize < 65536) // max packet size
{
const size_t stackCapacity = sizeof (stackPacket.packet->data);
if (dataSize > stackCapacity)
{
allocatedPackets.malloc ((sizeof (MIDIPacketList) - stackCapacity) + dataSize, 1);
packetToSend = allocatedPackets;
}
packetToSend->numPackets = 1;
MIDIPacket& p = *(packetToSend->packet);
p.timeStamp = timeStamp;
p.length = (UInt16) dataSize;
memcpy (p.data, message.getRawData(), dataSize);
}
else
{
jassertfalse; // packet too large to send!
return;
}
static_cast<CoreMidiHelpers::MidiPortAndEndpoint*> (internal)->send (packetToSend);
}
//==============================================================================
StringArray MidiInput::getDevices() { return CoreMidiHelpers::findDevices (true); }
int MidiInput::getDefaultDeviceIndex() { return 0; }
MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
{
jassert (callback != nullptr);
using namespace CoreMidiHelpers;
MidiInput* newInput = nullptr;
if (isPositiveAndBelow (index, (int) MIDIGetNumberOfSources()))
{
if (MIDIEndpointRef endPoint = MIDIGetSource ((ItemCount) index))
{
CFStringRef name;
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name)))
{
if (MIDIClientRef client = getGlobalMidiClient())
{
MIDIPortRef port;
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
if (CHECK_ERROR (MIDIInputPortCreate (client, name, midiInputProc, mpc, &port)))
{
if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, nullptr)))
{
mpc->portAndEndpoint = new MidiPortAndEndpoint (port, endPoint);
newInput = new MidiInput (getDevices() [index]);
mpc->input = newInput;
newInput->internal = mpc;
const ScopedLock sl (callbackLock);
activeCallbacks.add (mpc.release());
}
else
{
CHECK_ERROR (MIDIPortDispose (port));
}
}
}
}
CFRelease (name);
}
}
return newInput;
}
MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback)
{
jassert (callback != nullptr);
using namespace CoreMidiHelpers;
MidiInput* mi = nullptr;
if (MIDIClientRef client = getGlobalMidiClient())
{
ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback));
mpc->active = false;
MIDIEndpointRef endPoint;
CFStringRef name = deviceName.toCFString();
if (CHECK_ERROR (MIDIDestinationCreate (client, name, midiInputProc, mpc, &endPoint)))
{
mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint);
mi = new MidiInput (deviceName);
mpc->input = mi;
mi->internal = mpc;
const ScopedLock sl (callbackLock);
activeCallbacks.add (mpc.release());
}
CFRelease (name);
}
return mi;
}
MidiInput::MidiInput (const String& nm) : name (nm)
{
}
MidiInput::~MidiInput()
{
delete static_cast<CoreMidiHelpers::MidiPortAndCallback*> (internal);
}
void MidiInput::start()
{
const ScopedLock sl (CoreMidiHelpers::callbackLock);
static_cast<CoreMidiHelpers::MidiPortAndCallback*> (internal)->active = true;
}
void MidiInput::stop()
{
const ScopedLock sl (CoreMidiHelpers::callbackLock);
static_cast<CoreMidiHelpers::MidiPortAndCallback*> (internal)->active = false;
}
#undef CHECK_ERROR

+ 1638
- 0
source/modules/juce_audio_devices/native/juce_win32_ASIO.cpp
File diff suppressed because it is too large
View File


+ 411
- 0
source/modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp View File

@@ -0,0 +1,411 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
namespace CDBurnerHelpers
{
IDiscRecorder* enumCDBurners (StringArray* list, int indexToOpen, IDiscMaster** master)
{
CoInitialize (0);
IDiscMaster* dm;
IDiscRecorder* result = nullptr;
if (SUCCEEDED (CoCreateInstance (CLSID_MSDiscMasterObj, 0,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
IID_IDiscMaster,
(void**) &dm)))
{
if (SUCCEEDED (dm->Open()))
{
IEnumDiscRecorders* drEnum = nullptr;
if (SUCCEEDED (dm->EnumDiscRecorders (&drEnum)))
{
IDiscRecorder* dr = nullptr;
DWORD dummy;
int index = 0;
while (drEnum->Next (1, &dr, &dummy) == S_OK)
{
if (indexToOpen == index)
{
result = dr;
break;
}
else if (list != nullptr)
{
BSTR path;
if (SUCCEEDED (dr->GetPath (&path)))
list->add ((const WCHAR*) path);
}
++index;
dr->Release();
}
drEnum->Release();
}
if (master == 0)
dm->Close();
}
if (master != nullptr)
*master = dm;
else
dm->Release();
}
return result;
}
}
//==============================================================================
class AudioCDBurner::Pimpl : public ComBaseClassHelper <IDiscMasterProgressEvents>,
public Timer
{
public:
Pimpl (AudioCDBurner& owner_, IDiscMaster* discMaster_, IDiscRecorder* discRecorder_)
: owner (owner_), discMaster (discMaster_), discRecorder (discRecorder_), redbook (0),
listener (0), progress (0), shouldCancel (false)
{
HRESULT hr = discMaster->SetActiveDiscMasterFormat (IID_IRedbookDiscMaster, (void**) &redbook);
jassert (SUCCEEDED (hr));
hr = discMaster->SetActiveDiscRecorder (discRecorder);
//jassert (SUCCEEDED (hr));
lastState = getDiskState();
startTimer (2000);
}
~Pimpl() {}
void releaseObjects()
{
discRecorder->Close();
if (redbook != nullptr)
redbook->Release();
discRecorder->Release();
discMaster->Release();
Release();
}
JUCE_COMRESULT QueryCancel (boolean* pbCancel)
{
if (listener != nullptr && ! shouldCancel)
shouldCancel = listener->audioCDBurnProgress (progress);
*pbCancel = shouldCancel;
return S_OK;
}
JUCE_COMRESULT NotifyBlockProgress (long nCompleted, long nTotal)
{
progress = nCompleted / (float) nTotal;
shouldCancel = listener != nullptr && listener->audioCDBurnProgress (progress);
return E_NOTIMPL;
}
JUCE_COMRESULT NotifyPnPActivity (void) { return E_NOTIMPL; }
JUCE_COMRESULT NotifyAddProgress (long /*nCompletedSteps*/, long /*nTotalSteps*/) { return E_NOTIMPL; }
JUCE_COMRESULT NotifyTrackProgress (long /*nCurrentTrack*/, long /*nTotalTracks*/) { return E_NOTIMPL; }
JUCE_COMRESULT NotifyPreparingBurn (long /*nEstimatedSeconds*/) { return E_NOTIMPL; }
JUCE_COMRESULT NotifyClosingDisc (long /*nEstimatedSeconds*/) { return E_NOTIMPL; }
JUCE_COMRESULT NotifyBurnComplete (HRESULT /*status*/) { return E_NOTIMPL; }
JUCE_COMRESULT NotifyEraseComplete (HRESULT /*status*/) { return E_NOTIMPL; }
class ScopedDiscOpener
{
public:
ScopedDiscOpener (Pimpl& p) : pimpl (p) { pimpl.discRecorder->OpenExclusive(); }
~ScopedDiscOpener() { pimpl.discRecorder->Close(); }
private:
Pimpl& pimpl;
JUCE_DECLARE_NON_COPYABLE (ScopedDiscOpener)
};
DiskState getDiskState()
{
const ScopedDiscOpener opener (*this);
long type, flags;
HRESULT hr = discRecorder->QueryMediaType (&type, &flags);
if (FAILED (hr))
return unknown;
if (type != 0 && (flags & MEDIA_WRITABLE) != 0)
return writableDiskPresent;
if (type == 0)
return noDisc;
return readOnlyDiskPresent;
}
int getIntProperty (const LPOLESTR name, const int defaultReturn) const
{
ComSmartPtr<IPropertyStorage> prop;
if (FAILED (discRecorder->GetRecorderProperties (prop.resetAndGetPointerAddress())))
return defaultReturn;
PROPSPEC iPropSpec;
iPropSpec.ulKind = PRSPEC_LPWSTR;
iPropSpec.lpwstr = name;
PROPVARIANT iPropVariant;
return FAILED (prop->ReadMultiple (1, &iPropSpec, &iPropVariant))
? defaultReturn : (int) iPropVariant.lVal;
}
bool setIntProperty (const LPOLESTR name, const int value) const
{
ComSmartPtr<IPropertyStorage> prop;
if (FAILED (discRecorder->GetRecorderProperties (prop.resetAndGetPointerAddress())))
return false;
PROPSPEC iPropSpec;
iPropSpec.ulKind = PRSPEC_LPWSTR;
iPropSpec.lpwstr = name;
PROPVARIANT iPropVariant;
if (FAILED (prop->ReadMultiple (1, &iPropSpec, &iPropVariant)))
return false;
iPropVariant.lVal = (long) value;
return SUCCEEDED (prop->WriteMultiple (1, &iPropSpec, &iPropVariant, iPropVariant.vt))
&& SUCCEEDED (discRecorder->SetRecorderProperties (prop));
}
void timerCallback() override
{
const DiskState state = getDiskState();
if (state != lastState)
{
lastState = state;
owner.sendChangeMessage();
}
}
AudioCDBurner& owner;
DiskState lastState;
IDiscMaster* discMaster;
IDiscRecorder* discRecorder;
IRedbookDiscMaster* redbook;
AudioCDBurner::BurnProgressListener* listener;
float progress;
bool shouldCancel;
};
//==============================================================================
AudioCDBurner::AudioCDBurner (const int deviceIndex)
{
IDiscMaster* discMaster = nullptr;
IDiscRecorder* discRecorder = CDBurnerHelpers::enumCDBurners (0, deviceIndex, &discMaster);
if (discRecorder != nullptr)
pimpl = new Pimpl (*this, discMaster, discRecorder);
}
AudioCDBurner::~AudioCDBurner()
{
if (pimpl != nullptr)
pimpl.release()->releaseObjects();
}
StringArray AudioCDBurner::findAvailableDevices()
{
StringArray devs;
CDBurnerHelpers::enumCDBurners (&devs, -1, 0);
return devs;
}
AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
{
ScopedPointer<AudioCDBurner> b (new AudioCDBurner (deviceIndex));
if (b->pimpl == 0)
b = nullptr;
return b.release();
}
AudioCDBurner::DiskState AudioCDBurner::getDiskState() const
{
return pimpl->getDiskState();
}
bool AudioCDBurner::isDiskPresent() const
{
return getDiskState() == writableDiskPresent;
}
bool AudioCDBurner::openTray()
{
const Pimpl::ScopedDiscOpener opener (*pimpl);
return SUCCEEDED (pimpl->discRecorder->Eject());
}
AudioCDBurner::DiskState AudioCDBurner::waitUntilStateChange (int timeOutMilliseconds)
{
const int64 timeout = Time::currentTimeMillis() + timeOutMilliseconds;
DiskState oldState = getDiskState();
DiskState newState = oldState;
while (newState == oldState && Time::currentTimeMillis() < timeout)
{
newState = getDiskState();
Thread::sleep (jmin (250, (int) (timeout - Time::currentTimeMillis())));
}
return newState;
}
Array<int> AudioCDBurner::getAvailableWriteSpeeds() const
{
Array<int> results;
const int maxSpeed = pimpl->getIntProperty (L"MaxWriteSpeed", 1);
const int speeds[] = { 1, 2, 4, 8, 12, 16, 20, 24, 32, 40, 64, 80 };
for (int i = 0; i < numElementsInArray (speeds); ++i)
if (speeds[i] <= maxSpeed)
results.add (speeds[i]);
results.addIfNotAlreadyThere (maxSpeed);
return results;
}
bool AudioCDBurner::setBufferUnderrunProtection (const bool shouldBeEnabled)
{
if (pimpl->getIntProperty (L"BufferUnderrunFreeCapable", 0) == 0)
return false;
pimpl->setIntProperty (L"EnableBufferUnderrunFree", shouldBeEnabled ? -1 : 0);
return pimpl->getIntProperty (L"EnableBufferUnderrunFree", 0) != 0;
}
int AudioCDBurner::getNumAvailableAudioBlocks() const
{
long blocksFree = 0;
pimpl->redbook->GetAvailableAudioTrackBlocks (&blocksFree);
return blocksFree;
}
String AudioCDBurner::burn (AudioCDBurner::BurnProgressListener* listener, bool ejectDiscAfterwards,
bool performFakeBurnForTesting, int writeSpeed)
{
pimpl->setIntProperty (L"WriteSpeed", writeSpeed > 0 ? writeSpeed : -1);
pimpl->listener = listener;
pimpl->progress = 0;
pimpl->shouldCancel = false;
UINT_PTR cookie;
HRESULT hr = pimpl->discMaster->ProgressAdvise ((AudioCDBurner::Pimpl*) pimpl, &cookie);
hr = pimpl->discMaster->RecordDisc (performFakeBurnForTesting,
ejectDiscAfterwards);
String error;
if (hr != S_OK)
{
const char* e = "Couldn't open or write to the CD device";
if (hr == IMAPI_E_USERABORT)
e = "User cancelled the write operation";
else if (hr == IMAPI_E_MEDIUM_NOTPRESENT || hr == IMAPI_E_TRACKOPEN)
e = "No Disk present";
error = e;
}
pimpl->discMaster->ProgressUnadvise (cookie);
pimpl->listener = 0;
return error;
}
bool AudioCDBurner::addAudioTrack (AudioSource* audioSource, int numSamples)
{
if (audioSource == 0)
return false;
ScopedPointer<AudioSource> source (audioSource);
long bytesPerBlock;
HRESULT hr = pimpl->redbook->GetAudioBlockSize (&bytesPerBlock);
const int samplesPerBlock = bytesPerBlock / 4;
bool ok = true;
hr = pimpl->redbook->CreateAudioTrack ((long) numSamples / (bytesPerBlock * 4));
HeapBlock <byte> buffer (bytesPerBlock);
AudioSampleBuffer sourceBuffer (2, samplesPerBlock);
int samplesDone = 0;
source->prepareToPlay (samplesPerBlock, 44100.0);
while (ok)
{
{
AudioSourceChannelInfo info (&sourceBuffer, 0, samplesPerBlock);
sourceBuffer.clear();
source->getNextAudioBlock (info);
}
buffer.clear (bytesPerBlock);
typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian,
AudioData::Interleaved, AudioData::NonConst> CDSampleFormat;
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian,
AudioData::NonInterleaved, AudioData::Const> SourceSampleFormat;
CDSampleFormat left (buffer, 2);
left.convertSamples (SourceSampleFormat (sourceBuffer.getSampleData (0)), samplesPerBlock);
CDSampleFormat right (buffer + 2, 2);
right.convertSamples (SourceSampleFormat (sourceBuffer.getSampleData (1)), samplesPerBlock);
hr = pimpl->redbook->AddAudioTrackBlocks (buffer, bytesPerBlock);
if (FAILED (hr))
ok = false;
samplesDone += samplesPerBlock;
if (samplesDone >= numSamples)
break;
}
hr = pimpl->redbook->CloseAudioTrack();
return ok && hr == S_OK;
}

+ 1309
- 0
source/modules/juce_audio_devices/native/juce_win32_AudioCDReader.cpp
File diff suppressed because it is too large
View File


+ 1288
- 0
source/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp
File diff suppressed because it is too large
View File


+ 483
- 0
source/modules/juce_audio_devices/native/juce_win32_Midi.cpp View File

@@ -0,0 +1,483 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
class MidiInCollector
{
public:
MidiInCollector (MidiInput* const input_,
MidiInputCallback& callback_)
: deviceHandle (0),
input (input_),
callback (callback_),
concatenator (4096),
isStarted (false),
startTime (0)
{
}
~MidiInCollector()
{
stop();
if (deviceHandle != 0)
{
for (int count = 5; --count >= 0;)
{
if (midiInClose (deviceHandle) == MMSYSERR_NOERROR)
break;
Sleep (20);
}
}
}
//==============================================================================
void handleMessage (const uint8* bytes, const uint32 timeStamp)
{
if (bytes[0] >= 0x80 && isStarted)
{
concatenator.pushMidiData (bytes, MidiMessage::getMessageLengthFromFirstByte (bytes[0]),
convertTimeStamp (timeStamp), input, callback);
writeFinishedBlocks();
}
}
void handleSysEx (MIDIHDR* const hdr, const uint32 timeStamp)
{
if (isStarted && hdr->dwBytesRecorded > 0)
{
concatenator.pushMidiData (hdr->lpData, (int) hdr->dwBytesRecorded,
convertTimeStamp (timeStamp), input, callback);
writeFinishedBlocks();
}
}
void start()
{
if (deviceHandle != 0 && ! isStarted)
{
activeMidiCollectors.addIfNotAlreadyThere (this);
for (int i = 0; i < (int) numHeaders; ++i)
{
headers[i].prepare (deviceHandle);
headers[i].write (deviceHandle);
}
startTime = Time::getMillisecondCounterHiRes();
MMRESULT res = midiInStart (deviceHandle);
if (res == MMSYSERR_NOERROR)
{
concatenator.reset();
isStarted = true;
}
else
{
unprepareAllHeaders();
}
}
}
void stop()
{
if (isStarted)
{
isStarted = false;
midiInReset (deviceHandle);
midiInStop (deviceHandle);
activeMidiCollectors.removeFirstMatchingValue (this);
unprepareAllHeaders();
concatenator.reset();
}
}
static void CALLBACK midiInCallback (HMIDIIN, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR midiMessage, DWORD_PTR timeStamp)
{
MidiInCollector* const collector = reinterpret_cast <MidiInCollector*> (dwInstance);
if (activeMidiCollectors.contains (collector))
{
if (uMsg == MIM_DATA)
collector->handleMessage ((const uint8*) &midiMessage, (uint32) timeStamp);
else if (uMsg == MIM_LONGDATA)
collector->handleSysEx ((MIDIHDR*) midiMessage, (uint32) timeStamp);
}
}
HMIDIIN deviceHandle;
private:
static Array <MidiInCollector*, CriticalSection> activeMidiCollectors;
MidiInput* input;
MidiInputCallback& callback;
MidiDataConcatenator concatenator;
bool volatile isStarted;
double startTime;
class MidiHeader
{
public:
MidiHeader() {}
void prepare (HMIDIIN deviceHandle)
{
zerostruct (hdr);
hdr.lpData = data;
hdr.dwBufferLength = (DWORD) numElementsInArray (data);
midiInPrepareHeader (deviceHandle, &hdr, sizeof (hdr));
}
void unprepare (HMIDIIN deviceHandle)
{
if ((hdr.dwFlags & WHDR_DONE) != 0)
{
int c = 10;
while (--c >= 0 && midiInUnprepareHeader (deviceHandle, &hdr, sizeof (hdr)) == MIDIERR_STILLPLAYING)
Thread::sleep (20);
jassert (c >= 0);
}
}
void write (HMIDIIN deviceHandle)
{
hdr.dwBytesRecorded = 0;
midiInAddBuffer (deviceHandle, &hdr, sizeof (hdr));
}
void writeIfFinished (HMIDIIN deviceHandle)
{
if ((hdr.dwFlags & WHDR_DONE) != 0)
write (deviceHandle);
}
private:
MIDIHDR hdr;
char data [256];
JUCE_DECLARE_NON_COPYABLE (MidiHeader)
};
enum { numHeaders = 32 };
MidiHeader headers [numHeaders];
void writeFinishedBlocks()
{
for (int i = 0; i < (int) numHeaders; ++i)
headers[i].writeIfFinished (deviceHandle);
}
void unprepareAllHeaders()
{
for (int i = 0; i < (int) numHeaders; ++i)
headers[i].unprepare (deviceHandle);
}
double convertTimeStamp (uint32 timeStamp)
{
double t = startTime + timeStamp;
const double now = Time::getMillisecondCounterHiRes();
if (t > now)
{
if (t > now + 2.0)
startTime -= 1.0;
t = now;
}
return t * 0.001;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInCollector)
};
Array <MidiInCollector*, CriticalSection> MidiInCollector::activeMidiCollectors;
//==============================================================================
StringArray MidiInput::getDevices()
{
StringArray s;
const UINT num = midiInGetNumDevs();
for (UINT i = 0; i < num; ++i)
{
MIDIINCAPS mc = { 0 };
if (midiInGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
s.add (String (mc.szPname, sizeof (mc.szPname)));
}
return s;
}
int MidiInput::getDefaultDeviceIndex()
{
return 0;
}
MidiInput* MidiInput::openDevice (const int index, MidiInputCallback* const callback)
{
if (callback == nullptr)
return nullptr;
UINT deviceId = MIDI_MAPPER;
int n = 0;
String name;
const UINT num = midiInGetNumDevs();
for (UINT i = 0; i < num; ++i)
{
MIDIINCAPS mc = { 0 };
if (midiInGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
{
if (index == n)
{
deviceId = i;
name = String (mc.szPname, (size_t) numElementsInArray (mc.szPname));
break;
}
++n;
}
}
ScopedPointer <MidiInput> in (new MidiInput (name));
ScopedPointer <MidiInCollector> collector (new MidiInCollector (in, *callback));
HMIDIIN h;
MMRESULT err = midiInOpen (&h, deviceId,
(DWORD_PTR) &MidiInCollector::midiInCallback,
(DWORD_PTR) (MidiInCollector*) collector,
CALLBACK_FUNCTION);
if (err == MMSYSERR_NOERROR)
{
collector->deviceHandle = h;
in->internal = collector.release();
return in.release();
}
return nullptr;
}
MidiInput::MidiInput (const String& name_)
: name (name_),
internal (0)
{
}
MidiInput::~MidiInput()
{
delete static_cast <MidiInCollector*> (internal);
}
void MidiInput::start() { static_cast <MidiInCollector*> (internal)->start(); }
void MidiInput::stop() { static_cast <MidiInCollector*> (internal)->stop(); }
//==============================================================================
struct MidiOutHandle
{
int refCount;
UINT deviceId;
HMIDIOUT handle;
static Array<MidiOutHandle*> activeHandles;
private:
JUCE_LEAK_DETECTOR (MidiOutHandle)
};
Array<MidiOutHandle*> MidiOutHandle::activeHandles;
//==============================================================================
StringArray MidiOutput::getDevices()
{
StringArray s;
const UINT num = midiOutGetNumDevs();
for (UINT i = 0; i < num; ++i)
{
MIDIOUTCAPS mc = { 0 };
if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
s.add (String (mc.szPname, sizeof (mc.szPname)));
}
return s;
}
int MidiOutput::getDefaultDeviceIndex()
{
const UINT num = midiOutGetNumDevs();
int n = 0;
for (UINT i = 0; i < num; ++i)
{
MIDIOUTCAPS mc = { 0 };
if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
{
if ((mc.wTechnology & MOD_MAPPER) != 0)
return n;
++n;
}
}
return 0;
}
MidiOutput* MidiOutput::openDevice (int index)
{
UINT deviceId = MIDI_MAPPER;
const UINT num = midiOutGetNumDevs();
int n = 0;
for (UINT i = 0; i < num; ++i)
{
MIDIOUTCAPS mc = { 0 };
if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
{
// use the microsoft sw synth as a default - best not to allow deviceId
// to be MIDI_MAPPER, or else device sharing breaks
if (String (mc.szPname, sizeof (mc.szPname)).containsIgnoreCase ("microsoft"))
deviceId = i;
if (index == n)
{
deviceId = i;
break;
}
++n;
}
}
for (int i = MidiOutHandle::activeHandles.size(); --i >= 0;)
{
MidiOutHandle* const han = MidiOutHandle::activeHandles.getUnchecked(i);
if (han->deviceId == deviceId)
{
han->refCount++;
MidiOutput* const out = new MidiOutput();
out->internal = han;
return out;
}
}
for (int i = 4; --i >= 0;)
{
HMIDIOUT h = 0;
MMRESULT res = midiOutOpen (&h, deviceId, 0, 0, CALLBACK_NULL);
if (res == MMSYSERR_NOERROR)
{
MidiOutHandle* const han = new MidiOutHandle();
han->deviceId = deviceId;
han->refCount = 1;
han->handle = h;
MidiOutHandle::activeHandles.add (han);
MidiOutput* const out = new MidiOutput();
out->internal = han;
return out;
}
else if (res == MMSYSERR_ALLOCATED)
{
Sleep (100);
}
else
{
break;
}
}
return nullptr;
}
MidiOutput::~MidiOutput()
{
stopBackgroundThread();
MidiOutHandle* const h = static_cast <MidiOutHandle*> (internal);
if (MidiOutHandle::activeHandles.contains (h) && --(h->refCount) == 0)
{
midiOutClose (h->handle);
MidiOutHandle::activeHandles.removeFirstMatchingValue (h);
delete h;
}
}
void MidiOutput::sendMessageNow (const MidiMessage& message)
{
const MidiOutHandle* const handle = static_cast <const MidiOutHandle*> (internal);
if (message.getRawDataSize() > 3 || message.isSysEx())
{
MIDIHDR h = { 0 };
h.lpData = (char*) message.getRawData();
h.dwBytesRecorded = h.dwBufferLength = (DWORD) message.getRawDataSize();
if (midiOutPrepareHeader (handle->handle, &h, sizeof (MIDIHDR)) == MMSYSERR_NOERROR)
{
MMRESULT res = midiOutLongMsg (handle->handle, &h, sizeof (MIDIHDR));
if (res == MMSYSERR_NOERROR)
{
while ((h.dwFlags & MHDR_DONE) == 0)
Sleep (1);
int count = 500; // 1 sec timeout
while (--count >= 0)
{
res = midiOutUnprepareHeader (handle->handle, &h, sizeof (MIDIHDR));
if (res == MIDIERR_STILLPLAYING)
Sleep (2);
else
break;
}
}
}
}
else
{
midiOutShortMsg (handle->handle, *(unsigned int*) message.getRawData());
}
}

+ 1511
- 0
source/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp
File diff suppressed because it is too large
View File


+ 183
- 0
source/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp View File

@@ -0,0 +1,183 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioSourcePlayer::AudioSourcePlayer()
: source (nullptr),
sampleRate (0),
bufferSize (0),
tempBuffer (2, 8),
lastGain (1.0f),
gain (1.0f)
{
}
AudioSourcePlayer::~AudioSourcePlayer()
{
setSource (nullptr);
}
void AudioSourcePlayer::setSource (AudioSource* newSource)
{
if (source != newSource)
{
AudioSource* const oldSource = source;
if (newSource != nullptr && bufferSize > 0 && sampleRate > 0)
newSource->prepareToPlay (bufferSize, sampleRate);
{
const ScopedLock sl (readLock);
source = newSource;
}
if (oldSource != nullptr)
oldSource->releaseResources();
}
}
void AudioSourcePlayer::setGain (const float newGain) noexcept
{
gain = newGain;
}
void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData,
int totalNumInputChannels,
float** outputChannelData,
int totalNumOutputChannels,
int numSamples)
{
// these should have been prepared by audioDeviceAboutToStart()...
jassert (sampleRate > 0 && bufferSize > 0);
const ScopedLock sl (readLock);
if (source != nullptr)
{
int numActiveChans = 0, numInputs = 0, numOutputs = 0;
// messy stuff needed to compact the channels down into an array
// of non-zero pointers..
for (int i = 0; i < totalNumInputChannels; ++i)
{
if (inputChannelData[i] != nullptr)
{
inputChans [numInputs++] = inputChannelData[i];
if (numInputs >= numElementsInArray (inputChans))
break;
}
}
for (int i = 0; i < totalNumOutputChannels; ++i)
{
if (outputChannelData[i] != nullptr)
{
outputChans [numOutputs++] = outputChannelData[i];
if (numOutputs >= numElementsInArray (outputChans))
break;
}
}
if (numInputs > numOutputs)
{
// if there aren't enough output channels for the number of
// inputs, we need to create some temporary extra ones (can't
// use the input data in case it gets written to)
tempBuffer.setSize (numInputs - numOutputs, numSamples,
false, false, true);
for (int i = 0; i < numOutputs; ++i)
{
channels[numActiveChans] = outputChans[i];
memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples);
++numActiveChans;
}
for (int i = numOutputs; i < numInputs; ++i)
{
channels[numActiveChans] = tempBuffer.getSampleData (i - numOutputs, 0);
memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples);
++numActiveChans;
}
}
else
{
for (int i = 0; i < numInputs; ++i)
{
channels[numActiveChans] = outputChans[i];
memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples);
++numActiveChans;
}
for (int i = numInputs; i < numOutputs; ++i)
{
channels[numActiveChans] = outputChans[i];
zeromem (channels[numActiveChans], sizeof (float) * (size_t) numSamples);
++numActiveChans;
}
}
AudioSampleBuffer buffer (channels, numActiveChans, numSamples);
AudioSourceChannelInfo info (&buffer, 0, numSamples);
source->getNextAudioBlock (info);
for (int i = info.buffer->getNumChannels(); --i >= 0;)
buffer.applyGainRamp (i, info.startSample, info.numSamples, lastGain, gain);
lastGain = gain;
}
else
{
for (int i = 0; i < totalNumOutputChannels; ++i)
if (outputChannelData[i] != nullptr)
zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples);
}
}
void AudioSourcePlayer::audioDeviceAboutToStart (AudioIODevice* device)
{
prepareToPlay (device->getCurrentSampleRate(),
device->getCurrentBufferSizeSamples());
}
void AudioSourcePlayer::prepareToPlay (double newSampleRate, int newBufferSize)
{
sampleRate = newSampleRate;
bufferSize = newBufferSize;
zeromem (channels, sizeof (channels));
if (source != nullptr)
source->prepareToPlay (bufferSize, sampleRate);
}
void AudioSourcePlayer::audioDeviceStopped()
{
if (source != nullptr)
source->releaseResources();
sampleRate = 0.0;
bufferSize = 0;
tempBuffer.setSize (2, 8);
}

+ 116
- 0
source/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h View File

@@ -0,0 +1,116 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOSOURCEPLAYER_H_INCLUDED
#define JUCE_AUDIOSOURCEPLAYER_H_INCLUDED
//==============================================================================
/**
Wrapper class to continuously stream audio from an audio source to an
AudioIODevice.
This object acts as an AudioIODeviceCallback, so can be attached to an
output device, and will stream audio from an AudioSource.
*/
class JUCE_API AudioSourcePlayer : public AudioIODeviceCallback
{
public:
//==============================================================================
/** Creates an empty AudioSourcePlayer. */
AudioSourcePlayer();
/** Destructor.
Make sure this object isn't still being used by an AudioIODevice before
deleting it!
*/
virtual ~AudioSourcePlayer();
//==============================================================================
/** Changes the current audio source to play from.
If the source passed in is already being used, this method will do nothing.
If the source is not null, its prepareToPlay() method will be called
before it starts being used for playback.
If there's another source currently playing, its releaseResources() method
will be called after it has been swapped for the new one.
@param newSource the new source to use - this will NOT be deleted
by this object when no longer needed, so it's the
caller's responsibility to manage it.
*/
void setSource (AudioSource* newSource);
/** Returns the source that's playing.
May return 0 if there's no source.
*/
AudioSource* getCurrentSource() const noexcept { return source; }
/** Sets a gain to apply to the audio data.
@see getGain
*/
void setGain (float newGain) noexcept;
/** Returns the current gain.
@see setGain
*/
float getGain() const noexcept { return gain; }
//==============================================================================
/** Implementation of the AudioIODeviceCallback method. */
void audioDeviceIOCallback (const float** inputChannelData,
int totalNumInputChannels,
float** outputChannelData,
int totalNumOutputChannels,
int numSamples) override;
/** Implementation of the AudioIODeviceCallback method. */
void audioDeviceAboutToStart (AudioIODevice* device) override;
/** Implementation of the AudioIODeviceCallback method. */
void audioDeviceStopped() override;
/** An alternative method for initialising the source without an AudioIODevice. */
void prepareToPlay (double sampleRate, int blockSize);
private:
//==============================================================================
CriticalSection readLock;
AudioSource* source;
double sampleRate;
int bufferSize;
float* channels [128];
float* outputChans [128];
const float* inputChans [128];
AudioSampleBuffer tempBuffer;
float lastGain, gain;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourcePlayer)
};
#endif // JUCE_AUDIOSOURCEPLAYER_H_INCLUDED

+ 300
- 0
source/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp View File

@@ -0,0 +1,300 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioTransportSource::AudioTransportSource()
: source (nullptr),
resamplerSource (nullptr),
bufferingSource (nullptr),
positionableSource (nullptr),
masterSource (nullptr),
gain (1.0f),
lastGain (1.0f),
playing (false),
stopped (true),
sampleRate (44100.0),
sourceSampleRate (0.0),
blockSize (128),
readAheadBufferSize (0),
isPrepared (false),
inputStreamEOF (false)
{
}
AudioTransportSource::~AudioTransportSource()
{
setSource (nullptr);
releaseMasterResources();
}
void AudioTransportSource::setSource (PositionableAudioSource* const newSource,
int readAheadBufferSize_,
TimeSliceThread* readAheadThread,
double sourceSampleRateToCorrectFor,
int maxNumChannels)
{
if (source == newSource)
{
if (source == nullptr)
return;
setSource (nullptr, 0, nullptr); // deselect and reselect to avoid releasing resources wrongly
}
readAheadBufferSize = readAheadBufferSize_;
sourceSampleRate = sourceSampleRateToCorrectFor;
ResamplingAudioSource* newResamplerSource = nullptr;
BufferingAudioSource* newBufferingSource = nullptr;
PositionableAudioSource* newPositionableSource = nullptr;
AudioSource* newMasterSource = nullptr;
ScopedPointer <ResamplingAudioSource> oldResamplerSource (resamplerSource);
ScopedPointer <BufferingAudioSource> oldBufferingSource (bufferingSource);
AudioSource* oldMasterSource = masterSource;
if (newSource != nullptr)
{
newPositionableSource = newSource;
if (readAheadBufferSize_ > 0)
{
// If you want to use a read-ahead buffer, you must also provide a TimeSliceThread
// for it to use!
jassert (readAheadThread != nullptr);
newPositionableSource = newBufferingSource
= new BufferingAudioSource (newPositionableSource, *readAheadThread,
false, readAheadBufferSize_, maxNumChannels);
}
newPositionableSource->setNextReadPosition (0);
if (sourceSampleRateToCorrectFor > 0)
newMasterSource = newResamplerSource
= new ResamplingAudioSource (newPositionableSource, false, maxNumChannels);
else
newMasterSource = newPositionableSource;
if (isPrepared)
{
if (newResamplerSource != nullptr && sourceSampleRate > 0 && sampleRate > 0)
newResamplerSource->setResamplingRatio (sourceSampleRate / sampleRate);
newMasterSource->prepareToPlay (blockSize, sampleRate);
}
}
{
const ScopedLock sl (callbackLock);
source = newSource;
resamplerSource = newResamplerSource;
bufferingSource = newBufferingSource;
masterSource = newMasterSource;
positionableSource = newPositionableSource;
playing = false;
}
if (oldMasterSource != nullptr)
oldMasterSource->releaseResources();
}
void AudioTransportSource::start()
{
if ((! playing) && masterSource != nullptr)
{
{
const ScopedLock sl (callbackLock);
playing = true;
stopped = false;
inputStreamEOF = false;
}
sendChangeMessage();
}
}
void AudioTransportSource::stop()
{
if (playing)
{
{
const ScopedLock sl (callbackLock);
playing = false;
}
int n = 500;
while (--n >= 0 && ! stopped)
Thread::sleep (2);
sendChangeMessage();
}
}
void AudioTransportSource::setPosition (double newPosition)
{
if (sampleRate > 0.0)
setNextReadPosition ((int64) (newPosition * sampleRate));
}
double AudioTransportSource::getCurrentPosition() const
{
if (sampleRate > 0.0)
return getNextReadPosition() / sampleRate;
return 0.0;
}
double AudioTransportSource::getLengthInSeconds() const
{
return getTotalLength() / sampleRate;
}
void AudioTransportSource::setNextReadPosition (int64 newPosition)
{
if (positionableSource != nullptr)
{
if (sampleRate > 0 && sourceSampleRate > 0)
newPosition = (int64) (newPosition * sourceSampleRate / sampleRate);
positionableSource->setNextReadPosition (newPosition);
}
}
int64 AudioTransportSource::getNextReadPosition() const
{
if (positionableSource != nullptr)
{
const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
return (int64) (positionableSource->getNextReadPosition() * ratio);
}
return 0;
}
int64 AudioTransportSource::getTotalLength() const
{
const ScopedLock sl (callbackLock);
if (positionableSource != nullptr)
{
const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
return (int64) (positionableSource->getTotalLength() * ratio);
}
return 0;
}
bool AudioTransportSource::isLooping() const
{
const ScopedLock sl (callbackLock);
return positionableSource != nullptr
&& positionableSource->isLooping();
}
void AudioTransportSource::setGain (const float newGain) noexcept
{
gain = newGain;
}
void AudioTransportSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate)
{
const ScopedLock sl (callbackLock);
sampleRate = newSampleRate;
blockSize = samplesPerBlockExpected;
if (masterSource != nullptr)
masterSource->prepareToPlay (samplesPerBlockExpected, sampleRate);
if (resamplerSource != nullptr && sourceSampleRate > 0)
resamplerSource->setResamplingRatio (sourceSampleRate / sampleRate);
isPrepared = true;
}
void AudioTransportSource::releaseMasterResources()
{
const ScopedLock sl (callbackLock);
if (masterSource != nullptr)
masterSource->releaseResources();
isPrepared = false;
}
void AudioTransportSource::releaseResources()
{
releaseMasterResources();
}
void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
{
const ScopedLock sl (callbackLock);
inputStreamEOF = false;
if (masterSource != nullptr && ! stopped)
{
masterSource->getNextAudioBlock (info);
if (! playing)
{
// just stopped playing, so fade out the last block..
for (int i = info.buffer->getNumChannels(); --i >= 0;)
info.buffer->applyGainRamp (i, info.startSample, jmin (256, info.numSamples), 1.0f, 0.0f);
if (info.numSamples > 256)
info.buffer->clear (info.startSample + 256, info.numSamples - 256);
}
if (positionableSource->getNextReadPosition() > positionableSource->getTotalLength() + 1
&& ! positionableSource->isLooping())
{
playing = false;
inputStreamEOF = true;
sendChangeMessage();
}
stopped = ! playing;
for (int i = info.buffer->getNumChannels(); --i >= 0;)
{
info.buffer->applyGainRamp (i, info.startSample, info.numSamples,
lastGain, gain);
}
}
else
{
info.clearActiveBufferRegion();
stopped = true;
}
lastGain = gain;
}

+ 186
- 0
source/modules/juce_audio_devices/sources/juce_AudioTransportSource.h View File

@@ -0,0 +1,186 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOTRANSPORTSOURCE_H_INCLUDED
#define JUCE_AUDIOTRANSPORTSOURCE_H_INCLUDED
//==============================================================================
/**
An AudioSource that takes a PositionableAudioSource and allows it to be
played, stopped, started, etc.
This can also be told use a buffer and background thread to read ahead, and
if can correct for different sample-rates.
You may want to use one of these along with an AudioSourcePlayer and AudioIODevice
to control playback of an audio file.
@see AudioSource, AudioSourcePlayer
*/
class JUCE_API AudioTransportSource : public PositionableAudioSource,
public ChangeBroadcaster
{
public:
//==============================================================================
/** Creates an AudioTransportSource.
After creating one of these, use the setSource() method to select an input source.
*/
AudioTransportSource();
/** Destructor. */
~AudioTransportSource();
//==============================================================================
/** Sets the reader that is being used as the input source.
This will stop playback, reset the position to 0 and change to the new reader.
The source passed in will not be deleted by this object, so must be managed by
the caller.
@param newSource the new input source to use. This may be zero
@param readAheadBufferSize a size of buffer to use for reading ahead. If this
is zero, no reading ahead will be done; if it's
greater than zero, a BufferingAudioSource will be used
to do the reading-ahead. If you set a non-zero value here,
you'll also need to set the readAheadThread parameter.
@param readAheadThread if you set readAheadBufferSize to a non-zero value, then
you'll also need to supply this TimeSliceThread object for
the background reader to use. The thread object must not be
deleted while the AudioTransport source is still using it.
@param sourceSampleRateToCorrectFor if this is non-zero, it specifies the sample
rate of the source, and playback will be sample-rate
adjusted to maintain playback at the correct pitch. If
this is 0, no sample-rate adjustment will be performed
@param maxNumChannels the maximum number of channels that may need to be played
*/
void setSource (PositionableAudioSource* newSource,
int readAheadBufferSize = 0,
TimeSliceThread* readAheadThread = nullptr,
double sourceSampleRateToCorrectFor = 0.0,
int maxNumChannels = 2);
//==============================================================================
/** Changes the current playback position in the source stream.
The next time the getNextAudioBlock() method is called, this
is the time from which it'll read data.
@see getPosition
*/
void setPosition (double newPosition);
/** Returns the position that the next data block will be read from
This is a time in seconds.
*/
double getCurrentPosition() const;
/** Returns the stream's length in seconds. */
double getLengthInSeconds() const;
/** Returns true if the player has stopped because its input stream ran out of data.
*/
bool hasStreamFinished() const noexcept { return inputStreamEOF; }
//==============================================================================
/** Starts playing (if a source has been selected).
If it starts playing, this will send a message to any ChangeListeners
that are registered with this object.
*/
void start();
/** Stops playing.
If it's actually playing, this will send a message to any ChangeListeners
that are registered with this object.
*/
void stop();
/** Returns true if it's currently playing. */
bool isPlaying() const noexcept { return playing; }
//==============================================================================
/** Changes the gain to apply to the output.
@param newGain a factor by which to multiply the outgoing samples,
so 1.0 = 0dB, 0.5 = -6dB, 2.0 = 6dB, etc.
*/
void setGain (float newGain) noexcept;
/** Returns the current gain setting.
@see setGain
*/
float getGain() const noexcept { return gain; }
//==============================================================================
/** Implementation of the AudioSource method. */
void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
/** Implementation of the AudioSource method. */
void releaseResources() override;
/** Implementation of the AudioSource method. */
void getNextAudioBlock (const AudioSourceChannelInfo&) override;
//==============================================================================
/** Implements the PositionableAudioSource method. */
void setNextReadPosition (int64 newPosition) override;
/** Implements the PositionableAudioSource method. */
int64 getNextReadPosition() const override;
/** Implements the PositionableAudioSource method. */
int64 getTotalLength() const override;
/** Implements the PositionableAudioSource method. */
bool isLooping() const override;
private:
//==============================================================================
PositionableAudioSource* source;
ResamplingAudioSource* resamplerSource;
BufferingAudioSource* bufferingSource;
PositionableAudioSource* positionableSource;
AudioSource* masterSource;
CriticalSection callbackLock;
float volatile gain, lastGain;
bool volatile playing, stopped;
double sampleRate, sourceSampleRate;
int blockSize, readAheadBufferSize;
bool isPrepared, inputStreamEOF;
void releaseMasterResources();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource)
};
#endif // JUCE_AUDIOTRANSPORTSOURCE_H_INCLUDED

+ 26
- 0
source/modules/juce_audio_formats.h View File

@@ -0,0 +1,26 @@
/*
* Carla Juce setup
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/

#ifndef CARLA_JUCE_AUDIO_FORMATS_H_INCLUDED
#define CARLA_JUCE_AUDIO_FORMATS_H_INCLUDED

#include "juce_audio_basics.h"

#include "juce_audio_formats/AppConfig.h"
#include "juce_audio_formats/juce_audio_formats.h"

#endif // CARLA_JUCE_AUDIO_FORMATS_H_INCLUDED

+ 53
- 0
source/modules/juce_audio_formats/AppConfig.h View File

@@ -0,0 +1,53 @@
/*
==============================================================================
Build options for juce_audio_formats static library
==============================================================================
*/
#ifndef CARLA_JUCE_AUDIO_FORMATS_APPCONFIG_H_INCLUDED
#define CARLA_JUCE_AUDIO_FORMATS_APPCONFIG_H_INCLUDED
#include "../juce_audio_basics/AppConfig.h"
//=============================================================================
/** Config: JUCE_USE_FLAC
Enables the FLAC audio codec classes (available on all platforms).
If your app doesn't need to read FLAC files, you might want to disable this to
reduce the size of your codebase and build time.
*/
#define JUCE_USE_FLAC 0
/** Config: JUCE_USE_OGGVORBIS
Enables the Ogg-Vorbis audio codec classes (available on all platforms).
If your app doesn't need to read Ogg-Vorbis files, you might want to disable this to
reduce the size of your codebase and build time.
*/
#define JUCE_USE_OGGVORBIS 0
/** Config: JUCE_USE_MP3AUDIOFORMAT
Enables the software-based MP3AudioFormat class.
IMPORTANT DISCLAIMER: By choosing to enable the JUCE_USE_MP3AUDIOFORMAT flag and to compile
this MP3 code into your software, you do so AT YOUR OWN RISK! By doing so, you are agreeing
that Raw Material Software is in no way responsible for any patent, copyright, or other
legal issues that you may suffer as a result.
The code in juce_MP3AudioFormat.cpp is NOT guaranteed to be free from infringements of 3rd-party
intellectual property. If you wish to use it, please seek your own independent advice about the
legality of doing so. If you are not willing to accept full responsibility for the consequences
of using this code, then do not enable this setting.
*/
#define JUCE_USE_MP3AUDIOFORMAT 0
/** Config: JUCE_USE_LAME_AUDIO_FORMAT
Enables the LameEncoderAudioFormat class.
*/
#define JUCE_USE_LAME_AUDIO_FORMAT 0
/** Config: JUCE_USE_WINDOWS_MEDIA_FORMAT
Enables the Windows Media SDK codecs.
*/
#define JUCE_USE_WINDOWS_MEDIA_FORMAT 0
#endif // CARLA_JUCE_AUDIO_FORMATS_APPCONFIG_H_INCLUDED

+ 88
- 0
source/modules/juce_audio_formats/Makefile View File

@@ -0,0 +1,88 @@
#!/usr/bin/make -f
# Makefile for juce_audio_formats #
# ------------------------------- #
# Created by falkTX
#

include ../../Makefile.mk

# --------------------------------------------------------------

BUILD_CXX_FLAGS += -I.

ifeq ($(MACOS),true)
BUILD_CXX_FLAGS += -objc++
OBJS = juce_audio_formats.mm.o
OBJS_posix32 = juce_audio_formats.mm.posix32.o
OBJS_posix64 = juce_audio_formats.mm.posix64.o
else
OBJS = juce_audio_formats.cpp.o
OBJS_posix32 = juce_audio_formats.cpp.posix32.o
OBJS_posix64 = juce_audio_formats.cpp.posix64.o
endif

OBJS_win32 = juce_audio_formats.cpp.win32.o
OBJS_win64 = juce_audio_formats.cpp.win64.o

# --------------------------------------------------------------

all: ../juce_audio_formats.a

posix32: ../juce_audio_formats.posix32.a
posix64: ../juce_audio_formats.posix64.a
win32: ../juce_audio_formats.win32.a
win64: ../juce_audio_formats.win64.a

# --------------------------------------------------------------

../juce_audio_formats.a: $(OBJS)
$(AR) rs $@ $^

../juce_audio_formats.posix32.a: $(OBJS_posix32)
$(AR) rs $@ $^

../juce_audio_formats.posix64.a: $(OBJS_posix64)
$(AR) rs $@ $^

../juce_audio_formats.win32.a: $(OBJS_win32)
$(AR) rs $@ $^

../juce_audio_formats.win64.a: $(OBJS_win64)
$(AR) rs $@ $^

../juce_audio_formats.dll: $(OBJS)
$(CXX) $^ -shared $(LINK_FLAGS) -o $@

../juce_audio_formats.dylib: $(OBJS)
$(CXX) $^ -dynamiclib $(LINK_FLAGS) -o $@

../juce_audio_formats.so: $(OBJS)
$(CXX) $^ -shared $(LINK_FLAGS) -o $@

# --------------------------------------------------------------

%.cpp.o: %.cpp
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

%.mm.o: %.mm
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

%.posix32.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@

%.posix64.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@

%.win32.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@

%.win64.o: %
$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@

# --------------------------------------------------------------

clean:
rm -f *.o ../juce_audio_formats*.a

debug:
$(MAKE) DEBUG=true

+ 49
- 0
source/modules/juce_audio_formats/codecs/flac/Flac Licence.txt View File

@@ -0,0 +1,49 @@

=====================================================================

I've incorporated FLAC directly into the Juce codebase because it makes
things much easier than having to make all your builds link correctly to
the appropriate libraries on every different platform.

I've made minimal changes to the FLAC code - just tweaked a few include paths
to make it build smoothly, added some headers to allow you to turn off FLAC
compilation, and commented-out a couple of unused bits of code.

=====================================================================


The following license is the BSD-style license that comes with the
Flac distribution, and which applies just to the files I've
included in this directory. For more info, and to get the rest of the
distribution, visit the Flac homepage: flac.sourceforge.net

=====================================================================

Copyright (C) 2000,2001,2002,2003,2004,2005,2006 Josh Coalson

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 402
- 0
source/modules/juce_audio_formats/codecs/flac/all.h View File

@@ -0,0 +1,402 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__ALL_H
#define FLAC__ALL_H
#include "export.h"
#include "assert.h"
#include "callback.h"
#include "format.h"
#include "metadata.h"
#include "ordinals.h"
#include "stream_decoder.h"
#include "stream_encoder.h"
#ifdef _MSC_VER
/* OPT: an MSVC built-in would be better */
static _inline FLAC__uint32 local_swap32_(FLAC__uint32 x)
{
x = ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF);
return (x>>16) | (x<<16);
}
#endif
#if defined(_MSC_VER) && defined(_X86_)
/* OPT: an MSVC built-in would be better */
static void local_swap32_block_(FLAC__uint32 *start, FLAC__uint32 len)
{
__asm {
mov edx, start
mov ecx, len
test ecx, ecx
loop1:
jz done1
mov eax, [edx]
bswap eax
mov [edx], eax
add edx, 4
dec ecx
jmp short loop1
done1:
}
}
#endif
/** \mainpage
*
* \section intro Introduction
*
* This is the documentation for the FLAC C and C++ APIs. It is
* highly interconnected; this introduction should give you a top
* level idea of the structure and how to find the information you
* need. As a prerequisite you should have at least a basic
* knowledge of the FLAC format, documented
* <A HREF="../format.html">here</A>.
*
* \section c_api FLAC C API
*
* The FLAC C API is the interface to libFLAC, a set of structures
* describing the components of FLAC streams, and functions for
* encoding and decoding streams, as well as manipulating FLAC
* metadata in files. The public include files will be installed
* in your include area (for example /usr/include/FLAC/...).
*
* By writing a little code and linking against libFLAC, it is
* relatively easy to add FLAC support to another program. The
* library is licensed under <A HREF="../license.html">Xiph's BSD license</A>.
* Complete source code of libFLAC as well as the command-line
* encoder and plugins is available and is a useful source of
* examples.
*
* Aside from encoders and decoders, libFLAC provides a powerful
* metadata interface for manipulating metadata in FLAC files. It
* allows the user to add, delete, and modify FLAC metadata blocks
* and it can automatically take advantage of PADDING blocks to avoid
* rewriting the entire FLAC file when changing the size of the
* metadata.
*
* libFLAC usually only requires the standard C library and C math
* library. In particular, threading is not used so there is no
* dependency on a thread library. However, libFLAC does not use
* global variables and should be thread-safe.
*
* libFLAC also supports encoding to and decoding from Ogg FLAC.
* However the metadata editing interfaces currently have limited
* read-only support for Ogg FLAC files.
*
* \section cpp_api FLAC C++ API
*
* The FLAC C++ API is a set of classes that encapsulate the
* structures and functions in libFLAC. They provide slightly more
* functionality with respect to metadata but are otherwise
* equivalent. For the most part, they share the same usage as
* their counterparts in libFLAC, and the FLAC C API documentation
* can be used as a supplement. The public include files
* for the C++ API will be installed in your include area (for
* example /usr/include/FLAC++/...).
*
* libFLAC++ is also licensed under
* <A HREF="../license.html">Xiph's BSD license</A>.
*
* \section getting_started Getting Started
*
* A good starting point for learning the API is to browse through
* the <A HREF="modules.html">modules</A>. Modules are logical
* groupings of related functions or classes, which correspond roughly
* to header files or sections of header files. Each module includes a
* detailed description of the general usage of its functions or
* classes.
*
* From there you can go on to look at the documentation of
* individual functions. You can see different views of the individual
* functions through the links in top bar across this page.
*
* If you prefer a more hands-on approach, you can jump right to some
* <A HREF="../documentation_example_code.html">example code</A>.
*
* \section porting_guide Porting Guide
*
* Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink
* has been introduced which gives detailed instructions on how to
* port your code to newer versions of FLAC.
*
* \section embedded_developers Embedded Developers
*
* libFLAC has grown larger over time as more functionality has been
* included, but much of it may be unnecessary for a particular embedded
* implementation. Unused parts may be pruned by some simple editing of
* src/libFLAC/Makefile.am. In general, the decoders, encoders, and
* metadata interface are all independent from each other.
*
* It is easiest to just describe the dependencies:
*
* - All modules depend on the \link flac_format Format \endlink module.
* - The decoders and encoders depend on the bitbuffer.
* - The decoder is independent of the encoder. The encoder uses the
* decoder because of the verify feature, but this can be removed if
* not needed.
* - Parts of the metadata interface require the stream decoder (but not
* the encoder).
* - Ogg support is selectable through the compile time macro
* \c FLAC__HAS_OGG.
*
* For example, if your application only requires the stream decoder, no
* encoder, and no metadata interface, you can remove the stream encoder
* and the metadata interface, which will greatly reduce the size of the
* library.
*
* Also, there are several places in the libFLAC code with comments marked
* with "OPT:" where a #define can be changed to enable code that might be
* faster on a specific platform. Experimenting with these can yield faster
* binaries.
*/
/** \defgroup porting Porting Guide for New Versions
*
* This module describes differences in the library interfaces from
* version to version. It assists in the porting of code that uses
* the libraries to newer versions of FLAC.
*
* One simple facility for making porting easier that has been added
* in FLAC 1.1.3 is a set of \c #defines in \c export.h of each
* library's includes (e.g. \c include/FLAC/export.h). The
* \c #defines mirror the libraries'
* <A HREF="http://www.gnu.org/software/libtool/manual.html#Libtool-versioning">libtool version numbers</A>,
* e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT,
* \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE.
* These can be used to support multiple versions of an API during the
* transition phase, e.g.
*
* \code
* #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
* legacy code
* #else
* new code
* #endif
* \endcode
*
* The the source will work for multiple versions and the legacy code can
* easily be removed when the transition is complete.
*
* Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in
* include/FLAC/export.h), which can be used to determine whether or not
* the library has been compiled with support for Ogg FLAC. This is
* simpler than trying to call an Ogg init function and catching the
* error.
*/
/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3
* \ingroup porting
*
* \brief
* This module describes porting from FLAC 1.1.2 to FLAC 1.1.3.
*
* The main change between the APIs in 1.1.2 and 1.1.3 is that they have
* been simplified. First, libOggFLAC has been merged into libFLAC and
* libOggFLAC++ has been merged into libFLAC++. Second, both the three
* decoding layers and three encoding layers have been merged into a
* single stream decoder and stream encoder. That is, the functionality
* of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged
* into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and
* FLAC__FileEncoder into FLAC__StreamEncoder. Only the
* FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means
* is there is now a single API that can be used to encode or decode
* streams to/from native FLAC or Ogg FLAC and the single API can work
* on both seekable and non-seekable streams.
*
* Instead of creating an encoder or decoder of a certain layer, now the
* client will always create a FLAC__StreamEncoder or
* FLAC__StreamDecoder. The old layers are now differentiated by the
* initialization function. For example, for the decoder,
* FLAC__stream_decoder_init() has been replaced by
* FLAC__stream_decoder_init_stream(). This init function takes
* callbacks for the I/O, and the seeking callbacks are optional. This
* allows the client to use the same object for seekable and
* non-seekable streams. For decoding a FLAC file directly, the client
* can use FLAC__stream_decoder_init_file() and pass just a filename
* and fewer callbacks; most of the other callbacks are supplied
* internally. For situations where fopen()ing by filename is not
* possible (e.g. Unicode filenames on Windows) the client can instead
* open the file itself and supply the FILE* to
* FLAC__stream_decoder_init_FILE(). The init functions now returns a
* FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState.
* Since the callbacks and client data are now passed to the init
* function, the FLAC__stream_decoder_set_*_callback() functions and
* FLAC__stream_decoder_set_client_data() are no longer needed. The
* rest of the calls to the decoder are the same as before.
*
* There are counterpart init functions for Ogg FLAC, e.g.
* FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls
* and callbacks are the same as for native FLAC.
*
* As an example, in FLAC 1.1.2 a seekable stream decoder would have
* been set up like so:
*
* \code
* FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new();
* if(decoder == NULL) do_something;
* FLAC__seekable_stream_decoder_set_md5_checking(decoder, true);
* [... other settings ...]
* FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback);
* FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback);
* FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback);
* FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback);
* FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback);
* FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback);
* FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback);
* FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback);
* FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data);
* if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something;
* \endcode
*
* In FLAC 1.1.3 it is like this:
*
* \code
* FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
* if(decoder == NULL) do_something;
* FLAC__stream_decoder_set_md5_checking(decoder, true);
* [... other settings ...]
* if(FLAC__stream_decoder_init_stream(
* decoder,
* my_read_callback,
* my_seek_callback, // or NULL
* my_tell_callback, // or NULL
* my_length_callback, // or NULL
* my_eof_callback, // or NULL
* my_write_callback,
* my_metadata_callback, // or NULL
* my_error_callback,
* my_client_data
* ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
* \endcode
*
* or you could do;
*
* \code
* [...]
* FILE *file = fopen("somefile.flac","rb");
* if(file == NULL) do_somthing;
* if(FLAC__stream_decoder_init_FILE(
* decoder,
* file,
* my_write_callback,
* my_metadata_callback, // or NULL
* my_error_callback,
* my_client_data
* ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
* \endcode
*
* or just:
*
* \code
* [...]
* if(FLAC__stream_decoder_init_file(
* decoder,
* "somefile.flac",
* my_write_callback,
* my_metadata_callback, // or NULL
* my_error_callback,
* my_client_data
* ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
* \endcode
*
* Another small change to the decoder is in how it handles unparseable
* streams. Before, when the decoder found an unparseable stream
* (reserved for when the decoder encounters a stream from a future
* encoder that it can't parse), it changed the state to
* \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. Now the decoder instead
* drops sync and calls the error callback with a new error code
* \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM. This is
* more robust. If your error callback does not discriminate on the the
* error state, your code does not need to be changed.
*
* The encoder now has a new setting:
* FLAC__stream_encoder_set_apodization(). This is for setting the
* method used to window the data before LPC analysis. You only need to
* add a call to this function if the default is not suitable. There
* are also two new convenience functions that may be useful:
* FLAC__metadata_object_cuesheet_calculate_cddb_id() and
* FLAC__metadata_get_cuesheet().
*
* The \a bytes parameter to FLAC__StreamDecoderReadCallback,
* FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback
* is now \c size_t instead of \c unsigned.
*/
/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4
* \ingroup porting
*
* \brief
* This module describes porting from FLAC 1.1.3 to FLAC 1.1.4.
*
* There were no changes to any of the interfaces from 1.1.3 to 1.1.4.
* There was a slight change in the implementation of
* FLAC__stream_encoder_set_metadata(); the function now makes a copy
* of the \a metadata array of pointers so the client no longer needs
* to maintain it after the call. The objects themselves that are
* pointed to by the array are still not copied though and must be
* maintained until the call to FLAC__stream_encoder_finish().
*/
/** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0
* \ingroup porting
*
* \brief
* This module describes porting from FLAC 1.1.4 to FLAC 1.2.0.
*
* There were only very minor changes to the interfaces from 1.1.4 to 1.2.0.
* In libFLAC, \c FLAC__format_sample_rate_is_subset() was added.
* In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added.
*
* Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN
* has changed to reflect the conversion of one of the reserved bits
* into active use. It used to be \c 2 and now is \c 1. However the
* FLAC frame header length has not changed, so to skip the proper
* number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN +
* \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN
*/
/** \defgroup flac FLAC C API
*
* The FLAC C API is the interface to libFLAC, a set of structures
* describing the components of FLAC streams, and functions for
* encoding and decoding streams, as well as manipulating FLAC
* metadata in files.
*
* You should start with the format components as all other modules
* are dependent on it.
*/
#endif

+ 212
- 0
source/modules/juce_audio_formats/codecs/flac/alloc.h View File

@@ -0,0 +1,212 @@
/* alloc - Convenience routines for safely allocating memory
* Copyright (C) 2007 Josh Coalson
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FLAC__SHARE__ALLOC_H
#define FLAC__SHARE__ALLOC_H
#if HAVE_CONFIG_H
# include <config.h>
#endif
/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early
* before #including this file, otherwise SIZE_MAX might not be defined
*/
#include <limits.h> /* for SIZE_MAX */
#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */
#endif
#include <stdlib.h> /* for size_t, malloc(), etc */
#ifndef SIZE_MAX
# ifndef SIZE_T_MAX
# ifdef _MSC_VER
# define SIZE_T_MAX UINT_MAX
# else
# error
# endif
# endif
# define SIZE_MAX SIZE_T_MAX
#endif
#ifndef FLaC__INLINE
#define FLaC__INLINE
#endif
/* avoid malloc()ing 0 bytes, see:
* https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
*/
static FLaC__INLINE void *safe_malloc_(size_t size)
{
/* malloc(0) is undefined; FLAC src convention is to always allocate */
if(!size)
size++;
return malloc(size);
}
static FLaC__INLINE void *safe_calloc_(size_t nmemb, size_t size)
{
if(!nmemb || !size)
return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
return calloc(nmemb, size);
}
/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */
static FLaC__INLINE void *safe_malloc_add_2op_(size_t size1, size_t size2)
{
size2 += size1;
if(size2 < size1)
return 0;
return safe_malloc_(size2);
}
static FLaC__INLINE void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
return safe_malloc_(size3);
}
static FLaC__INLINE void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
size4 += size3;
if(size4 < size3)
return 0;
return safe_malloc_(size4);
}
static FLaC__INLINE void *safe_malloc_mul_2op_(size_t size1, size_t size2)
#if 0
needs support for cases where sizeof(size_t) != 4
{
/* could be faster #ifdef'ing off SIZEOF_SIZE_T */
if(sizeof(size_t) == 4) {
if ((double)size1 * (double)size2 < 4294967296.0)
return malloc(size1*size2);
}
return 0;
}
#else
/* better? */
{
if(!size1 || !size2)
return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
if(size1 > SIZE_MAX / size2)
return 0;
return malloc(size1*size2);
}
#endif
static FLaC__INLINE void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
{
if(!size1 || !size2 || !size3)
return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
if(size1 > SIZE_MAX / size2)
return 0;
size1 *= size2;
if(size1 > SIZE_MAX / size3)
return 0;
return malloc(size1*size3);
}
/* size1*size2 + size3 */
static FLaC__INLINE void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
{
if(!size1 || !size2)
return safe_malloc_(size3);
if(size1 > SIZE_MAX / size2)
return 0;
return safe_malloc_add_2op_(size1*size2, size3);
}
/* size1 * (size2 + size3) */
static FLaC__INLINE void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
{
if(!size1 || (!size2 && !size3))
return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
size2 += size3;
if(size2 < size3)
return 0;
return safe_malloc_mul_2op_(size1, size2);
}
static FLaC__INLINE void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2)
{
size2 += size1;
if(size2 < size1)
return 0;
return realloc(ptr, size2);
}
static FLaC__INLINE void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
return realloc(ptr, size3);
}
static FLaC__INLINE void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
size4 += size3;
if(size4 < size3)
return 0;
return realloc(ptr, size4);
}
static FLaC__INLINE void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
{
if(!size1 || !size2)
return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
if(size1 > SIZE_MAX / size2)
return 0;
return realloc(ptr, size1*size2);
}
/* size1 * (size2 + size3) */
static FLaC__INLINE void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
{
if(!size1 || (!size2 && !size3))
return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
size2 += size3;
if(size2 < size3)
return 0;
return safe_realloc_mul_2op_(ptr, size1, size2);
}
#endif

+ 45
- 0
source/modules/juce_audio_formats/codecs/flac/assert.h View File

@@ -0,0 +1,45 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__ASSERT_H
#define FLAC__ASSERT_H
/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */
#ifdef DEBUG
#include <assert.h>
#define FLAC__ASSERT(x) assert(x)
#define FLAC__ASSERT_DECLARATION(x) x
#else
#define FLAC__ASSERT(x)
#define FLAC__ASSERT_DECLARATION(x)
#endif
#endif

+ 184
- 0
source/modules/juce_audio_formats/codecs/flac/callback.h View File

@@ -0,0 +1,184 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__CALLBACK_H
#define FLAC__CALLBACK_H
#include "ordinals.h"
#include <stdlib.h> /* for size_t */
/** \file include/FLAC/callback.h
*
* \brief
* This module defines the structures for describing I/O callbacks
* to the other FLAC interfaces.
*
* See the detailed documentation for callbacks in the
* \link flac_callbacks callbacks \endlink module.
*/
/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures
* \ingroup flac
*
* \brief
* This module defines the structures for describing I/O callbacks
* to the other FLAC interfaces.
*
* The purpose of the I/O callback functions is to create a common way
* for the metadata interfaces to handle I/O.
*
* Originally the metadata interfaces required filenames as the way of
* specifying FLAC files to operate on. This is problematic in some
* environments so there is an additional option to specify a set of
* callbacks for doing I/O on the FLAC file, instead of the filename.
*
* In addition to the callbacks, a FLAC__IOHandle type is defined as an
* opaque structure for a data source.
*
* The callback function prototypes are similar (but not identical) to the
* stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use
* stdio streams to implement the callbacks, you can pass fread, fwrite, and
* fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or
* FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle
* is required. \warning You generally CANNOT directly use fseek or ftell
* for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems
* these use 32-bit offsets and FLAC requires 64-bit offsets to deal with
* large files. You will have to find an equivalent function (e.g. ftello),
* or write a wrapper. The same is true for feof() since this is usually
* implemented as a macro, not as a function whose address can be taken.
*
* \{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** This is the opaque handle type used by the callbacks. Typically
* this is a \c FILE* or address of a file descriptor.
*/
typedef void* FLAC__IOHandle;
/** Signature for the read callback.
* The signature and semantics match POSIX fread() implementations
* and can generally be used interchangeably.
*
* \param ptr The address of the read buffer.
* \param size The size of the records to be read.
* \param nmemb The number of records to be read.
* \param handle The handle to the data source.
* \retval size_t
* The number of records read.
*/
typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
/** Signature for the write callback.
* The signature and semantics match POSIX fwrite() implementations
* and can generally be used interchangeably.
*
* \param ptr The address of the write buffer.
* \param size The size of the records to be written.
* \param nmemb The number of records to be written.
* \param handle The handle to the data source.
* \retval size_t
* The number of records written.
*/
typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
/** Signature for the seek callback.
* The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT
* EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long'
* and 32-bits wide.
*
* \param handle The handle to the data source.
* \param offset The new position, relative to \a whence
* \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END
* \retval int
* \c 0 on success, \c -1 on error.
*/
typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence);
/** Signature for the tell callback.
* The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT
* EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long'
* and 32-bits wide.
*
* \param handle The handle to the data source.
* \retval FLAC__int64
* The current position on success, \c -1 on error.
*/
typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle);
/** Signature for the EOF callback.
* The signature and semantics mostly match POSIX feof() but WATCHOUT:
* on many systems, feof() is a macro, so in this case a wrapper function
* must be provided instead.
*
* \param handle The handle to the data source.
* \retval int
* \c 0 if not at end of file, nonzero if at end of file.
*/
typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle);
/** Signature for the close callback.
* The signature and semantics match POSIX fclose() implementations
* and can generally be used interchangeably.
*
* \param handle The handle to the data source.
* \retval int
* \c 0 on success, \c EOF on error.
*/
typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
/** A structure for holding a set of callbacks.
* Each FLAC interface that requires a FLAC__IOCallbacks structure will
* describe which of the callbacks are required. The ones that are not
* required may be set to NULL.
*
* If the seek requirement for an interface is optional, you can signify that
* a data sorce is not seekable by setting the \a seek field to \c NULL.
*/
typedef struct {
FLAC__IOCallback_Read read;
FLAC__IOCallback_Write write;
FLAC__IOCallback_Seek seek;
FLAC__IOCallback_Tell tell;
FLAC__IOCallback_Eof eof;
FLAC__IOCallback_Close close;
} FLAC__IOCallbacks;
/* \} */
#ifdef __cplusplus
}
#endif
#endif

+ 91
- 0
source/modules/juce_audio_formats/codecs/flac/export.h View File

@@ -0,0 +1,91 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__EXPORT_H
#define FLAC__EXPORT_H
/** \file include/FLAC/export.h
*
* \brief
* This module contains #defines and symbols for exporting function
* calls, and providing version information and compiled-in features.
*
* See the \link flac_export export \endlink module.
*/
/** \defgroup flac_export FLAC/export.h: export symbols
* \ingroup flac
*
* \brief
* This module contains #defines and symbols for exporting function
* calls, and providing version information and compiled-in features.
*
* If you are compiling with MSVC and will link to the static library
* (libFLAC.lib) you should define FLAC__NO_DLL in your project to
* make sure the symbols are exported properly.
*
* \{
*/
#if defined(FLAC__NO_DLL) || !defined(_MSC_VER)
#define FLAC_API
#else
#ifdef FLAC_API_EXPORTS
#define FLAC_API _declspec(dllexport)
#else
#define FLAC_API _declspec(dllimport)
#endif
#endif
/** These #defines will mirror the libtool-based library version number, see
* http://www.gnu.org/software/libtool/manual.html#Libtool-versioning
*/
#define FLAC_API_VERSION_CURRENT 10
#define FLAC_API_VERSION_REVISION 0 /**< see above */
#define FLAC_API_VERSION_AGE 2 /**< see above */
#ifdef __cplusplus
extern "C" {
#endif
/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */
extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC;
#ifdef __cplusplus
}
#endif
/* \} */
#endif

+ 1010
- 0
source/modules/juce_audio_formats/codecs/flac/format.h
File diff suppressed because it is too large
View File


+ 149
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/bitmath.c View File

@@ -0,0 +1,149 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "include/private/bitmath.h"
#include "../assert.h"
/* An example of what FLAC__bitmath_ilog2() computes:
*
* ilog2( 0) = assertion failure
* ilog2( 1) = 0
* ilog2( 2) = 1
* ilog2( 3) = 1
* ilog2( 4) = 2
* ilog2( 5) = 2
* ilog2( 6) = 2
* ilog2( 7) = 2
* ilog2( 8) = 3
* ilog2( 9) = 3
* ilog2(10) = 3
* ilog2(11) = 3
* ilog2(12) = 3
* ilog2(13) = 3
* ilog2(14) = 3
* ilog2(15) = 3
* ilog2(16) = 4
* ilog2(17) = 4
* ilog2(18) = 4
*/
unsigned FLAC__bitmath_ilog2(FLAC__uint32 v)
{
unsigned l = 0;
FLAC__ASSERT(v > 0);
while(v >>= 1)
l++;
return l;
}
unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
{
unsigned l = 0;
FLAC__ASSERT(v > 0);
while(v >>= 1)
l++;
return l;
}
/* An example of what FLAC__bitmath_silog2() computes:
*
* silog2(-10) = 5
* silog2(- 9) = 5
* silog2(- 8) = 4
* silog2(- 7) = 4
* silog2(- 6) = 4
* silog2(- 5) = 4
* silog2(- 4) = 3
* silog2(- 3) = 3
* silog2(- 2) = 2
* silog2(- 1) = 2
* silog2( 0) = 0
* silog2( 1) = 2
* silog2( 2) = 3
* silog2( 3) = 3
* silog2( 4) = 4
* silog2( 5) = 4
* silog2( 6) = 4
* silog2( 7) = 4
* silog2( 8) = 5
* silog2( 9) = 5
* silog2( 10) = 5
*/
unsigned FLAC__bitmath_silog2(int v)
{
while(1) {
if(v == 0) {
return 0;
}
else if(v > 0) {
unsigned l = 0;
while(v) {
l++;
v >>= 1;
}
return l+1;
}
else if(v == -1) {
return 2;
}
else {
v++;
v = -v;
}
}
}
unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v)
{
while(1) {
if(v == 0) {
return 0;
}
else if(v > 0) {
unsigned l = 0;
while(v) {
l++;
v >>= 1;
}
return l+1;
}
else if(v == -1) {
return 2;
}
else {
v++;
v = -v;
}
}
}

+ 1350
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/bitreader.c
File diff suppressed because it is too large
View File


+ 880
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/bitwriter.c View File

@@ -0,0 +1,880 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h> /* for malloc() */
#include <string.h> /* for memcpy(), memset() */
#ifdef _MSC_VER
#include <winsock.h> /* for ntohl() */
#elif defined FLAC__SYS_DARWIN
#include <machine/endian.h> /* for ntohl() */
#elif defined __MINGW32__
#include <winsock.h> /* for ntohl() */
#else
#include <netinet/in.h> /* for ntohl() */
#endif
#if 0 /* UNUSED */
#include "include/private/bitmath.h"
#endif
#include "include/private/bitwriter.h"
#include "include/private/crc.h"
#include "../assert.h"
#include "../alloc.h"
/* Things should be fastest when this matches the machine word size */
/* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */
/* WATCHOUT: there are a few places where the code will not work unless bwword is >= 32 bits wide */
typedef FLAC__uint32 bwword;
#define FLAC__BYTES_PER_WORD 4
#define FLAC__BITS_PER_WORD 32
#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */
#if WORDS_BIGENDIAN
#define SWAP_BE_WORD_TO_HOST(x) (x)
#else
#ifdef _MSC_VER
#define SWAP_BE_WORD_TO_HOST(x) local_swap32_(x)
#else
#define SWAP_BE_WORD_TO_HOST(x) ntohl(x)
#endif
#endif
/*
* The default capacity here doesn't matter too much. The buffer always grows
* to hold whatever is written to it. Usually the encoder will stop adding at
* a frame or metadata block, then write that out and clear the buffer for the
* next one.
*/
static const unsigned FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */
/* When growing, increment 4K at a time */
static const unsigned FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* size in words */
#define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD)
#define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits)
#ifdef min
#undef min
#endif
#define min(x,y) ((x)<(y)?(x):(y))
/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
#ifdef _MSC_VER
#define FLAC__U64L(x) x
#else
#define FLAC__U64L(x) x##LLU
#endif
#ifndef FLaC__INLINE
#define FLaC__INLINE
#endif
struct FLAC__BitWriter {
bwword *buffer;
bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
unsigned capacity; /* capacity of buffer in words */
unsigned words; /* # of complete words in buffer */
unsigned bits; /* # of used bits in accum */
};
/* * WATCHOUT: The current implementation only grows the buffer. */
static FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, unsigned bits_to_add)
{
unsigned new_capacity;
bwword *new_buffer;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
/* calculate total words needed to store 'bits_to_add' additional bits */
new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD);
/* it's possible (due to pessimism in the growth estimation that
* leads to this call) that we don't actually need to grow
*/
if(bw->capacity >= new_capacity)
return true;
/* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */
if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT)
new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
/* make sure we got everything right */
FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
FLAC__ASSERT(new_capacity > bw->capacity);
FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD));
new_buffer = (bwword*)safe_realloc_mul_2op_(bw->buffer, sizeof(bwword), /*times*/new_capacity);
if(new_buffer == 0)
return false;
bw->buffer = new_buffer;
bw->capacity = new_capacity;
return true;
}
/***********************************************************************
*
* Class constructor/destructor
*
***********************************************************************/
FLAC__BitWriter *FLAC__bitwriter_new(void)
{
FLAC__BitWriter *bw = (FLAC__BitWriter*)calloc(1, sizeof(FLAC__BitWriter));
/* note that calloc() sets all members to 0 for us */
return bw;
}
void FLAC__bitwriter_delete(FLAC__BitWriter *bw)
{
FLAC__ASSERT(0 != bw);
FLAC__bitwriter_free(bw);
free(bw);
}
/***********************************************************************
*
* Public class methods
*
***********************************************************************/
FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw)
{
FLAC__ASSERT(0 != bw);
bw->words = bw->bits = 0;
bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY;
bw->buffer = (bwword*)malloc(sizeof(bwword) * bw->capacity);
if(bw->buffer == 0)
return false;
return true;
}
void FLAC__bitwriter_free(FLAC__BitWriter *bw)
{
FLAC__ASSERT(0 != bw);
if(0 != bw->buffer)
free(bw->buffer);
bw->buffer = 0;
bw->capacity = 0;
bw->words = bw->bits = 0;
}
void FLAC__bitwriter_clear(FLAC__BitWriter *bw)
{
bw->words = bw->bits = 0;
}
void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out)
{
unsigned i, j;
if(bw == 0) {
fprintf(out, "bitwriter is NULL\n");
}
else {
fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, FLAC__TOTAL_BITS(bw));
for(i = 0; i < bw->words; i++) {
fprintf(out, "%08X: ", i);
for(j = 0; j < FLAC__BITS_PER_WORD; j++)
fprintf(out, "%01u", bw->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
fprintf(out, "\n");
}
if(bw->bits > 0) {
fprintf(out, "%08X: ", i);
for(j = 0; j < bw->bits; j++)
fprintf(out, "%01u", bw->accum & (1 << (bw->bits-j-1)) ? 1:0);
fprintf(out, "\n");
}
}
}
FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc)
{
const FLAC__byte *buffer;
size_t bytes;
FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
return false;
*crc = (FLAC__uint16)FLAC__crc16(buffer, bytes);
FLAC__bitwriter_release_buffer(bw);
return true;
}
FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc)
{
const FLAC__byte *buffer;
size_t bytes;
FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
return false;
*crc = FLAC__crc8(buffer, bytes);
FLAC__bitwriter_release_buffer(bw);
return true;
}
FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw)
{
return ((bw->bits & 7) == 0);
}
unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw)
{
return FLAC__TOTAL_BITS(bw);
}
FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes)
{
FLAC__ASSERT((bw->bits & 7) == 0);
/* double protection */
if(bw->bits & 7)
return false;
/* if we have bits in the accumulator we have to flush those to the buffer first */
if(bw->bits) {
FLAC__ASSERT(bw->words <= bw->capacity);
if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD))
return false;
/* append bits as complete word to buffer, but don't change bw->accum or bw->bits */
bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits));
}
/* now we can just return what we have */
*buffer = (FLAC__byte*)bw->buffer;
*bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3);
return true;
}
void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw)
{
/* nothing to do. in the future, strict checking of a 'writer-is-in-
* get-mode' flag could be added everywhere and then cleared here
*/
(void)bw;
}
FLaC__INLINE FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits)
{
unsigned n;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
if(bits == 0)
return true;
/* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
return false;
/* first part gets to word alignment */
if(bw->bits) {
n = min(FLAC__BITS_PER_WORD - bw->bits, bits);
bw->accum <<= n;
bits -= n;
bw->bits += n;
if(bw->bits == FLAC__BITS_PER_WORD) {
bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
bw->bits = 0;
}
else
return true;
}
/* do whole words */
while(bits >= FLAC__BITS_PER_WORD) {
bw->buffer[bw->words++] = 0;
bits -= FLAC__BITS_PER_WORD;
}
/* do any leftovers */
if(bits > 0) {
bw->accum = 0;
bw->bits = bits;
}
return true;
}
FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits)
{
register unsigned left;
/* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
FLAC__ASSERT(bits <= 32);
if(bits == 0)
return true;
/* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
return false;
left = FLAC__BITS_PER_WORD - bw->bits;
if(bits < left) {
bw->accum <<= bits;
bw->accum |= val;
bw->bits += bits;
}
else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */
bw->accum <<= left;
bw->accum |= val >> (bw->bits = bits - left);
bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
bw->accum = val;
}
else {
bw->accum = val;
bw->bits = 0;
bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(val);
}
return true;
}
FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits)
{
/* zero-out unused bits */
if(bits < 32)
val &= (~(0xffffffff << bits));
return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
}
FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits)
{
/* this could be a little faster but it's not used for much */
if(bits > 32) {
return
FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) &&
FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 32);
}
else
return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
}
FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val)
{
/* this doesn't need to be that fast as currently it is only used for vorbis comments */
if(!FLAC__bitwriter_write_raw_uint32(bw, val & 0xff, 8))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>8) & 0xff, 8))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>16) & 0xff, 8))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, val>>24, 8))
return false;
return true;
}
FLaC__INLINE FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals)
{
unsigned i;
/* this could be faster but currently we don't need it to be since it's only used for writing metadata */
for(i = 0; i < nvals; i++) {
if(!FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(vals[i]), 8))
return false;
}
return true;
}
FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val)
{
if(val < 32)
return FLAC__bitwriter_write_raw_uint32(bw, 1, ++val);
else
return
FLAC__bitwriter_write_zeroes(bw, val) &&
FLAC__bitwriter_write_raw_uint32(bw, 1, 1);
}
unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter)
{
FLAC__uint32 uval;
FLAC__ASSERT(parameter < sizeof(unsigned)*8);
/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
uval = (val<<1) ^ (val>>31);
return 1 + parameter + (uval >> parameter);
}
#if 0 /* UNUSED */
unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter)
{
unsigned bits, msbs, uval;
unsigned k;
FLAC__ASSERT(parameter > 0);
/* fold signed to unsigned */
if(val < 0)
uval = (unsigned)(((-(++val)) << 1) + 1);
else
uval = (unsigned)(val << 1);
k = FLAC__bitmath_ilog2(parameter);
if(parameter == 1u<<k) {
FLAC__ASSERT(k <= 30);
msbs = uval >> k;
bits = 1 + k + msbs;
}
else {
unsigned q, r, d;
d = (1 << (k+1)) - parameter;
q = uval / parameter;
r = uval - (q * parameter);
bits = 1 + q + k;
if(r >= d)
bits++;
}
return bits;
}
unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned uval, unsigned parameter)
{
unsigned bits, msbs;
unsigned k;
FLAC__ASSERT(parameter > 0);
k = FLAC__bitmath_ilog2(parameter);
if(parameter == 1u<<k) {
FLAC__ASSERT(k <= 30);
msbs = uval >> k;
bits = 1 + k + msbs;
}
else {
unsigned q, r, d;
d = (1 << (k+1)) - parameter;
q = uval / parameter;
r = uval - (q * parameter);
bits = 1 + q + k;
if(r >= d)
bits++;
}
return bits;
}
#endif /* UNUSED */
FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter)
{
unsigned total_bits, interesting_bits, msbs;
FLAC__uint32 uval, pattern;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
FLAC__ASSERT(parameter < 8*sizeof(uval));
/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
uval = (val<<1) ^ (val>>31);
msbs = uval >> parameter;
interesting_bits = 1 + parameter;
total_bits = interesting_bits + msbs;
pattern = 1 << parameter; /* the unary end bit */
pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */
if(total_bits <= 32)
return FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits);
else
return
FLAC__bitwriter_write_zeroes(bw, msbs) && /* write the unary MSBs */
FLAC__bitwriter_write_raw_uint32(bw, pattern, interesting_bits); /* write the unary end bit and binary LSBs */
}
FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter)
{
const FLAC__uint32 mask1 = FLAC__WORD_ALL_ONES << parameter; /* we val|=mask1 to set the stop bit above it... */
const FLAC__uint32 mask2 = FLAC__WORD_ALL_ONES >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2*/
FLAC__uint32 uval;
unsigned left;
const unsigned lsbits = 1 + parameter;
unsigned msbits;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
FLAC__ASSERT(parameter < 8*sizeof(bwword)-1);
/* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
while(nvals) {
/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
uval = (*vals<<1) ^ (*vals>>31);
msbits = uval >> parameter;
#if 0 /* OPT: can remove this special case if it doesn't make up for the extra compare (doesn't make a statistically significant difference with msvc or gcc/x86) */
if(bw->bits && bw->bits + msbits + lsbits <= FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
/* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */
bw->bits = bw->bits + msbits + lsbits;
uval |= mask1; /* set stop bit */
uval &= mask2; /* mask off unused top bits */
/* NOT: bw->accum <<= msbits + lsbits because msbits+lsbits could be 32, then the shift would be a NOP */
bw->accum <<= msbits;
bw->accum <<= lsbits;
bw->accum |= uval;
if(bw->bits == FLAC__BITS_PER_WORD) {
bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
bw->bits = 0;
/* burying the capacity check down here means we have to grow the buffer a little if there are more vals to do */
if(bw->capacity <= bw->words && nvals > 1 && !bitwriter_grow_(bw, 1)) {
FLAC__ASSERT(bw->capacity == bw->words);
return false;
}
}
}
else {
#elif 1 /*@@@@@@ OPT: try this version with MSVC6 to see if better, not much difference for gcc-4 */
if(bw->bits && bw->bits + msbits + lsbits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
/* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */
bw->bits = bw->bits + msbits + lsbits;
uval |= mask1; /* set stop bit */
uval &= mask2; /* mask off unused top bits */
bw->accum <<= msbits + lsbits;
bw->accum |= uval;
}
else {
#endif
/* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
/* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */
if(bw->capacity <= bw->words + bw->bits + msbits + 1/*lsbits always fit in 1 bwword*/ && !bitwriter_grow_(bw, msbits+lsbits))
return false;
if(msbits) {
/* first part gets to word alignment */
if(bw->bits) {
left = FLAC__BITS_PER_WORD - bw->bits;
if(msbits < left) {
bw->accum <<= msbits;
bw->bits += msbits;
goto break1;
}
else {
bw->accum <<= left;
msbits -= left;
bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
bw->bits = 0;
}
}
/* do whole words */
while(msbits >= FLAC__BITS_PER_WORD) {
bw->buffer[bw->words++] = 0;
msbits -= FLAC__BITS_PER_WORD;
}
/* do any leftovers */
if(msbits > 0) {
bw->accum = 0;
bw->bits = msbits;
}
}
break1:
uval |= mask1; /* set stop bit */
uval &= mask2; /* mask off unused top bits */
left = FLAC__BITS_PER_WORD - bw->bits;
if(lsbits < left) {
bw->accum <<= lsbits;
bw->accum |= uval;
bw->bits += lsbits;
}
else {
/* if bw->bits == 0, left==FLAC__BITS_PER_WORD which will always
* be > lsbits (because of previous assertions) so it would have
* triggered the (lsbits<left) case above.
*/
FLAC__ASSERT(bw->bits);
FLAC__ASSERT(left < FLAC__BITS_PER_WORD);
bw->accum <<= left;
bw->accum |= uval >> (bw->bits = lsbits - left);
bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
bw->accum = uval;
}
#if 1
}
#endif
vals++;
nvals--;
}
return true;
}
#if 0 /* UNUSED */
FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter)
{
unsigned total_bits, msbs, uval;
unsigned k;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
FLAC__ASSERT(parameter > 0);
/* fold signed to unsigned */
if(val < 0)
uval = (unsigned)(((-(++val)) << 1) + 1);
else
uval = (unsigned)(val << 1);
k = FLAC__bitmath_ilog2(parameter);
if(parameter == 1u<<k) {
unsigned pattern;
FLAC__ASSERT(k <= 30);
msbs = uval >> k;
total_bits = 1 + k + msbs;
pattern = 1 << k; /* the unary end bit */
pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
if(total_bits <= 32) {
if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits))
return false;
}
else {
/* write the unary MSBs */
if(!FLAC__bitwriter_write_zeroes(bw, msbs))
return false;
/* write the unary end bit and binary LSBs */
if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1))
return false;
}
}
else {
unsigned q, r, d;
d = (1 << (k+1)) - parameter;
q = uval / parameter;
r = uval - (q * parameter);
/* write the unary MSBs */
if(!FLAC__bitwriter_write_zeroes(bw, q))
return false;
/* write the unary end bit */
if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
return false;
/* write the binary LSBs */
if(r >= d) {
if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
return false;
}
else {
if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
return false;
}
}
return true;
}
FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned uval, unsigned parameter)
{
unsigned total_bits, msbs;
unsigned k;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
FLAC__ASSERT(parameter > 0);
k = FLAC__bitmath_ilog2(parameter);
if(parameter == 1u<<k) {
unsigned pattern;
FLAC__ASSERT(k <= 30);
msbs = uval >> k;
total_bits = 1 + k + msbs;
pattern = 1 << k; /* the unary end bit */
pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
if(total_bits <= 32) {
if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits))
return false;
}
else {
/* write the unary MSBs */
if(!FLAC__bitwriter_write_zeroes(bw, msbs))
return false;
/* write the unary end bit and binary LSBs */
if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1))
return false;
}
}
else {
unsigned q, r, d;
d = (1 << (k+1)) - parameter;
q = uval / parameter;
r = uval - (q * parameter);
/* write the unary MSBs */
if(!FLAC__bitwriter_write_zeroes(bw, q))
return false;
/* write the unary end bit */
if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
return false;
/* write the binary LSBs */
if(r >= d) {
if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
return false;
}
else {
if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
return false;
}
}
return true;
}
#endif /* UNUSED */
FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val)
{
FLAC__bool ok = 1;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
FLAC__ASSERT(!(val & 0x80000000)); /* this version only handles 31 bits */
if(val < 0x80) {
return FLAC__bitwriter_write_raw_uint32(bw, val, 8);
}
else if(val < 0x800) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (val>>6), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
}
else if(val < 0x10000) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (val>>12), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
}
else if(val < 0x200000) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (val>>18), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
}
else if(val < 0x4000000) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (val>>24), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
}
else {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (val>>30), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>24)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
}
return ok;
}
FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val)
{
FLAC__bool ok = 1;
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */
if(val < 0x80) {
return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 8);
}
else if(val < 0x800) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (FLAC__uint32)(val>>6), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
}
else if(val < 0x10000) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (FLAC__uint32)(val>>12), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
}
else if(val < 0x200000) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (FLAC__uint32)(val>>18), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
}
else if(val < 0x4000000) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (FLAC__uint32)(val>>24), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
}
else if(val < 0x80000000) {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (FLAC__uint32)(val>>30), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
}
else {
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFE, 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
}
return ok;
}
FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw)
{
/* 0-pad to byte boundary */
if(bw->bits & 7u)
return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u));
else
return true;
}

+ 418
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/cpu.c View File

@@ -0,0 +1,418 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "include/private/cpu.h"
#include <stdlib.h>
#include <stdio.h>
#if defined FLAC__CPU_IA32
# include <signal.h>
#elif defined FLAC__CPU_PPC
# if !defined FLAC__NO_ASM
# if defined FLAC__SYS_DARWIN
# include <sys/sysctl.h>
# include <mach/mach.h>
# include <mach/mach_host.h>
# include <mach/host_info.h>
# include <mach/machine.h>
# ifndef CPU_SUBTYPE_POWERPC_970
# define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
# endif
# else /* FLAC__SYS_DARWIN */
# include <signal.h>
# include <setjmp.h>
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump = 0;
static void sigill_handler (int sig)
{
if (!canjump) {
signal (sig, SIG_DFL);
raise (sig);
}
canjump = 0;
siglongjmp (jmpbuf, 1);
}
# endif /* FLAC__SYS_DARWIN */
# endif /* FLAC__NO_ASM */
#endif /* FLAC__CPU_PPC */
#if defined (__NetBSD__) || defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
#if defined(__APPLE__)
/* how to get sysctlbyname()? */
#endif
/* these are flags in EDX of CPUID AX=00000001 */
static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
/* these are flags in ECX of CPUID AX=00000001 */
static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
/* these are flags in EDX of CPUID AX=80000001 */
static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
/*
* Extra stuff needed for detection of OS support for SSE on IA-32
*/
#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS
# if defined(__linux__)
/*
* If the OS doesn't support SSE, we will get here with a SIGILL. We
* modify the return address to jump over the offending SSE instruction
* and also the operation following it that indicates the instruction
* executed successfully. In this way we use no global variables and
* stay thread-safe.
*
* 3 + 3 + 6:
* 3 bytes for "xorps xmm0,xmm0"
* 3 bytes for estimate of how long the follwing "inc var" instruction is
* 6 bytes extra in case our estimate is wrong
* 12 bytes puts us in the NOP "landing zone"
*/
# undef USE_OBSOLETE_SIGCONTEXT_FLAVOR /* #define this to use the older signal handler method */
# ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
static void sigill_handler_sse_os(int signal, struct sigcontext sc)
{
(void)signal;
sc.eip += 3 + 3 + 6;
}
# else
# include <sys/ucontext.h>
static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc)
{
(void)signal, (void)si;
((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6;
}
# endif
# elif defined(_MSC_VER)
# include <windows.h>
# undef USE_TRY_CATCH_FLAVOR /* #define this to use the try/catch method for catching illegal opcode exception */
# ifdef USE_TRY_CATCH_FLAVOR
# else
LONG CALLBACK sigill_handler_sse_os(EXCEPTION_POINTERS *ep)
{
if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
ep->ContextRecord->Eip += 3 + 3 + 6;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
# endif
# endif
#endif
void FLAC__cpu_info(FLAC__CPUInfo *info)
{
/*
* IA32-specific
*/
#ifdef FLAC__CPU_IA32
info->type = FLAC__CPUINFO_TYPE_IA32;
#if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
info->data.ia32.cpuid = FLAC__cpu_have_cpuid_asm_ia32()? true : false;
info->data.ia32.bswap = info->data.ia32.cpuid; /* CPUID => BSWAP since it came after */
info->data.ia32.cmov = false;
info->data.ia32.mmx = false;
info->data.ia32.fxsr = false;
info->data.ia32.sse = false;
info->data.ia32.sse2 = false;
info->data.ia32.sse3 = false;
info->data.ia32.ssse3 = false;
info->data.ia32._3dnow = false;
info->data.ia32.ext3dnow = false;
info->data.ia32.extmmx = false;
if(info->data.ia32.cpuid) {
/* http://www.sandpile.org/ia32/cpuid.htm */
FLAC__uint32 flags_edx, flags_ecx;
FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
info->data.ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false;
info->data.ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false;
info->data.ia32.fxsr = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false;
info->data.ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false;
info->data.ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false;
info->data.ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
info->data.ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
#ifdef FLAC__USE_3DNOW
flags_edx = FLAC__cpu_info_extended_amd_asm_ia32();
info->data.ia32._3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW )? true : false;
info->data.ia32.ext3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
info->data.ia32.extmmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX )? true : false;
#else
info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false;
#endif
#ifdef DEBUG
fprintf(stderr, "CPU info (IA-32):\n");
fprintf(stderr, " CPUID ...... %c\n", info->data.ia32.cpuid ? 'Y' : 'n');
fprintf(stderr, " BSWAP ...... %c\n", info->data.ia32.bswap ? 'Y' : 'n');
fprintf(stderr, " CMOV ....... %c\n", info->data.ia32.cmov ? 'Y' : 'n');
fprintf(stderr, " MMX ........ %c\n", info->data.ia32.mmx ? 'Y' : 'n');
fprintf(stderr, " FXSR ....... %c\n", info->data.ia32.fxsr ? 'Y' : 'n');
fprintf(stderr, " SSE ........ %c\n", info->data.ia32.sse ? 'Y' : 'n');
fprintf(stderr, " SSE2 ....... %c\n", info->data.ia32.sse2 ? 'Y' : 'n');
fprintf(stderr, " SSE3 ....... %c\n", info->data.ia32.sse3 ? 'Y' : 'n');
fprintf(stderr, " SSSE3 ...... %c\n", info->data.ia32.ssse3 ? 'Y' : 'n');
fprintf(stderr, " 3DNow! ..... %c\n", info->data.ia32._3dnow ? 'Y' : 'n');
fprintf(stderr, " 3DNow!-ext . %c\n", info->data.ia32.ext3dnow? 'Y' : 'n');
fprintf(stderr, " 3DNow!-MMX . %c\n", info->data.ia32.extmmx ? 'Y' : 'n');
#endif
/*
* now have to check for OS support of SSE/SSE2
*/
if(info->data.ia32.fxsr || info->data.ia32.sse || info->data.ia32.sse2) {
#if defined FLAC__NO_SSE_OS
/* assume user knows better than us; turn it off */
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
#elif defined FLAC__SSE_OS
/* assume user knows better than us; leave as detected above */
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
int sse = 0;
size_t len;
/* at least one of these must work: */
len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse);
len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse" , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */
if(!sse)
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
#elif defined(__NetBSD__) || defined (__OpenBSD__)
# if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE };
size_t len = sizeof(val);
if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
else { /* double-check SSE2 */
mib[1] = CPU_SSE2;
len = sizeof(val);
if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
}
# else
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
# endif
#elif defined(__linux__)
int sse = 0;
struct sigaction sigill_save;
#ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
if(0 == sigaction(SIGILL, NULL, &sigill_save) && signal(SIGILL, (void (*)(int))sigill_handler_sse_os) != SIG_ERR)
#else
struct sigaction sigill_sse;
sigill_sse.sa_sigaction = sigill_handler_sse_os;
__sigemptyset(&sigill_sse.sa_mask);
sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */
if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save))
#endif
{
/* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
/* see sigill_handler_sse_os() for an explanation of the following: */
asm volatile (
"xorl %0,%0\n\t" /* for some reason, still need to do this to clear 'sse' var */
"xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */
"incl %0\n\t" /* SIGILL handler will jump over this */
/* landing zone */
"nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */
"nop\n\t"
"nop" /* SIGILL jump lands here if "inc" is 1 byte */
: "=r"(sse)
: "r"(sse)
);
sigaction(SIGILL, &sigill_save, NULL);
}
if(!sse)
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
#elif defined(_MSC_VER)
# ifdef USE_TRY_CATCH_FLAVOR
_try {
__asm {
# if _MSC_VER <= 1200
/* VC6 assembler doesn't know SSE, have to emit bytecode instead */
_emit 0x0F
_emit 0x57
_emit 0xC0
# else
xorps xmm0,xmm0
# endif
}
}
_except(EXCEPTION_EXECUTE_HANDLER) {
if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
}
# else
int sse = 0;
LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os);
/* see GCC version above for explanation */
/* http://msdn2.microsoft.com/en-us/library/4ks26t93.aspx */
/* http://www.codeproject.com/cpp/gccasm.asp */
/* http://www.hick.org/~mmiller/msvc_inline_asm.html */
__asm {
# if _MSC_VER <= 1200
/* VC6 assembler doesn't know SSE, have to emit bytecode instead */
_emit 0x0F
_emit 0x57
_emit 0xC0
# else
xorps xmm0,xmm0
# endif
inc sse
nop
nop
nop
nop
nop
nop
nop
nop
nop
}
SetUnhandledExceptionFilter(save);
if(!sse)
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
# endif
#else
/* no way to test, disable to be safe */
info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
#endif
#ifdef DEBUG
fprintf(stderr, " SSE OS sup . %c\n", info->data.ia32.sse ? 'Y' : 'n');
#endif
}
}
#else
info->use_asm = false;
#endif
/*
* PPC-specific
*/
#elif defined FLAC__CPU_PPC
info->type = FLAC__CPUINFO_TYPE_PPC;
# if !defined FLAC__NO_ASM
info->use_asm = true;
# ifdef FLAC__USE_ALTIVEC
# if defined FLAC__SYS_DARWIN
{
int val = 0, mib[2] = { CTL_HW, HW_VECTORUNIT };
size_t len = sizeof(val);
info->data.ppc.altivec = !(sysctl(mib, 2, &val, &len, NULL, 0) || !val);
}
{
host_basic_info_data_t hostInfo;
mach_msg_type_number_t infoCount;
infoCount = HOST_BASIC_INFO_COUNT;
host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount);
info->data.ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970);
}
# else /* FLAC__USE_ALTIVEC && !FLAC__SYS_DARWIN */
{
/* no Darwin, do it the brute-force way */
/* @@@@@@ this is not thread-safe; replace with SSE OS method above or remove */
info->data.ppc.altivec = 0;
info->data.ppc.ppc64 = 0;
signal (SIGILL, sigill_handler);
canjump = 0;
if (!sigsetjmp (jmpbuf, 1)) {
canjump = 1;
asm volatile (
"mtspr 256, %0\n\t"
"vand %%v0, %%v0, %%v0"
:
: "r" (-1)
);
info->data.ppc.altivec = 1;
}
canjump = 0;
if (!sigsetjmp (jmpbuf, 1)) {
int x = 0;
canjump = 1;
/* PPC64 hardware implements the cntlzd instruction */
asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) );
info->data.ppc.ppc64 = 1;
}
signal (SIGILL, SIG_DFL); /*@@@@@@ should save and restore old signal */
}
# endif
# else /* !FLAC__USE_ALTIVEC */
info->data.ppc.altivec = 0;
info->data.ppc.ppc64 = 0;
# endif
# else
info->use_asm = false;
# endif
/*
* unknown CPI
*/
#else
info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
info->use_asm = false;
#endif
}

+ 142
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/crc.c View File

@@ -0,0 +1,142 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "include/private/crc.h"
/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
FLAC__byte const FLAC__crc8_table[256] = {
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
};
/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
unsigned FLAC__crc16_table[256] = {
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
};
void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc)
{
*crc = FLAC__crc8_table[*crc ^ data];
}
void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc)
{
while(len--)
*crc = FLAC__crc8_table[*crc ^ *data++];
}
FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len)
{
FLAC__uint8 crc = 0;
while(len--)
crc = FLAC__crc8_table[crc ^ *data++];
return crc;
}
unsigned FLAC__crc16(const FLAC__byte *data, unsigned len)
{
unsigned crc = 0;
while(len--)
crc = ((crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]) & 0xffff;
return crc;
}

+ 435
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/fixed.c View File

@@ -0,0 +1,435 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h>
#include <string.h>
#include "include/private/bitmath.h"
#include "include/private/fixed.h"
#include "../assert.h"
#ifndef M_LN2
/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
#define M_LN2 0.69314718055994530942
#endif
#ifdef min
#undef min
#endif
#define min(x,y) ((x) < (y)? (x) : (y))
#ifdef local_abs
#undef local_abs
#endif
#define local_abs(x) ((unsigned)((x)<0? -(x) : (x)))
#ifdef FLAC__INTEGER_ONLY_LIBRARY
/* rbps stands for residual bits per sample
*
* (ln(2) * err)
* rbps = log (-----------)
* 2 ( n )
*/
static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n)
{
FLAC__uint32 rbps;
unsigned bits; /* the number of bits required to represent a number */
int fracbits; /* the number of bits of rbps that comprise the fractional part */
FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
FLAC__ASSERT(err > 0);
FLAC__ASSERT(n > 0);
FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
if(err <= n)
return 0;
/*
* The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
* These allow us later to know we won't lose too much precision in the
* fixed-point division (err<<fracbits)/n.
*/
fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2(err)+1);
err <<= fracbits;
err /= n;
/* err now holds err/n with fracbits fractional bits */
/*
* Whittle err down to 16 bits max. 16 significant bits is enough for
* our purposes.
*/
FLAC__ASSERT(err > 0);
bits = FLAC__bitmath_ilog2(err)+1;
if(bits > 16) {
err >>= (bits-16);
fracbits -= (bits-16);
}
rbps = (FLAC__uint32)err;
/* Multiply by fixed-point version of ln(2), with 16 fractional bits */
rbps *= FLAC__FP_LN2;
fracbits += 16;
FLAC__ASSERT(fracbits >= 0);
/* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
{
const int f = fracbits & 3;
if(f) {
rbps >>= f;
fracbits -= f;
}
}
rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
if(rbps == 0)
return 0;
/*
* The return value must have 16 fractional bits. Since the whole part
* of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
* must be >= -3, these assertion allows us to be able to shift rbps
* left if necessary to get 16 fracbits without losing any bits of the
* whole part of rbps.
*
* There is a slight chance due to accumulated error that the whole part
* will require 6 bits, so we use 6 in the assertion. Really though as
* long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
*/
FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
FLAC__ASSERT(fracbits >= -3);
/* now shift the decimal point into place */
if(fracbits < 16)
return rbps << (16-fracbits);
else if(fracbits > 16)
return rbps >> (fracbits-16);
else
return rbps;
}
static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n)
{
FLAC__uint32 rbps;
unsigned bits; /* the number of bits required to represent a number */
int fracbits; /* the number of bits of rbps that comprise the fractional part */
FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
FLAC__ASSERT(err > 0);
FLAC__ASSERT(n > 0);
FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
if(err <= n)
return 0;
/*
* The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
* These allow us later to know we won't lose too much precision in the
* fixed-point division (err<<fracbits)/n.
*/
fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2_wide(err)+1);
err <<= fracbits;
err /= n;
/* err now holds err/n with fracbits fractional bits */
/*
* Whittle err down to 16 bits max. 16 significant bits is enough for
* our purposes.
*/
FLAC__ASSERT(err > 0);
bits = FLAC__bitmath_ilog2_wide(err)+1;
if(bits > 16) {
err >>= (bits-16);
fracbits -= (bits-16);
}
rbps = (FLAC__uint32)err;
/* Multiply by fixed-point version of ln(2), with 16 fractional bits */
rbps *= FLAC__FP_LN2;
fracbits += 16;
FLAC__ASSERT(fracbits >= 0);
/* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
{
const int f = fracbits & 3;
if(f) {
rbps >>= f;
fracbits -= f;
}
}
rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
if(rbps == 0)
return 0;
/*
* The return value must have 16 fractional bits. Since the whole part
* of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
* must be >= -3, these assertion allows us to be able to shift rbps
* left if necessary to get 16 fracbits without losing any bits of the
* whole part of rbps.
*
* There is a slight chance due to accumulated error that the whole part
* will require 6 bits, so we use 6 in the assertion. Really though as
* long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
*/
FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
FLAC__ASSERT(fracbits >= -3);
/* now shift the decimal point into place */
if(fracbits < 16)
return rbps << (16-fracbits);
else if(fracbits > 16)
return rbps >> (fracbits-16);
else
return rbps;
}
#endif
#ifndef FLAC__INTEGER_ONLY_LIBRARY
unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
#else
unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
#endif
{
FLAC__int32 last_error_0 = data[-1];
FLAC__int32 last_error_1 = data[-1] - data[-2];
FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
FLAC__int32 error, save;
FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
unsigned i, order;
for(i = 0; i < data_len; i++) {
error = data[i] ; total_error_0 += local_abs(error); save = error;
error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
}
if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
order = 0;
else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
order = 1;
else if(total_error_2 < min(total_error_3, total_error_4))
order = 2;
else if(total_error_3 < total_error_4)
order = 3;
else
order = 4;
/* Estimate the expected number of bits per residual signal sample. */
/* 'total_error*' is linearly related to the variance of the residual */
/* signal, so we use it directly to compute E(|x|) */
FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
#ifndef FLAC__INTEGER_ONLY_LIBRARY
residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
#else
residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0;
residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0;
residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0;
residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0;
residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0;
#endif
return order;
}
#ifndef FLAC__INTEGER_ONLY_LIBRARY
unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
#else
unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
#endif
{
FLAC__int32 last_error_0 = data[-1];
FLAC__int32 last_error_1 = data[-1] - data[-2];
FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
FLAC__int32 error, save;
/* total_error_* are 64-bits to avoid overflow when encoding
* erratic signals when the bits-per-sample and blocksize are
* large.
*/
FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
unsigned i, order;
for(i = 0; i < data_len; i++) {
error = data[i] ; total_error_0 += local_abs(error); save = error;
error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
}
if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
order = 0;
else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
order = 1;
else if(total_error_2 < min(total_error_3, total_error_4))
order = 2;
else if(total_error_3 < total_error_4)
order = 3;
else
order = 4;
/* Estimate the expected number of bits per residual signal sample. */
/* 'total_error*' is linearly related to the variance of the residual */
/* signal, so we use it directly to compute E(|x|) */
FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
#ifndef FLAC__INTEGER_ONLY_LIBRARY
#if defined _MSC_VER || defined __MINGW32__
/* with MSVC you have to spoon feed it the casting */
residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
#else
residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
#endif
#else
residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0;
residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0;
residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0;
residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0;
residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0;
#endif
return order;
}
void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[])
{
const int idata_len = (int)data_len;
int i;
switch(order) {
case 0:
FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
memcpy(residual, data, sizeof(residual[0])*data_len);
break;
case 1:
for(i = 0; i < idata_len; i++)
residual[i] = data[i] - data[i-1];
break;
case 2:
for(i = 0; i < idata_len; i++)
#if 1 /* OPT: may be faster with some compilers on some systems */
residual[i] = data[i] - (data[i-1] << 1) + data[i-2];
#else
residual[i] = data[i] - 2*data[i-1] + data[i-2];
#endif
break;
case 3:
for(i = 0; i < idata_len; i++)
#if 1 /* OPT: may be faster with some compilers on some systems */
residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3];
#else
residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
#endif
break;
case 4:
for(i = 0; i < idata_len; i++)
#if 1 /* OPT: may be faster with some compilers on some systems */
residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4];
#else
residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
#endif
break;
default:
FLAC__ASSERT(0);
}
}
void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[])
{
int i, idata_len = (int)data_len;
switch(order) {
case 0:
FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
memcpy(data, residual, sizeof(residual[0])*data_len);
break;
case 1:
for(i = 0; i < idata_len; i++)
data[i] = residual[i] + data[i-1];
break;
case 2:
for(i = 0; i < idata_len; i++)
#if 1 /* OPT: may be faster with some compilers on some systems */
data[i] = residual[i] + (data[i-1]<<1) - data[i-2];
#else
data[i] = residual[i] + 2*data[i-1] - data[i-2];
#endif
break;
case 3:
for(i = 0; i < idata_len; i++)
#if 1 /* OPT: may be faster with some compilers on some systems */
data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3];
#else
data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
#endif
break;
case 4:
for(i = 0; i < idata_len; i++)
#if 1 /* OPT: may be faster with some compilers on some systems */
data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4];
#else
data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
#endif
break;
default:
FLAC__ASSERT(0);
}
}

+ 308
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/float.c View File

@@ -0,0 +1,308 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "../assert.h"
#include "include/private/float.h"
#ifdef FLAC__INTEGER_ONLY_LIBRARY
/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
#ifdef _MSC_VER
#define FLAC__U64L(x) x
#else
#define FLAC__U64L(x) x##LLU
#endif
const FLAC__fixedpoint FLAC__FP_ZERO = 0;
const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000;
const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000;
const FLAC__fixedpoint FLAC__FP_LN2 = 45426;
const FLAC__fixedpoint FLAC__FP_E = 178145;
/* Lookup tables for Knuth's logarithm algorithm */
#define LOG2_LOOKUP_PRECISION 16
static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = {
{
/*
* 0 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x00000001,
/* lg(4/3) = */ 0x00000000,
/* lg(8/7) = */ 0x00000000,
/* lg(16/15) = */ 0x00000000,
/* lg(32/31) = */ 0x00000000,
/* lg(64/63) = */ 0x00000000,
/* lg(128/127) = */ 0x00000000,
/* lg(256/255) = */ 0x00000000,
/* lg(512/511) = */ 0x00000000,
/* lg(1024/1023) = */ 0x00000000,
/* lg(2048/2047) = */ 0x00000000,
/* lg(4096/4095) = */ 0x00000000,
/* lg(8192/8191) = */ 0x00000000,
/* lg(16384/16383) = */ 0x00000000,
/* lg(32768/32767) = */ 0x00000000
},
{
/*
* 4 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x00000010,
/* lg(4/3) = */ 0x00000007,
/* lg(8/7) = */ 0x00000003,
/* lg(16/15) = */ 0x00000001,
/* lg(32/31) = */ 0x00000001,
/* lg(64/63) = */ 0x00000000,
/* lg(128/127) = */ 0x00000000,
/* lg(256/255) = */ 0x00000000,
/* lg(512/511) = */ 0x00000000,
/* lg(1024/1023) = */ 0x00000000,
/* lg(2048/2047) = */ 0x00000000,
/* lg(4096/4095) = */ 0x00000000,
/* lg(8192/8191) = */ 0x00000000,
/* lg(16384/16383) = */ 0x00000000,
/* lg(32768/32767) = */ 0x00000000
},
{
/*
* 8 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x00000100,
/* lg(4/3) = */ 0x0000006a,
/* lg(8/7) = */ 0x00000031,
/* lg(16/15) = */ 0x00000018,
/* lg(32/31) = */ 0x0000000c,
/* lg(64/63) = */ 0x00000006,
/* lg(128/127) = */ 0x00000003,
/* lg(256/255) = */ 0x00000001,
/* lg(512/511) = */ 0x00000001,
/* lg(1024/1023) = */ 0x00000000,
/* lg(2048/2047) = */ 0x00000000,
/* lg(4096/4095) = */ 0x00000000,
/* lg(8192/8191) = */ 0x00000000,
/* lg(16384/16383) = */ 0x00000000,
/* lg(32768/32767) = */ 0x00000000
},
{
/*
* 12 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x00001000,
/* lg(4/3) = */ 0x000006a4,
/* lg(8/7) = */ 0x00000315,
/* lg(16/15) = */ 0x0000017d,
/* lg(32/31) = */ 0x000000bc,
/* lg(64/63) = */ 0x0000005d,
/* lg(128/127) = */ 0x0000002e,
/* lg(256/255) = */ 0x00000017,
/* lg(512/511) = */ 0x0000000c,
/* lg(1024/1023) = */ 0x00000006,
/* lg(2048/2047) = */ 0x00000003,
/* lg(4096/4095) = */ 0x00000001,
/* lg(8192/8191) = */ 0x00000001,
/* lg(16384/16383) = */ 0x00000000,
/* lg(32768/32767) = */ 0x00000000
},
{
/*
* 16 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x00010000,
/* lg(4/3) = */ 0x00006a40,
/* lg(8/7) = */ 0x00003151,
/* lg(16/15) = */ 0x000017d6,
/* lg(32/31) = */ 0x00000bba,
/* lg(64/63) = */ 0x000005d1,
/* lg(128/127) = */ 0x000002e6,
/* lg(256/255) = */ 0x00000172,
/* lg(512/511) = */ 0x000000b9,
/* lg(1024/1023) = */ 0x0000005c,
/* lg(2048/2047) = */ 0x0000002e,
/* lg(4096/4095) = */ 0x00000017,
/* lg(8192/8191) = */ 0x0000000c,
/* lg(16384/16383) = */ 0x00000006,
/* lg(32768/32767) = */ 0x00000003
},
{
/*
* 20 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x00100000,
/* lg(4/3) = */ 0x0006a3fe,
/* lg(8/7) = */ 0x00031513,
/* lg(16/15) = */ 0x00017d60,
/* lg(32/31) = */ 0x0000bb9d,
/* lg(64/63) = */ 0x00005d10,
/* lg(128/127) = */ 0x00002e59,
/* lg(256/255) = */ 0x00001721,
/* lg(512/511) = */ 0x00000b8e,
/* lg(1024/1023) = */ 0x000005c6,
/* lg(2048/2047) = */ 0x000002e3,
/* lg(4096/4095) = */ 0x00000171,
/* lg(8192/8191) = */ 0x000000b9,
/* lg(16384/16383) = */ 0x0000005c,
/* lg(32768/32767) = */ 0x0000002e
},
{
/*
* 24 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x01000000,
/* lg(4/3) = */ 0x006a3fe6,
/* lg(8/7) = */ 0x00315130,
/* lg(16/15) = */ 0x0017d605,
/* lg(32/31) = */ 0x000bb9ca,
/* lg(64/63) = */ 0x0005d0fc,
/* lg(128/127) = */ 0x0002e58f,
/* lg(256/255) = */ 0x0001720e,
/* lg(512/511) = */ 0x0000b8d8,
/* lg(1024/1023) = */ 0x00005c61,
/* lg(2048/2047) = */ 0x00002e2d,
/* lg(4096/4095) = */ 0x00001716,
/* lg(8192/8191) = */ 0x00000b8b,
/* lg(16384/16383) = */ 0x000005c5,
/* lg(32768/32767) = */ 0x000002e3
},
{
/*
* 28 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ 0x10000000,
/* lg(4/3) = */ 0x06a3fe5c,
/* lg(8/7) = */ 0x03151301,
/* lg(16/15) = */ 0x017d6049,
/* lg(32/31) = */ 0x00bb9ca6,
/* lg(64/63) = */ 0x005d0fba,
/* lg(128/127) = */ 0x002e58f7,
/* lg(256/255) = */ 0x001720da,
/* lg(512/511) = */ 0x000b8d87,
/* lg(1024/1023) = */ 0x0005c60b,
/* lg(2048/2047) = */ 0x0002e2d7,
/* lg(4096/4095) = */ 0x00017160,
/* lg(8192/8191) = */ 0x0000b8ad,
/* lg(16384/16383) = */ 0x00005c56,
/* lg(32768/32767) = */ 0x00002e2b
}
};
#if 0
static const FLAC__uint64 log2_lookup_wide[] = {
{
/*
* 32 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ FLAC__U64L(0x100000000),
/* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6),
/* lg(8/7) = */ FLAC__U64L(0x31513015),
/* lg(16/15) = */ FLAC__U64L(0x17d60497),
/* lg(32/31) = */ FLAC__U64L(0x0bb9ca65),
/* lg(64/63) = */ FLAC__U64L(0x05d0fba2),
/* lg(128/127) = */ FLAC__U64L(0x02e58f74),
/* lg(256/255) = */ FLAC__U64L(0x01720d9c),
/* lg(512/511) = */ FLAC__U64L(0x00b8d875),
/* lg(1024/1023) = */ FLAC__U64L(0x005c60aa),
/* lg(2048/2047) = */ FLAC__U64L(0x002e2d72),
/* lg(4096/4095) = */ FLAC__U64L(0x00171600),
/* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2),
/* lg(16384/16383) = */ FLAC__U64L(0x0005c55d),
/* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac)
},
{
/*
* 48 fraction bits
*/
/* undefined */ 0x00000000,
/* lg(2/1) = */ FLAC__U64L(0x1000000000000),
/* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429),
/* lg(8/7) = */ FLAC__U64L(0x315130157f7a),
/* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb),
/* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac),
/* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd),
/* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee),
/* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8),
/* lg(512/511) = */ FLAC__U64L(0xb8d8752173),
/* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e),
/* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8),
/* lg(4096/4095) = */ FLAC__U64L(0x1716001719),
/* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b),
/* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d),
/* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52)
}
};
#endif
FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision)
{
const FLAC__uint32 ONE = (1u << fracbits);
const FLAC__uint32 *table = log2_lookup[fracbits >> 2];
FLAC__ASSERT(fracbits < 32);
FLAC__ASSERT((fracbits & 0x3) == 0);
if(x < ONE)
return 0;
if(precision > LOG2_LOOKUP_PRECISION)
precision = LOG2_LOOKUP_PRECISION;
/* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */
{
FLAC__uint32 y = 0;
FLAC__uint32 z = x >> 1, k = 1;
while (x > ONE && k < precision) {
if (x - z >= ONE) {
x -= z;
z = x >> k;
y += table[k];
}
else {
z >>= 1;
k++;
}
}
return y;
}
}
#endif /* defined FLAC__INTEGER_ONLY_LIBRARY */

+ 598
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/format.c View File

@@ -0,0 +1,598 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h> /* for qsort() */
#include <string.h> /* for memset() */
#include "../assert.h"
#include "../format.h"
#include "include/private/format.h"
#ifndef FLaC__INLINE
#define FLaC__INLINE
#endif
#ifdef min
#undef min
#endif
#define min(a,b) ((a)<(b)?(a):(b))
/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
#ifdef _MSC_VER
#define FLAC__U64L(x) x
#else
#define FLAC__U64L(x) x##LLU
#endif
/* VERSION should come from configure */
FLAC_API const char *FLAC__VERSION_STRING = VERSION
;
#if defined _MSC_VER || defined __BORLANDC__ || defined __MINW32__
/* yet one more hack because of MSVC6: */
FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.2.1 20070917";
#else
FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20070917";
#endif
FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */
FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
"PARTITIONED_RICE",
"PARTITIONED_RICE2"
};
FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
FLAC_API const char * const FLAC__SubframeTypeString[] = {
"CONSTANT",
"VERBATIM",
"FIXED",
"LPC"
};
FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
"INDEPENDENT",
"LEFT_SIDE",
"RIGHT_SIDE",
"MID_SIDE"
};
FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
"FRAME_NUMBER_TYPE_FRAME_NUMBER",
"FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
};
FLAC_API const char * const FLAC__MetadataTypeString[] = {
"STREAMINFO",
"PADDING",
"APPLICATION",
"SEEKTABLE",
"VORBIS_COMMENT",
"CUESHEET",
"PICTURE"
};
FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
"Other",
"32x32 pixels 'file icon' (PNG only)",
"Other file icon",
"Cover (front)",
"Cover (back)",
"Leaflet page",
"Media (e.g. label side of CD)",
"Lead artist/lead performer/soloist",
"Artist/performer",
"Conductor",
"Band/Orchestra",
"Composer",
"Lyricist/text writer",
"Recording Location",
"During recording",
"During performance",
"Movie/video screen capture",
"A bright coloured fish",
"Illustration",
"Band/artist logotype",
"Publisher/Studio logotype"
};
FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
{
if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) {
return false;
}
else
return true;
}
FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate)
{
if(
!FLAC__format_sample_rate_is_valid(sample_rate) ||
(
sample_rate >= (1u << 16) &&
!(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
)
) {
return false;
}
else
return true;
}
/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
{
unsigned i;
FLAC__uint64 prev_sample_number = 0;
FLAC__bool got_prev = false;
FLAC__ASSERT(0 != seek_table);
for(i = 0; i < seek_table->num_points; i++) {
if(got_prev) {
if(
seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
seek_table->points[i].sample_number <= prev_sample_number
)
return false;
}
prev_sample_number = seek_table->points[i].sample_number;
got_prev = true;
}
return true;
}
/* used as the sort predicate for qsort() */
static int JUCE_CDECL seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
{
/* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
if(l->sample_number == r->sample_number)
return 0;
else if(l->sample_number < r->sample_number)
return -1;
else
return 1;
}
/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
{
unsigned i, j;
FLAC__bool first;
FLAC__ASSERT(0 != seek_table);
/* sort the seekpoints */
qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (JUCE_CDECL *)(const void *, const void *))seekpoint_compare_);
/* uniquify the seekpoints */
first = true;
for(i = j = 0; i < seek_table->num_points; i++) {
if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
if(!first) {
if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
continue;
}
}
first = false;
seek_table->points[j++] = seek_table->points[i];
}
for(i = j; i < seek_table->num_points; i++) {
seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
seek_table->points[i].stream_offset = 0;
seek_table->points[i].frame_samples = 0;
}
return j;
}
/*
* also disallows non-shortest-form encodings, c.f.
* http://www.unicode.org/versions/corrigendum1.html
* and a more clear explanation at the end of this section:
* http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
*/
static FLaC__INLINE unsigned utf8len_(const FLAC__byte *utf8)
{
FLAC__ASSERT(0 != utf8);
if ((utf8[0] & 0x80) == 0) {
return 1;
}
else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
return 0;
return 2;
}
else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
return 0;
/* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
return 0;
if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
return 0;
return 3;
}
else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
return 0;
return 4;
}
else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
return 0;
return 5;
}
else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
return 0;
return 6;
}
else {
return 0;
}
}
FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
{
char c;
for(c = *name; c; c = *(++name))
if(c < 0x20 || c == 0x3d || c > 0x7d)
return false;
return true;
}
FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
{
if(length == (unsigned)(-1)) {
while(*value) {
unsigned n = utf8len_(value);
if(n == 0)
return false;
value += n;
}
}
else {
const FLAC__byte *end = value + length;
while(value < end) {
unsigned n = utf8len_(value);
if(n == 0)
return false;
value += n;
}
if(value != end)
return false;
}
return true;
}
FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
{
const FLAC__byte *s, *end;
for(s = entry, end = s + length; s < end && *s != '='; s++) {
if(*s < 0x20 || *s > 0x7D)
return false;
}
if(s == end)
return false;
s++; /* skip '=' */
while(s < end) {
unsigned n = utf8len_(s);
if(n == 0)
return false;
s += n;
}
if(s != end)
return false;
return true;
}
/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
{
unsigned i, j;
if(check_cd_da_subset) {
if(cue_sheet->lead_in < 2 * 44100) {
if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
return false;
}
if(cue_sheet->lead_in % 588 != 0) {
if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
return false;
}
}
if(cue_sheet->num_tracks == 0) {
if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
return false;
}
if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
return false;
}
for(i = 0; i < cue_sheet->num_tracks; i++) {
if(cue_sheet->tracks[i].number == 0) {
if(violation) *violation = "cue sheet may not have a track number 0";
return false;
}
if(check_cd_da_subset) {
if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
return false;
}
}
if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
if(violation) {
if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
*violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
else
*violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
}
return false;
}
if(i < cue_sheet->num_tracks - 1) {
if(cue_sheet->tracks[i].num_indices == 0) {
if(violation) *violation = "cue sheet track must have at least one index point";
return false;
}
if(cue_sheet->tracks[i].indices[0].number > 1) {
if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
return false;
}
}
for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
return false;
}
if(j > 0) {
if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
if(violation) *violation = "cue sheet track index numbers must increase by 1";
return false;
}
}
}
}
return true;
}
/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
{
char *p;
FLAC__byte *b;
for(p = picture->mime_type; *p; p++) {
if(*p < 0x20 || *p > 0x7e) {
if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
return false;
}
}
for(b = picture->description; *b; ) {
unsigned n = utf8len_(b);
if(n == 0) {
if(violation) *violation = "description string must be valid UTF-8";
return false;
}
b += n;
}
return true;
}
/*
* These routines are private to libFLAC
*/
unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
{
return
FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
blocksize,
predictor_order
);
}
unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
{
unsigned max_rice_partition_order = 0;
while(!(blocksize & 1)) {
max_rice_partition_order++;
blocksize >>= 1;
}
return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
}
unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
{
unsigned max_rice_partition_order = limit;
while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
max_rice_partition_order--;
FLAC__ASSERT(
(max_rice_partition_order == 0 && blocksize >= predictor_order) ||
(max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
);
return max_rice_partition_order;
}
void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
{
FLAC__ASSERT(0 != object);
object->parameters = 0;
object->raw_bits = 0;
object->capacity_by_order = 0;
}
void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
{
FLAC__ASSERT(0 != object);
if(0 != object->parameters)
free(object->parameters);
if(0 != object->raw_bits)
free(object->raw_bits);
FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
}
FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order)
{
FLAC__ASSERT(0 != object);
FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
if(object->capacity_by_order < max_partition_order) {
if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
return false;
if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
return false;
memset(object->raw_bits, 0, sizeof(unsigned)*(1 << max_partition_order));
object->capacity_by_order = max_partition_order;
}
return true;
}

+ 49
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/all.h View File

@@ -0,0 +1,49 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__ALL_H
#define FLAC__PRIVATE__ALL_H
#include "bitmath.h"
#include "bitreader.h"
#include "bitwriter.h"
#include "cpu.h"
#include "crc.h"
#include "fixed.h"
#include "float.h"
#include "format.h"
#include "lpc.h"
#include "md5.h"
#include "memory.h"
#include "metadata.h"
#include "stream_encoder_framing.h"
#endif

+ 42
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/bitmath.h View File

@@ -0,0 +1,42 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__BITMATH_H
#define FLAC__PRIVATE__BITMATH_H
#include "../../../ordinals.h"
unsigned FLAC__bitmath_ilog2(FLAC__uint32 v);
unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v);
unsigned FLAC__bitmath_silog2(int v);
unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v);
#endif

+ 99
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/bitreader.h View File

@@ -0,0 +1,99 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__BITREADER_H
#define FLAC__PRIVATE__BITREADER_H
#include <stdio.h> /* for FILE */
#include "../../../ordinals.h"
#include "cpu.h"
/*
* opaque structure definition
*/
struct FLAC__BitReader;
typedef struct FLAC__BitReader FLAC__BitReader;
typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data);
/*
* construction, deletion, initialization, etc functions
*/
FLAC__BitReader *FLAC__bitreader_new(void);
void FLAC__bitreader_delete(FLAC__BitReader *br);
FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd);
void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */
FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br);
void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out);
/*
* CRC functions
*/
void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed);
FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br);
/*
* info functions
*/
FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
/*
* read functions
*/
FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits);
FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits);
FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits);
FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/
FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */
FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val);
FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter);
FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
#ifndef FLAC__NO_ASM
# ifdef FLAC__CPU_IA32
# ifdef FLAC__HAS_NASM
FLAC__bool FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
# endif
# endif
#endif
#if 0 /* UNUSED */
FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter);
FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter);
#endif
FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen);
FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen);
FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br);
#endif

+ 103
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/bitwriter.h View File

@@ -0,0 +1,103 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__BITWRITER_H
#define FLAC__PRIVATE__BITWRITER_H
#include <stdio.h> /* for FILE */
#include "../../../ordinals.h"
/*
* opaque structure definition
*/
struct FLAC__BitWriter;
typedef struct FLAC__BitWriter FLAC__BitWriter;
/*
* construction, deletion, initialization, etc functions
*/
FLAC__BitWriter *FLAC__bitwriter_new(void);
void FLAC__bitwriter_delete(FLAC__BitWriter *bw);
FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw);
void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */
void FLAC__bitwriter_clear(FLAC__BitWriter *bw);
void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out);
/*
* CRC functions
*
* non-const *bw because they have to cal FLAC__bitwriter_get_buffer()
*/
FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc);
FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc);
/*
* info functions
*/
FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw);
unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */
/*
* direct buffer access
*
* there may be no calls on the bitwriter between get and release.
* the bitwriter continues to own the returned buffer.
* before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned()
*/
FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes);
void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw);
/*
* write functions
*/
FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits);
FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits);
FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits);
FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits);
FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/
FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals);
FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val);
unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter);
#if 0 /* UNUSED */
unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter);
unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned val, unsigned parameter);
#endif
FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter);
FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter);
#if 0 /* UNUSED */
FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter);
FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned val, unsigned parameter);
#endif
FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val);
FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val);
FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw);
#endif

+ 88
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/cpu.h View File

@@ -0,0 +1,88 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__CPU_H
#define FLAC__PRIVATE__CPU_H
#include "../../../ordinals.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
typedef enum {
FLAC__CPUINFO_TYPE_IA32,
FLAC__CPUINFO_TYPE_PPC,
FLAC__CPUINFO_TYPE_UNKNOWN
} FLAC__CPUInfo_Type;
typedef struct {
FLAC__bool cpuid;
FLAC__bool bswap;
FLAC__bool cmov;
FLAC__bool mmx;
FLAC__bool fxsr;
FLAC__bool sse;
FLAC__bool sse2;
FLAC__bool sse3;
FLAC__bool ssse3;
FLAC__bool _3dnow;
FLAC__bool ext3dnow;
FLAC__bool extmmx;
} FLAC__CPUInfo_IA32;
typedef struct {
FLAC__bool altivec;
FLAC__bool ppc64;
} FLAC__CPUInfo_PPC;
typedef struct {
FLAC__bool use_asm;
FLAC__CPUInfo_Type type;
union {
FLAC__CPUInfo_IA32 ia32;
FLAC__CPUInfo_PPC ppc;
} data;
} FLAC__CPUInfo;
void FLAC__cpu_info(FLAC__CPUInfo *info);
#ifndef FLAC__NO_ASM
#ifdef FLAC__CPU_IA32
#ifdef FLAC__HAS_NASM
FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void);
void FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx);
FLAC__uint32 FLAC__cpu_info_extended_amd_asm_ia32(void);
#endif
#endif
#endif
#endif

+ 61
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/crc.h View File

@@ -0,0 +1,61 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__CRC_H
#define FLAC__PRIVATE__CRC_H
#include "../../../ordinals.h"
/* 8 bit CRC generator, MSB shifted first
** polynomial = x^8 + x^2 + x^1 + x^0
** init = 0
*/
extern FLAC__byte const FLAC__crc8_table[256];
#define FLAC__CRC8_UPDATE(data, crc) (crc) = FLAC__crc8_table[(crc) ^ (data)];
void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc);
void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc);
FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len);
/* 16 bit CRC generator, MSB shifted first
** polynomial = x^16 + x^15 + x^2 + x^0
** init = 0
*/
extern unsigned FLAC__crc16_table[256];
#define FLAC__CRC16_UPDATE(data, crc) (((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]))
/* this alternate may be faster on some systems/compilers */
#if 0
#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) & 0xffff)
#endif
unsigned FLAC__crc16(const FLAC__byte *data, unsigned len);
#endif

+ 97
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/fixed.h View File

@@ -0,0 +1,97 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__FIXED_H
#define FLAC__PRIVATE__FIXED_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "float.h"
#include "format.h"
/*
* FLAC__fixed_compute_best_predictor()
* --------------------------------------------------------------------
* Compute the best fixed predictor and the expected bits-per-sample
* of the residual signal for each order. The _wide() version uses
* 64-bit integers which is statistically necessary when bits-per-
* sample + log2(blocksize) > 30
*
* IN data[0,data_len-1]
* IN data_len
* OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
*/
#ifndef FLAC__INTEGER_ONLY_LIBRARY
unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
# ifndef FLAC__NO_ASM
# ifdef FLAC__CPU_IA32
# ifdef FLAC__HAS_NASM
unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
# endif
# endif
# endif
unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
#else
unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
#endif
/*
* FLAC__fixed_compute_residual()
* --------------------------------------------------------------------
* Compute the residual signal obtained from sutracting the predicted
* signal from the original.
*
* IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
* IN data_len length of original signal
* IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
* OUT residual[0,data_len-1] residual signal
*/
void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]);
/*
* FLAC__fixed_restore_signal()
* --------------------------------------------------------------------
* Restore the original signal by summing the residual and the
* predictor.
*
* IN residual[0,data_len-1] residual signal
* IN data_len length of original signal
* IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
* *** IMPORTANT: the caller must pass in the historical samples:
* IN data[-order,-1] previously-reconstructed historical samples
* OUT data[0,data_len-1] original signal
*/
void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]);
#endif

+ 97
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/float.h View File

@@ -0,0 +1,97 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__FLOAT_H
#define FLAC__PRIVATE__FLOAT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "../../../ordinals.h"
/*
* These typedefs make it easier to ensure that integer versions of
* the library really only contain integer operations. All the code
* in libFLAC should use FLAC__float and FLAC__double in place of
* float and double, and be protected by checks of the macro
* FLAC__INTEGER_ONLY_LIBRARY.
*
* FLAC__real is the basic floating point type used in LPC analysis.
*/
#ifndef FLAC__INTEGER_ONLY_LIBRARY
typedef double FLAC__double;
typedef float FLAC__float;
/*
* WATCHOUT: changing FLAC__real will change the signatures of many
* functions that have assembly language equivalents and break them.
*/
typedef float FLAC__real;
#else
/*
* The convention for FLAC__fixedpoint is to use the upper 16 bits
* for the integer part and lower 16 bits for the fractional part.
*/
typedef FLAC__int32 FLAC__fixedpoint;
extern const FLAC__fixedpoint FLAC__FP_ZERO;
extern const FLAC__fixedpoint FLAC__FP_ONE_HALF;
extern const FLAC__fixedpoint FLAC__FP_ONE;
extern const FLAC__fixedpoint FLAC__FP_LN2;
extern const FLAC__fixedpoint FLAC__FP_E;
#define FLAC__fixedpoint_trunc(x) ((x)>>16)
#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) )
#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) )
/*
* FLAC__fixedpoint_log2()
* --------------------------------------------------------------------
* Returns the base-2 logarithm of the fixed-point number 'x' using an
* algorithm by Knuth for x >= 1.0
*
* 'fracbits' is the number of fractional bits of 'x'. 'fracbits' must
* be < 32 and evenly divisible by 4 (0 is OK but not very precise).
*
* 'precision' roughly limits the number of iterations that are done;
* use (unsigned)(-1) for maximum precision.
*
* If 'x' is less than one -- that is, x < (1<<fracbits) -- then this
* function will punt and return 0.
*
* The return value will also have 'fracbits' fractional bits.
*/
FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision);
#endif
#endif

+ 44
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/format.h View File

@@ -0,0 +1,44 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__FORMAT_H
#define FLAC__PRIVATE__FORMAT_H
#include "../../../format.h"
unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order);
unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize);
unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order);
void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order);
#endif

+ 214
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/lpc.h View File

@@ -0,0 +1,214 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__LPC_H
#define FLAC__PRIVATE__LPC_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "float.h"
#include "../../../format.h"
#ifndef FLAC__INTEGER_ONLY_LIBRARY
/*
* FLAC__lpc_window_data()
* --------------------------------------------------------------------
* Applies the given window to the data.
* OPT: asm implementation
*
* IN in[0,data_len-1]
* IN window[0,data_len-1]
* OUT out[0,lag-1]
* IN data_len
*/
void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len);
/*
* FLAC__lpc_compute_autocorrelation()
* --------------------------------------------------------------------
* Compute the autocorrelation for lags between 0 and lag-1.
* Assumes data[] outside of [0,data_len-1] == 0.
* Asserts that lag > 0.
*
* IN data[0,data_len-1]
* IN data_len
* IN 0 < lag <= data_len
* OUT autoc[0,lag-1]
*/
void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
#ifndef FLAC__NO_ASM
# ifdef FLAC__CPU_IA32
# ifdef FLAC__HAS_NASM
void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
# endif
# endif
#endif
/*
* FLAC__lpc_compute_lp_coefficients()
* --------------------------------------------------------------------
* Computes LP coefficients for orders 1..max_order.
* Do not call if autoc[0] == 0.0. This means the signal is zero
* and there is no point in calculating a predictor.
*
* IN autoc[0,max_order] autocorrelation values
* IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute
* OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
* *** IMPORTANT:
* *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
* OUT error[0,max_order-1] error for each order (more
* specifically, the variance of
* the error signal times # of
* samples in the signal)
*
* Example: if max_order is 9, the LP coefficients for order 9 will be
* in lp_coeff[8][0,8], the LP coefficients for order 8 will be
* in lp_coeff[7][0,7], etc.
*/
void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]);
/*
* FLAC__lpc_quantize_coefficients()
* --------------------------------------------------------------------
* Quantizes the LP coefficients. NOTE: precision + bits_per_sample
* must be less than 32 (sizeof(FLAC__int32)*8).
*
* IN lp_coeff[0,order-1] LP coefficients
* IN order LP order
* IN FLAC__MIN_QLP_COEFF_PRECISION < precision
* desired precision (in bits, including sign
* bit) of largest coefficient
* OUT qlp_coeff[0,order-1] quantized coefficients
* OUT shift # of bits to shift right to get approximated
* LP coefficients. NOTE: could be negative.
* RETURN 0 => quantization OK
* 1 => coefficients require too much shifting for *shift to
* fit in the LPC subframe header. 'shift' is unset.
* 2 => coefficients are all zero, which is bad. 'shift' is
* unset.
*/
int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift);
/*
* FLAC__lpc_compute_residual_from_qlp_coefficients()
* --------------------------------------------------------------------
* Compute the residual signal obtained from sutracting the predicted
* signal from the original.
*
* IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
* IN data_len length of original signal
* IN qlp_coeff[0,order-1] quantized LP coefficients
* IN order > 0 LP order
* IN lp_quantization quantization of LP coefficients in bits
* OUT residual[0,data_len-1] residual signal
*/
void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
#ifndef FLAC__NO_ASM
# ifdef FLAC__CPU_IA32
# ifdef FLAC__HAS_NASM
void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
# endif
# endif
#endif
#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
/*
* FLAC__lpc_restore_signal()
* --------------------------------------------------------------------
* Restore the original signal by summing the residual and the
* predictor.
*
* IN residual[0,data_len-1] residual signal
* IN data_len length of original signal
* IN qlp_coeff[0,order-1] quantized LP coefficients
* IN order > 0 LP order
* IN lp_quantization quantization of LP coefficients in bits
* *** IMPORTANT: the caller must pass in the historical samples:
* IN data[-order,-1] previously-reconstructed historical samples
* OUT data[0,data_len-1] original signal
*/
void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
#ifndef FLAC__NO_ASM
# ifdef FLAC__CPU_IA32
# ifdef FLAC__HAS_NASM
void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
# endif /* FLAC__HAS_NASM */
# elif defined FLAC__CPU_PPC
void FLAC__lpc_restore_signal_asm_ppc_altivec_16(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
# endif/* FLAC__CPU_IA32 || FLAC__CPU_PPC */
#endif /* FLAC__NO_ASM */
#ifndef FLAC__INTEGER_ONLY_LIBRARY
/*
* FLAC__lpc_compute_expected_bits_per_residual_sample()
* --------------------------------------------------------------------
* Compute the expected number of bits per residual signal sample
* based on the LP error (which is related to the residual variance).
*
* IN lpc_error >= 0.0 error returned from calculating LP coefficients
* IN total_samples > 0 # of samples in residual signal
* RETURN expected bits per sample
*/
FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples);
FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale);
/*
* FLAC__lpc_compute_best_order()
* --------------------------------------------------------------------
* Compute the best order from the array of signal errors returned
* during coefficient computation.
*
* IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients
* IN max_order > 0 max LP order
* IN total_samples > 0 # of samples in residual signal
* IN overhead_bits_per_order # of bits overhead for each increased LP order
* (includes warmup sample size and quantized LP coefficient)
* RETURN [1,max_order] best order
*/
unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order);
#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
#endif

+ 44
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/md5.h View File

@@ -0,0 +1,44 @@
#ifndef FLAC__PRIVATE__MD5_H
#define FLAC__PRIVATE__MD5_H
/*
* This is the header file for the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*
* Changed so as no longer to depend on Colin Plumb's `usual.h'
* header definitions; now uses stuff from dpkg's config.h
* - Ian Jackson <ijackson@nyx.cs.du.edu>.
* Still in the public domain.
*
* Josh Coalson: made some changes to integrate with libFLAC.
* Still in the public domain, with no warranty.
*/
#include "../../../ordinals.h"
typedef struct {
FLAC__uint32 in[16];
FLAC__uint32 buf[4];
FLAC__uint32 bytes[2];
FLAC__byte *internal_buf;
size_t capacity;
} FLAC__MD5Context;
void FLAC__MD5Init(FLAC__MD5Context *context);
void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
#endif

+ 56
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/memory.h View File

@@ -0,0 +1,56 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__MEMORY_H
#define FLAC__PRIVATE__MEMORY_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h> /* for size_t */
#include "float.h"
#include "../../../ordinals.h" /* for FLAC__bool */
/* Returns the unaligned address returned by malloc.
* Use free() on this address to deallocate.
*/
void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address);
FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer);
#ifndef FLAC__INTEGER_ONLY_LIBRARY
FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
#endif
#endif

+ 45
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/metadata.h View File

@@ -0,0 +1,45 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__METADATA_H
#define FLAC__PRIVATE__METADATA_H
#include "metadata.h"
/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
* be a consistent state (e.g. PICTURE) or equivalent to the initial
* state after FLAC__metadata_object_new()
*/
void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
#endif

+ 45
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/stream_encoder_framing.h View File

@@ -0,0 +1,45 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
#include "../../../format.h"
#include "bitwriter.h"
FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw);
FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw);
FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
#endif

+ 71
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/private/window.h View File

@@ -0,0 +1,71 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PRIVATE__WINDOW_H
#define FLAC__PRIVATE__WINDOW_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "float.h"
#include "../../../format.h"
#ifndef FLAC__INTEGER_ONLY_LIBRARY
/*
* FLAC__window_*()
* --------------------------------------------------------------------
* Calculates window coefficients according to different apodization
* functions.
*
* OUT window[0,L-1]
* IN L (number of points in window)
*/
void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */
void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
#endif

+ 38
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/protected/all.h View File

@@ -0,0 +1,38 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PROTECTED__ALL_H
#define FLAC__PROTECTED__ALL_H
#include "stream_decoder.h"
#include "stream_encoder.h"
#endif

+ 58
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/protected/stream_decoder.h View File

@@ -0,0 +1,58 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PROTECTED__STREAM_DECODER_H
#define FLAC__PROTECTED__STREAM_DECODER_H
#include "../../../stream_decoder.h"
#if FLAC__HAS_OGG
#include "include/private/ogg_decoder_aspect.h"
#endif
typedef struct FLAC__StreamDecoderProtected {
FLAC__StreamDecoderState state;
unsigned channels;
FLAC__ChannelAssignment channel_assignment;
unsigned bits_per_sample;
unsigned sample_rate; /* in Hz */
unsigned blocksize; /* in samples (per channel) */
FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */
#if FLAC__HAS_OGG
FLAC__OggDecoderAspect ogg_decoder_aspect;
#endif
} FLAC__StreamDecoderProtected;
/*
* return the number of input bytes consumed
*/
unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
#endif

+ 110
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/include/protected/stream_encoder.h View File

@@ -0,0 +1,110 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__PROTECTED__STREAM_ENCODER_H
#define FLAC__PROTECTED__STREAM_ENCODER_H
#include "../../../stream_encoder.h"
#if FLAC__HAS_OGG
#include "private/ogg_encoder_aspect.h"
#endif
#ifndef FLAC__INTEGER_ONLY_LIBRARY
#include "../private/float.h"
#define FLAC__MAX_APODIZATION_FUNCTIONS 32
typedef enum {
FLAC__APODIZATION_BARTLETT,
FLAC__APODIZATION_BARTLETT_HANN,
FLAC__APODIZATION_BLACKMAN,
FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE,
FLAC__APODIZATION_CONNES,
FLAC__APODIZATION_FLATTOP,
FLAC__APODIZATION_GAUSS,
FLAC__APODIZATION_HAMMING,
FLAC__APODIZATION_HANN,
FLAC__APODIZATION_KAISER_BESSEL,
FLAC__APODIZATION_NUTTALL,
FLAC__APODIZATION_RECTANGLE,
FLAC__APODIZATION_TRIANGLE,
FLAC__APODIZATION_TUKEY,
FLAC__APODIZATION_WELCH
} FLAC__ApodizationFunction;
typedef struct {
FLAC__ApodizationFunction type;
union {
struct {
FLAC__real stddev;
} gauss;
struct {
FLAC__real p;
} tukey;
} parameters;
} FLAC__ApodizationSpecification;
#endif // #ifndef FLAC__INTEGER_ONLY_LIBRARY
typedef struct FLAC__StreamEncoderProtected {
FLAC__StreamEncoderState state;
FLAC__bool verify;
FLAC__bool streamable_subset;
FLAC__bool do_md5;
FLAC__bool do_mid_side_stereo;
FLAC__bool loose_mid_side_stereo;
unsigned channels;
unsigned bits_per_sample;
unsigned sample_rate;
unsigned blocksize;
#ifndef FLAC__INTEGER_ONLY_LIBRARY
unsigned num_apodizations;
FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS];
#endif
unsigned max_lpc_order;
unsigned qlp_coeff_precision;
FLAC__bool do_qlp_coeff_prec_search;
FLAC__bool do_exhaustive_model_search;
FLAC__bool do_escape_coding;
unsigned min_residual_partition_order;
unsigned max_residual_partition_order;
unsigned rice_parameter_search_dist;
FLAC__uint64 total_samples_estimate;
FLAC__StreamMetadata **metadata;
unsigned num_metadata_blocks;
FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset;
#if FLAC__HAS_OGG
FLAC__OggEncoderAspect ogg_encoder_aspect;
#endif
} FLAC__StreamEncoderProtected;
#endif

+ 1376
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/lpc_flac.c
File diff suppressed because it is too large
View File


+ 425
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/md5.c View File

@@ -0,0 +1,425 @@
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h> /* for malloc() */
#include <string.h> /* for memcpy() */
#include "include/private/md5.h"
#include "../alloc.h"
#ifndef FLaC__INLINE
#define FLaC__INLINE
#endif
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*
* Changed so as no longer to depend on Colin Plumb's `usual.h' header
* definitions; now uses stuff from dpkg's config.h.
* - Ian Jackson <ijackson@nyx.cs.du.edu>.
* Still in the public domain.
*
* Josh Coalson: made some changes to integrate with libFLAC.
* Still in the public domain.
*/
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f,w,x,y,z,in,s) \
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
{
register FLAC__uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
#if WORDS_BIGENDIAN
//@@@@@@ OPT: use bswap/intrinsics
static void byteSwap(FLAC__uint32 *buf, unsigned words)
{
register FLAC__uint32 x;
do {
x = *buf;
x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
*buf++ = (x >> 16) | (x << 16);
} while (--words);
}
static void byteSwapX16(FLAC__uint32 *buf)
{
register FLAC__uint32 x;
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf = (x >> 16) | (x << 16);
}
#else
#define byteSwap(buf, words)
#define byteSwapX16(buf)
#endif
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, unsigned len)
{
FLAC__uint32 t;
/* Update byte count */
t = ctx->bytes[0];
if ((ctx->bytes[0] = t + len) < t)
ctx->bytes[1]++; /* Carry from low to high */
t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
if (t > len) {
memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len);
return;
}
/* First chunk is an odd size */
memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
byteSwapX16(ctx->in);
FLAC__MD5Transform(ctx->buf, ctx->in);
buf += t;
len -= t;
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteSwapX16(ctx->in);
FLAC__MD5Transform(ctx->buf, ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void FLAC__MD5Init(FLAC__MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bytes[0] = 0;
ctx->bytes[1] = 0;
ctx->internal_buf = 0;
ctx->capacity = 0;
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
{
int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
FLAC__byte *p = (FLAC__byte *)ctx->in + count;
/* Set the first char of padding to 0x80. There is always room. */
*p++ = 0x80;
/* Bytes of padding needed to make 56 bytes (-8..55) */
count = 56 - 1 - count;
if (count < 0) { /* Padding forces an extra block */
memset(p, 0, count + 8);
byteSwapX16(ctx->in);
FLAC__MD5Transform(ctx->buf, ctx->in);
p = (FLAC__byte *)ctx->in;
count = 56;
}
memset(p, 0, count);
byteSwap(ctx->in, 14);
/* Append length in bits and transform */
ctx->in[14] = ctx->bytes[0] << 3;
ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
FLAC__MD5Transform(ctx->buf, ctx->in);
byteSwap(ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
//memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
if(0 != ctx->internal_buf) {
free(ctx->internal_buf);
ctx->internal_buf = 0;
ctx->capacity = 0;
}
}
/*
* Convert the incoming audio signal to a byte stream
*/
static void format_input_(FLAC__byte *buf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
{
unsigned channel, sample;
register FLAC__int32 a_word;
register FLAC__byte *buf_ = buf;
#if WORDS_BIGENDIAN
#else
if(channels == 2 && bytes_per_sample == 2) {
FLAC__int16 *buf1_ = ((FLAC__int16*)buf_) + 1;
memcpy(buf_, signal[0], sizeof(FLAC__int32) * samples);
for(sample = 0; sample < samples; sample++, buf1_+=2)
*buf1_ = (FLAC__int16)signal[1][sample];
}
else if(channels == 1 && bytes_per_sample == 2) {
FLAC__int16 *buf1_ = (FLAC__int16*)buf_;
for(sample = 0; sample < samples; sample++)
*buf1_++ = (FLAC__int16)signal[0][sample];
}
else
#endif
if(bytes_per_sample == 2) {
if(channels == 2) {
for(sample = 0; sample < samples; sample++) {
a_word = signal[0][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
a_word = signal[1][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
}
}
else if(channels == 1) {
for(sample = 0; sample < samples; sample++) {
a_word = signal[0][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
}
}
else {
for(sample = 0; sample < samples; sample++) {
for(channel = 0; channel < channels; channel++) {
a_word = signal[channel][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
}
}
}
}
else if(bytes_per_sample == 3) {
if(channels == 2) {
for(sample = 0; sample < samples; sample++) {
a_word = signal[0][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
a_word = signal[1][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
}
}
else if(channels == 1) {
for(sample = 0; sample < samples; sample++) {
a_word = signal[0][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
}
}
else {
for(sample = 0; sample < samples; sample++) {
for(channel = 0; channel < channels; channel++) {
a_word = signal[channel][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
}
}
}
}
else if(bytes_per_sample == 1) {
if(channels == 2) {
for(sample = 0; sample < samples; sample++) {
a_word = signal[0][sample];
*buf_++ = (FLAC__byte)a_word;
a_word = signal[1][sample];
*buf_++ = (FLAC__byte)a_word;
}
}
else if(channels == 1) {
for(sample = 0; sample < samples; sample++) {
a_word = signal[0][sample];
*buf_++ = (FLAC__byte)a_word;
}
}
else {
for(sample = 0; sample < samples; sample++) {
for(channel = 0; channel < channels; channel++) {
a_word = signal[channel][sample];
*buf_++ = (FLAC__byte)a_word;
}
}
}
}
else { /* bytes_per_sample == 4, maybe optimize more later */
for(sample = 0; sample < samples; sample++) {
for(channel = 0; channel < channels; channel++) {
a_word = signal[channel][sample];
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
*buf_++ = (FLAC__byte)a_word;
}
}
}
}
/*
* Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
*/
FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
{
const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample;
/* overflow check */
if((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample)
return false;
if((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples)
return false;
if(ctx->capacity < bytes_needed) {
FLAC__byte *tmp = (FLAC__byte*)realloc(ctx->internal_buf, bytes_needed);
if(0 == tmp) {
free(ctx->internal_buf);
if(0 == (ctx->internal_buf = (FLAC__byte*)safe_malloc_(bytes_needed)))
return false;
}
ctx->internal_buf = tmp;
ctx->capacity = bytes_needed;
}
format_input_(ctx->internal_buf, signal, channels, samples, bytes_per_sample);
FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed);
return true;
}

+ 206
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/memory.c View File

@@ -0,0 +1,206 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "include/private/memory.h"
#include "../assert.h"
#include "../alloc.h"
void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
{
void *x;
FLAC__ASSERT(0 != aligned_address);
#ifdef FLAC__ALIGN_MALLOC_DATA
/* align on 32-byte (256-bit) boundary */
x = safe_malloc_add_2op_(bytes, /*+*/31);
#ifdef SIZEOF_VOIDP
#if SIZEOF_VOIDP == 4
/* could do *aligned_address = x + ((unsigned) (32 - (((unsigned)x) & 31))) & 31; */
*aligned_address = (void*)(((unsigned)x + 31) & -32);
#elif SIZEOF_VOIDP == 8
*aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32)));
#else
# error Unsupported sizeof(void*)
#endif
#else
/* there's got to be a better way to do this right for all archs */
if(sizeof(void*) == sizeof(unsigned))
*aligned_address = (void*)(((unsigned)x + 31) & -32);
else if(sizeof(void*) == sizeof(FLAC__uint64))
*aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32)));
else
return 0;
#endif
#else
x = safe_malloc_(bytes);
*aligned_address = x;
#endif
return x;
}
FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer)
{
FLAC__int32 *pu; /* unaligned pointer */
union { /* union needed to comply with C99 pointer aliasing rules */
FLAC__int32 *pa; /* aligned pointer */
void *pv; /* aligned pointer alias */
} u;
FLAC__ASSERT(elements > 0);
FLAC__ASSERT(0 != unaligned_pointer);
FLAC__ASSERT(0 != aligned_pointer);
FLAC__ASSERT(unaligned_pointer != aligned_pointer);
pu = (FLAC__int32*)FLAC__memory_alloc_aligned(sizeof(*pu) * (size_t)elements, &u.pv);
if(0 == pu) {
return false;
}
else {
if(*unaligned_pointer != 0)
free(*unaligned_pointer);
*unaligned_pointer = pu;
*aligned_pointer = u.pa;
return true;
}
}
FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
{
FLAC__uint32 *pu; /* unaligned pointer */
union { /* union needed to comply with C99 pointer aliasing rules */
FLAC__uint32 *pa; /* aligned pointer */
void *pv; /* aligned pointer alias */
} u;
FLAC__ASSERT(elements > 0);
FLAC__ASSERT(0 != unaligned_pointer);
FLAC__ASSERT(0 != aligned_pointer);
FLAC__ASSERT(unaligned_pointer != aligned_pointer);
pu = (FLAC__uint32*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
if(0 == pu) {
return false;
}
else {
if(*unaligned_pointer != 0)
free(*unaligned_pointer);
*unaligned_pointer = pu;
*aligned_pointer = u.pa;
return true;
}
}
FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
{
FLAC__uint64 *pu; /* unaligned pointer */
union { /* union needed to comply with C99 pointer aliasing rules */
FLAC__uint64 *pa; /* aligned pointer */
void *pv; /* aligned pointer alias */
} u;
FLAC__ASSERT(elements > 0);
FLAC__ASSERT(0 != unaligned_pointer);
FLAC__ASSERT(0 != aligned_pointer);
FLAC__ASSERT(unaligned_pointer != aligned_pointer);
pu = (FLAC__uint64*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
if(0 == pu) {
return false;
}
else {
if(*unaligned_pointer != 0)
free(*unaligned_pointer);
*unaligned_pointer = pu;
*aligned_pointer = u.pa;
return true;
}
}
FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer)
{
unsigned *pu; /* unaligned pointer */
union { /* union needed to comply with C99 pointer aliasing rules */
unsigned *pa; /* aligned pointer */
void *pv; /* aligned pointer alias */
} u;
FLAC__ASSERT(elements > 0);
FLAC__ASSERT(0 != unaligned_pointer);
FLAC__ASSERT(0 != aligned_pointer);
FLAC__ASSERT(unaligned_pointer != aligned_pointer);
pu = (unsigned*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
if(0 == pu) {
return false;
}
else {
if(*unaligned_pointer != 0)
free(*unaligned_pointer);
*unaligned_pointer = pu;
*aligned_pointer = u.pa;
return true;
}
}
#ifndef FLAC__INTEGER_ONLY_LIBRARY
FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
{
FLAC__real *pu; /* unaligned pointer */
union { /* union needed to comply with C99 pointer aliasing rules */
FLAC__real *pa; /* aligned pointer */
void *pv; /* aligned pointer alias */
} u;
FLAC__ASSERT(elements > 0);
FLAC__ASSERT(0 != unaligned_pointer);
FLAC__ASSERT(0 != aligned_pointer);
FLAC__ASSERT(unaligned_pointer != aligned_pointer);
pu = (FLAC__real*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
if(0 == pu) {
return false;
}
else {
if(*unaligned_pointer != 0)
free(*unaligned_pointer);
*unaligned_pointer = pu;
*aligned_pointer = u.pa;
return true;
}
}
#endif

+ 3384
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/stream_decoder.c
File diff suppressed because it is too large
View File


+ 4362
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/stream_encoder.c
File diff suppressed because it is too large
View File


+ 553
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/stream_encoder_framing.c View File

@@ -0,0 +1,553 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h> /* for strlen() */
#include "include/private/stream_encoder_framing.h"
#include "include/private/crc.h"
#include "../assert.h"
#ifdef max
#undef max
#endif
#define max(x,y) ((x)>(y)?(x):(y))
static FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method);
static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended);
FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw)
{
unsigned i, j;
const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN))
return false;
/*
* First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string
*/
i = metadata->length;
if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry);
i -= metadata->data.vorbis_comment.vendor_string.length;
i += vendor_string_length;
}
FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
if(!FLAC__bitwriter_write_raw_uint32(bw, i, FLAC__STREAM_METADATA_LENGTH_LEN))
return false;
switch(metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN));
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN))
return false;
FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN));
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
return false;
FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
return false;
FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
return false;
FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate));
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
return false;
FLAC__ASSERT(metadata->data.stream_info.channels > 0);
FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN));
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
return false;
FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0);
FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN));
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
return false;
if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16))
return false;
break;
case FLAC__METADATA_TYPE_PADDING:
if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8))
return false;
break;
case FLAC__METADATA_TYPE_APPLICATION:
if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))
return false;
if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)))
return false;
break;
case FLAC__METADATA_TYPE_SEEKTABLE:
for(i = 0; i < metadata->data.seek_table.num_points; i++) {
if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
return false;
}
break;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length))
return false;
if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length))
return false;
if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.num_comments))
return false;
for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) {
if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length))
return false;
if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length))
return false;
}
break;
case FLAC__METADATA_TYPE_CUESHEET:
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
return false;
if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
return false;
if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
return false;
for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) {
const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i;
if(!FLAC__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
return false;
FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
return false;
if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
return false;
for(j = 0; j < track->num_indices; j++) {
const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
if(!FLAC__bitwriter_write_raw_uint64(bw, index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, index->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
return false;
if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
return false;
}
}
break;
case FLAC__METADATA_TYPE_PICTURE:
{
size_t len;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
return false;
len = strlen(metadata->data.picture.mime_type);
if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
return false;
if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len))
return false;
len = strlen((const char *)metadata->data.picture.description);
if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
return false;
if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
return false;
if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length))
return false;
}
break;
default:
if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length))
return false;
break;
}
FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
return true;
}
FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw)
{
unsigned u, blocksize_hint, sample_rate_hint;
FLAC__byte crc;
FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, (header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)? 0 : 1, FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN))
return false;
FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE);
/* when this assertion holds true, any legal blocksize can be expressed in the frame header */
FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u);
blocksize_hint = 0;
switch(header->blocksize) {
case 192: u = 1; break;
case 576: u = 2; break;
case 1152: u = 3; break;
case 2304: u = 4; break;
case 4608: u = 5; break;
case 256: u = 8; break;
case 512: u = 9; break;
case 1024: u = 10; break;
case 2048: u = 11; break;
case 4096: u = 12; break;
case 8192: u = 13; break;
case 16384: u = 14; break;
case 32768: u = 15; break;
default:
if(header->blocksize <= 0x100)
blocksize_hint = u = 6;
else
blocksize_hint = u = 7;
break;
}
if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN))
return false;
FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate));
sample_rate_hint = 0;
switch(header->sample_rate) {
case 88200: u = 1; break;
case 176400: u = 2; break;
case 192000: u = 3; break;
case 8000: u = 4; break;
case 16000: u = 5; break;
case 22050: u = 6; break;
case 24000: u = 7; break;
case 32000: u = 8; break;
case 44100: u = 9; break;
case 48000: u = 10; break;
case 96000: u = 11; break;
default:
if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0)
sample_rate_hint = u = 12;
else if(header->sample_rate % 10 == 0)
sample_rate_hint = u = 14;
else if(header->sample_rate <= 0xffff)
sample_rate_hint = u = 13;
else
u = 0;
break;
}
if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN))
return false;
FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS);
switch(header->channel_assignment) {
case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
u = header->channels - 1;
break;
case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
FLAC__ASSERT(header->channels == 2);
u = 8;
break;
case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
FLAC__ASSERT(header->channels == 2);
u = 9;
break;
case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
FLAC__ASSERT(header->channels == 2);
u = 10;
break;
default:
FLAC__ASSERT(0);
}
if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN))
return false;
FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN));
switch(header->bits_per_sample) {
case 8 : u = 1; break;
case 12: u = 2; break;
case 16: u = 4; break;
case 20: u = 5; break;
case 24: u = 6; break;
default: u = 0; break;
}
if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN))
return false;
if(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number))
return false;
}
else {
if(!FLAC__bitwriter_write_utf8_uint64(bw, header->number.sample_number))
return false;
}
if(blocksize_hint)
if(!FLAC__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16))
return false;
switch(sample_rate_hint) {
case 12:
if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8))
return false;
break;
case 13:
if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16))
return false;
break;
case 14:
if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16))
return false;
break;
}
/* write the CRC */
if(!FLAC__bitwriter_get_write_crc8(bw, &crc))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, crc, FLAC__FRAME_HEADER_CRC_LEN))
return false;
return true;
}
FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
{
FLAC__bool ok;
ok =
FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) &&
(wasted_bits? FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) &&
FLAC__bitwriter_write_raw_int32(bw, subframe->value, subframe_bps)
;
return ok;
}
FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
{
unsigned i;
if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
return false;
if(wasted_bits)
if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
return false;
for(i = 0; i < subframe->order; i++)
if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
return false;
if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method))
return false;
switch(subframe->entropy_coding_method.type) {
case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
if(!add_residual_partitioned_rice_(
bw,
subframe->residual,
residual_samples,
subframe->order,
subframe->entropy_coding_method.data.partitioned_rice.contents->parameters,
subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits,
subframe->entropy_coding_method.data.partitioned_rice.order,
/*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2
))
return false;
break;
default:
FLAC__ASSERT(0);
}
return true;
}
FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
{
unsigned i;
if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
return false;
if(wasted_bits)
if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
return false;
for(i = 0; i < subframe->order; i++)
if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
return false;
if(!FLAC__bitwriter_write_raw_int32(bw, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
return false;
for(i = 0; i < subframe->order; i++)
if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision))
return false;
if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method))
return false;
switch(subframe->entropy_coding_method.type) {
case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
if(!add_residual_partitioned_rice_(
bw,
subframe->residual,
residual_samples,
subframe->order,
subframe->entropy_coding_method.data.partitioned_rice.contents->parameters,
subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits,
subframe->entropy_coding_method.data.partitioned_rice.order,
/*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2
))
return false;
break;
default:
FLAC__ASSERT(0);
}
return true;
}
FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
{
unsigned i;
const FLAC__int32 *signal = subframe->data;
if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
return false;
if(wasted_bits)
if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
return false;
for(i = 0; i < samples; i++)
if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps))
return false;
return true;
}
FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method)
{
if(!FLAC__bitwriter_write_raw_uint32(bw, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
return false;
switch(method->type) {
case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
return false;
break;
default:
FLAC__ASSERT(0);
}
return true;
}
FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended)
{
const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
if(partition_order == 0) {
unsigned i;
if(raw_bits[0] == 0) {
if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], plen))
return false;
if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0]))
return false;
}
else {
FLAC__ASSERT(rice_parameters[0] == 0);
if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
return false;
for(i = 0; i < residual_samples; i++) {
if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0]))
return false;
}
}
return true;
}
else {
unsigned i, j, k = 0, k_last = 0;
unsigned partition_samples;
const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order;
for(i = 0; i < (1u<<partition_order); i++) {
partition_samples = default_partition_samples;
if(i == 0)
partition_samples -= predictor_order;
k += partition_samples;
if(raw_bits[i] == 0) {
if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[i], plen))
return false;
if(!FLAC__bitwriter_write_rice_signed_block(bw, residual+k_last, k-k_last, rice_parameters[i]))
return false;
}
else {
if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen))
return false;
if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
return false;
for(j = k_last; j < k; j++) {
if(!FLAC__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i]))
return false;
}
}
k_last = k;
}
return true;
}
}

+ 225
- 0
source/modules/juce_audio_formats/codecs/flac/libFLAC/window_flac.c View File

@@ -0,0 +1,225 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h>
#include "../assert.h"
#include "../format.h"
#include "include/private/window.h"
#ifndef FLAC__INTEGER_ONLY_LIBRARY
#ifndef M_PI
/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
#define M_PI 3.14159265358979323846
#endif
void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
if (L & 1) {
for (n = 0; n <= N/2; n++)
window[n] = 2.0f * n / (float)N;
for (; n <= N; n++)
window[n] = 2.0f - 2.0f * n / (float)N;
}
else {
for (n = 0; n <= L/2-1; n++)
window[n] = 2.0f * n / (float)N;
for (; n <= N; n++)
window[n] = 2.0f - 2.0f * (N-n) / (float)N;
}
}
void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N+0.5f) + 0.38f * cos(2.0f * M_PI * ((float)n/(float)N+0.5f)));
}
void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N));
}
/* 4-term -92dB side-lobe */
void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n <= N; n++)
window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N));
}
void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
const double N2 = (double)N / 2.;
FLAC__int32 n;
for (n = 0; n <= N; n++) {
double k = ((double)n - N2) / N2;
k = 1.0f - k * k;
window[n] = (FLAC__real)(k * k);
}
}
void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(1.0f - 1.93f * cos(2.0f * M_PI * n / N) + 1.29f * cos(4.0f * M_PI * n / N) - 0.388f * cos(6.0f * M_PI * n / N) + 0.0322f * cos(8.0f * M_PI * n / N));
}
void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev)
{
const FLAC__int32 N = L - 1;
const double N2 = (double)N / 2.;
FLAC__int32 n;
for (n = 0; n <= N; n++) {
const double k = ((double)n - N2) / (stddev * N2);
window[n] = (FLAC__real)exp(-0.5f * k * k);
}
}
void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N));
}
void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N));
}
void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N));
}
void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N));
}
void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L)
{
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = 1.0f;
}
void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L)
{
FLAC__int32 n;
if (L & 1) {
for (n = 1; n <= L+1/2; n++)
window[n-1] = 2.0f * n / ((float)L + 1.0f);
for (; n <= L; n++)
window[n-1] = - (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
}
else {
for (n = 1; n <= L/2; n++)
window[n-1] = 2.0f * n / (float)L;
for (; n <= L; n++)
window[n-1] = ((float)(2 * (L - n)) + 1.0f) / (float)L;
}
}
void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p)
{
if (p <= 0.0)
FLAC__window_rectangle(window, L);
else if (p >= 1.0)
FLAC__window_hann(window, L);
else {
const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1;
FLAC__int32 n;
/* start with rectangle... */
FLAC__window_rectangle(window, L);
/* ...replace ends with hann */
if (Np > 0) {
for (n = 0; n <= Np; n++) {
window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np));
window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np));
}
}
}
}
void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;
const double N2 = (double)N / 2.;
FLAC__int32 n;
for (n = 0; n <= N; n++) {
const double k = ((double)n - N2) / N2;
window[n] = (FLAC__real)(1.0f - k * k);
}
}
#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */

+ 2181
- 0
source/modules/juce_audio_formats/codecs/flac/metadata.h
File diff suppressed because it is too large
View File


+ 80
- 0
source/modules/juce_audio_formats/codecs/flac/ordinals.h View File

@@ -0,0 +1,80 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLAC__ORDINALS_H
#define FLAC__ORDINALS_H
#if !(defined(_MSC_VER) || defined(__BORLANDC__) || defined(__EMX__))
#include <inttypes.h>
#endif
typedef signed char FLAC__int8;
typedef unsigned char FLAC__uint8;
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int16 FLAC__int16;
typedef __int32 FLAC__int32;
typedef __int64 FLAC__int64;
typedef unsigned __int16 FLAC__uint16;
typedef unsigned __int32 FLAC__uint32;
typedef unsigned __int64 FLAC__uint64;
#elif defined(__EMX__)
typedef short FLAC__int16;
typedef long FLAC__int32;
typedef long long FLAC__int64;
typedef unsigned short FLAC__uint16;
typedef unsigned long FLAC__uint32;
typedef unsigned long long FLAC__uint64;
#else
typedef int16_t FLAC__int16;
typedef int32_t FLAC__int32;
typedef int64_t FLAC__int64;
typedef uint16_t FLAC__uint16;
typedef uint32_t FLAC__uint32;
typedef uint64_t FLAC__uint64;
#endif
typedef int FLAC__bool;
typedef FLAC__uint8 FLAC__byte;
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
#ifndef __cplusplus
#define true 1
#define false 0
#endif
#endif

+ 1559
- 0
source/modules/juce_audio_formats/codecs/flac/stream_decoder.h
File diff suppressed because it is too large
View File


+ 1768
- 0
source/modules/juce_audio_formats/codecs/flac/stream_encoder.h
File diff suppressed because it is too large
View File


+ 957
- 0
source/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp View File

@@ -0,0 +1,957 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
//==============================================================================
static const char* const aiffFormatName = "AIFF file";
static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 };
//==============================================================================
const char* const AiffAudioFormat::appleOneShot = "apple one shot";
const char* const AiffAudioFormat::appleRootSet = "apple root set";
const char* const AiffAudioFormat::appleRootNote = "apple root note";
const char* const AiffAudioFormat::appleBeats = "apple beats";
const char* const AiffAudioFormat::appleDenominator = "apple denominator";
const char* const AiffAudioFormat::appleNumerator = "apple numerator";
const char* const AiffAudioFormat::appleTag = "apple tag";
const char* const AiffAudioFormat::appleKey = "apple key";
//==============================================================================
namespace AiffFileHelpers
{
inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
#if JUCE_MSVC
#pragma pack (push, 1)
#endif
//==============================================================================
struct InstChunk
{
struct Loop
{
uint16 type; // these are different in AIFF and WAV
uint16 startIdentifier;
uint16 endIdentifier;
} JUCE_PACKED;
int8 baseNote;
int8 detune;
int8 lowNote;
int8 highNote;
int8 lowVelocity;
int8 highVelocity;
int16 gain;
Loop sustainLoop;
Loop releaseLoop;
void copyTo (StringPairArray& values) const
{
values.set ("MidiUnityNote", String (baseNote));
values.set ("Detune", String (detune));
values.set ("LowNote", String (lowNote));
values.set ("HighNote", String (highNote));
values.set ("LowVelocity", String (lowVelocity));
values.set ("HighVelocity", String (highVelocity));
values.set ("Gain", String ((int16) ByteOrder::swapIfLittleEndian ((uint16) gain)));
values.set ("NumSampleLoops", String (2)); // always 2 with AIFF, WAV can have more
values.set ("Loop0Type", String (ByteOrder::swapIfLittleEndian (sustainLoop.type)));
values.set ("Loop0StartIdentifier", String (ByteOrder::swapIfLittleEndian (sustainLoop.startIdentifier)));
values.set ("Loop0EndIdentifier", String (ByteOrder::swapIfLittleEndian (sustainLoop.endIdentifier)));
values.set ("Loop1Type", String (ByteOrder::swapIfLittleEndian (releaseLoop.type)));
values.set ("Loop1StartIdentifier", String (ByteOrder::swapIfLittleEndian (releaseLoop.startIdentifier)));
values.set ("Loop1EndIdentifier", String (ByteOrder::swapIfLittleEndian (releaseLoop.endIdentifier)));
}
static uint16 getValue16 (const StringPairArray& values, const char* name, const char* def)
{
return ByteOrder::swapIfLittleEndian ((uint16) values.getValue (name, def).getIntValue());
}
static int8 getValue8 (const StringPairArray& values, const char* name, const char* def)
{
return (int8) values.getValue (name, def).getIntValue();
}
static void create (MemoryBlock& block, const StringPairArray& values)
{
if (values.getAllKeys().contains ("MidiUnityNote", true))
{
block.setSize ((sizeof (InstChunk) + 3) & ~(size_t) 3, true);
InstChunk& inst = *static_cast <InstChunk*> (block.getData());
inst.baseNote = getValue8 (values, "MidiUnityNote", "60");
inst.detune = getValue8 (values, "Detune", "0");
inst.lowNote = getValue8 (values, "LowNote", "0");
inst.highNote = getValue8 (values, "HighNote", "127");
inst.lowVelocity = getValue8 (values, "LowVelocity", "1");
inst.highVelocity = getValue8 (values, "HighVelocity", "127");
inst.gain = (int16) getValue16 (values, "Gain", "0");
inst.sustainLoop.type = getValue16 (values, "Loop0Type", "0");
inst.sustainLoop.startIdentifier = getValue16 (values, "Loop0StartIdentifier", "0");
inst.sustainLoop.endIdentifier = getValue16 (values, "Loop0EndIdentifier", "0");
inst.releaseLoop.type = getValue16 (values, "Loop1Type", "0");
inst.releaseLoop.startIdentifier = getValue16 (values, "Loop1StartIdentifier", "0");
inst.releaseLoop.endIdentifier = getValue16 (values, "Loop1EndIdentifier", "0");
}
}
} JUCE_PACKED;
//==============================================================================
struct BASCChunk
{
enum Key
{
minor = 1,
major = 2,
neither = 3,
both = 4
};
BASCChunk (InputStream& input)
{
zerostruct (*this);
flags = (uint32) input.readIntBigEndian();
numBeats = (uint32) input.readIntBigEndian();
rootNote = (uint16) input.readShortBigEndian();
key = (uint16) input.readShortBigEndian();
timeSigNum = (uint16) input.readShortBigEndian();
timeSigDen = (uint16) input.readShortBigEndian();
oneShot = (uint16) input.readShortBigEndian();
input.read (unknown, sizeof (unknown));
}
void addToMetadata (StringPairArray& metadata) const
{
const bool rootNoteSet = rootNote != 0;
setBoolFlag (metadata, AiffAudioFormat::appleOneShot, oneShot == 2);
setBoolFlag (metadata, AiffAudioFormat::appleRootSet, rootNoteSet);
if (rootNoteSet)
metadata.set (AiffAudioFormat::appleRootNote, String (rootNote));
metadata.set (AiffAudioFormat::appleBeats, String (numBeats));
metadata.set (AiffAudioFormat::appleDenominator, String (timeSigDen));
metadata.set (AiffAudioFormat::appleNumerator, String (timeSigNum));
const char* keyString = nullptr;
switch (key)
{
case minor: keyString = "major"; break;
case major: keyString = "major"; break;
case neither: keyString = "neither"; break;
case both: keyString = "both"; break;
}
if (keyString != nullptr)
metadata.set (AiffAudioFormat::appleKey, keyString);
}
void setBoolFlag (StringPairArray& values, const char* name, bool shouldBeSet) const
{
values.set (name, shouldBeSet ? "1" : "0");
}
uint32 flags;
uint32 numBeats;
uint16 rootNote;
uint16 key;
uint16 timeSigNum;
uint16 timeSigDen;
uint16 oneShot;
uint8 unknown[66];
} JUCE_PACKED;
#if JUCE_MSVC
#pragma pack (pop)
#endif
//==============================================================================
static String readCATEChunk (InputStream& input, const uint32 length)
{
MemoryBlock mb;
input.skipNextBytes (4);
input.readIntoMemoryBlock (mb, (ssize_t) length - 4);
static const char* appleGenres[] =
{
"Rock/Blues",
"Electronic/Dance",
"Jazz",
"Urban",
"World/Ethnic",
"Cinematic/New Age",
"Orchestral",
"Country/Folk",
"Experimental",
"Other Genre",
nullptr
};
const StringArray genres (appleGenres);
StringArray tagsArray;
int bytesLeft = (int) mb.getSize();
const char* data = static_cast <const char*> (mb.getData());
while (bytesLeft > 0)
{
const String tag (CharPointer_UTF8 (data),
CharPointer_UTF8 (data + bytesLeft));
if (tag.isNotEmpty())
tagsArray.add (data);
const int numBytesInTag = genres.contains (tag) ? 118 : 50;
data += numBytesInTag;
bytesLeft -= numBytesInTag;
}
return tagsArray.joinIntoString (";");
}
//==============================================================================
namespace MarkChunk
{
static bool metaDataContainsZeroIdentifiers (const StringPairArray& values)
{
// (zero cue identifiers are valid for WAV but not for AIFF)
const String cueString ("Cue");
const String noteString ("CueNote");
const String identifierString ("Identifier");
const StringArray& keys = values.getAllKeys();
for (int i = 0; i < keys.size(); ++i)
{
const String key (keys[i]);
if (key.startsWith (noteString))
continue; // zero identifier IS valid in a COMT chunk
if (key.startsWith (cueString) && key.contains (identifierString))
{
const int value = values.getValue (key, "-1").getIntValue();
if (value == 0)
return true;
}
}
return false;
}
static void create (MemoryBlock& block, const StringPairArray& values)
{
const int numCues = values.getValue ("NumCuePoints", "0").getIntValue();
if (numCues > 0)
{
MemoryOutputStream out (block, false);
out.writeShortBigEndian ((short) numCues);
const int numCueLabels = values.getValue ("NumCueLabels", "0").getIntValue();
const int idOffset = metaDataContainsZeroIdentifiers (values) ? 1 : 0; // can't have zero IDs in AIFF
#if JUCE_DEBUG
Array<int> identifiers;
#endif
for (int i = 0; i < numCues; ++i)
{
const String prefixCue ("Cue" + String (i));
const int identifier = idOffset + values.getValue (prefixCue + "Identifier", "1").getIntValue();
#if JUCE_DEBUG
jassert (! identifiers.contains (identifier));
identifiers.add (identifier);
#endif
const int offset = values.getValue (prefixCue + "Offset", "0").getIntValue();
String label ("CueLabel" + String (i));
for (int labelIndex = 0; labelIndex < numCueLabels; ++labelIndex)
{
const String prefixLabel ("CueLabel" + String (labelIndex));
const int labelIdentifier = idOffset + values.getValue (prefixLabel + "Identifier", "1").getIntValue();
if (labelIdentifier == identifier)
{
label = values.getValue (prefixLabel + "Text", label);
break;
}
}
out.writeShortBigEndian ((short) identifier);
out.writeIntBigEndian (offset);
const size_t labelLength = jmin ((size_t) 254, label.getNumBytesAsUTF8()); // seems to need null terminator even though it's a pstring
out.writeByte ((char) labelLength + 1);
out.write (label.toUTF8(), labelLength);
out.writeByte (0);
}
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
}
}
}
//==============================================================================
namespace COMTChunk
{
static void create (MemoryBlock& block, const StringPairArray& values)
{
const int numNotes = values.getValue ("NumCueNotes", "0").getIntValue();
if (numNotes > 0)
{
MemoryOutputStream out (block, false);
out.writeShortBigEndian ((short) numNotes);
for (int i = 0; i < numNotes; ++i)
{
const String prefix ("CueNote" + String (i));
out.writeIntBigEndian (values.getValue (prefix + "TimeStamp", "0").getIntValue());
out.writeShortBigEndian ((short) values.getValue (prefix + "Identifier", "0").getIntValue());
const String comment (values.getValue (prefix + "Text", String::empty));
const size_t commentLength = jmin (comment.getNumBytesAsUTF8(), (size_t) 65534);
out.writeShortBigEndian ((short) commentLength + 1);
out.write (comment.toUTF8(), commentLength);
out.writeByte (0);
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
}
}
}
}
}
//==============================================================================
class AiffAudioFormatReader : public AudioFormatReader
{
public:
AiffAudioFormatReader (InputStream* in)
: AudioFormatReader (in, TRANS (aiffFormatName))
{
using namespace AiffFileHelpers;
if (input->readInt() == chunkName ("FORM"))
{
const int len = input->readIntBigEndian();
const int64 end = input->getPosition() + len;
const int nextType = input->readInt();
if (nextType == chunkName ("AIFF") || nextType == chunkName ("AIFC"))
{
bool hasGotVer = false;
bool hasGotData = false;
bool hasGotType = false;
while (input->getPosition() < end)
{
const int type = input->readInt();
const uint32 length = (uint32) input->readIntBigEndian();
const int64 chunkEnd = input->getPosition() + length;
if (type == chunkName ("FVER"))
{
hasGotVer = true;
const int ver = input->readIntBigEndian();
if (ver != 0 && ver != (int) 0xa2805140)
break;
}
else if (type == chunkName ("COMM"))
{
hasGotType = true;
numChannels = (unsigned int) input->readShortBigEndian();
lengthInSamples = input->readIntBigEndian();
bitsPerSample = (unsigned int) input->readShortBigEndian();
bytesPerFrame = (int) ((numChannels * bitsPerSample) >> 3);
unsigned char sampleRateBytes[10];
input->read (sampleRateBytes, 10);
const int byte0 = sampleRateBytes[0];
if ((byte0 & 0x80) != 0
|| byte0 <= 0x3F || byte0 > 0x40
|| (byte0 == 0x40 && sampleRateBytes[1] > 0x1C))
break;
unsigned int sampRate = ByteOrder::bigEndianInt (sampleRateBytes + 2);
sampRate >>= (16414 - ByteOrder::bigEndianShort (sampleRateBytes));
sampleRate = (int) sampRate;
if (length <= 18)
{
// some types don't have a chunk large enough to include a compression
// type, so assume it's just big-endian pcm
littleEndian = false;
}
else
{
const int compType = input->readInt();
if (compType == chunkName ("NONE") || compType == chunkName ("twos"))
{
littleEndian = false;
}
else if (compType == chunkName ("sowt"))
{
littleEndian = true;
}
else if (compType == chunkName ("fl32") || compType == chunkName ("FL32"))
{
littleEndian = false;
usesFloatingPointData = true;
}
else
{
sampleRate = 0;
break;
}
}
}
else if (type == chunkName ("SSND"))
{
hasGotData = true;
const int offset = input->readIntBigEndian();
dataChunkStart = input->getPosition() + 4 + offset;
lengthInSamples = (bytesPerFrame > 0) ? jmin (lengthInSamples, ((int64) length) / (int64) bytesPerFrame) : 0;
}
else if (type == chunkName ("MARK"))
{
const uint16 numCues = (uint16) input->readShortBigEndian();
// these two are always the same for AIFF-read files
metadataValues.set ("NumCuePoints", String (numCues));
metadataValues.set ("NumCueLabels", String (numCues));
for (uint16 i = 0; i < numCues; ++i)
{
uint16 identifier = (uint16) input->readShortBigEndian();
uint32 offset = (uint32) input->readIntBigEndian();
uint8 stringLength = (uint8) input->readByte();
MemoryBlock textBlock;
input->readIntoMemoryBlock (textBlock, stringLength);
// if the stringLength is even then read one more byte as the
// string needs to be an even number of bytes INCLUDING the
// leading length character in the pascal string
if ((stringLength & 1) == 0)
input->readByte();
const String prefixCue ("Cue" + String (i));
metadataValues.set (prefixCue + "Identifier", String (identifier));
metadataValues.set (prefixCue + "Offset", String (offset));
const String prefixLabel ("CueLabel" + String (i));
metadataValues.set (prefixLabel + "Identifier", String (identifier));
metadataValues.set (prefixLabel + "Text", textBlock.toString());
}
}
else if (type == chunkName ("COMT"))
{
const uint16 numNotes = (uint16) input->readShortBigEndian();
metadataValues.set ("NumCueNotes", String (numNotes));
for (uint16 i = 0; i < numNotes; ++i)
{
uint32 timestamp = (uint32) input->readIntBigEndian();
uint16 identifier = (uint16) input->readShortBigEndian(); // may be zero in this case
uint16 stringLength = (uint16) input->readShortBigEndian();
MemoryBlock textBlock;
input->readIntoMemoryBlock (textBlock, stringLength + (stringLength & 1));
const String prefix ("CueNote" + String (i));
metadataValues.set (prefix + "TimeStamp", String (timestamp));
metadataValues.set (prefix + "Identifier", String (identifier));
metadataValues.set (prefix + "Text", textBlock.toString());
}
}
else if (type == chunkName ("INST"))
{
HeapBlock <InstChunk> inst;
inst.calloc (jmax ((size_t) length + 1, sizeof (InstChunk)), 1);
input->read (inst, (int) length);
inst->copyTo (metadataValues);
}
else if (type == chunkName ("basc"))
{
AiffFileHelpers::BASCChunk (*input).addToMetadata (metadataValues);
}
else if (type == chunkName ("cate"))
{
metadataValues.set (AiffAudioFormat::appleTag,
AiffFileHelpers::readCATEChunk (*input, length));;
}
else if ((hasGotVer && hasGotData && hasGotType)
|| chunkEnd < input->getPosition()
|| input->isExhausted())
{
break;
}
input->setPosition (chunkEnd + (chunkEnd & 1)); // (chunks should be aligned to an even byte address)
}
}
}
if (metadataValues.size() > 0)
metadataValues.set ("MetaDataSource", "AIFF");
}
//==============================================================================
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) override
{
clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
startSampleInFile, numSamples, lengthInSamples);
if (numSamples <= 0)
return true;
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
while (numSamples > 0)
{
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
if (bytesRead < numThisTime * bytesPerFrame)
{
jassert (bytesRead >= 0);
zeromem (tempBuffer + bytesRead, (size_t) (numThisTime * bytesPerFrame - bytesRead));
}
if (littleEndian)
copySampleData<AudioData::LittleEndian> (bitsPerSample, usesFloatingPointData,
destSamples, startOffsetInDestBuffer, numDestChannels,
tempBuffer, (int) numChannels, numThisTime);
else
copySampleData<AudioData::BigEndian> (bitsPerSample, usesFloatingPointData,
destSamples, startOffsetInDestBuffer, numDestChannels,
tempBuffer, (int) numChannels, numThisTime);
startOffsetInDestBuffer += numThisTime;
numSamples -= numThisTime;
}
return true;
}
template <typename Endianness>
static void copySampleData (unsigned int bitsPerSample, const bool usesFloatingPointData,
int* const* destSamples, int startOffsetInDestBuffer, int numDestChannels,
const void* sourceData, int numChannels, int numSamples) noexcept
{
switch (bitsPerSample)
{
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, Endianness>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples); break;
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, Endianness>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples); break;
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, Endianness>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples); break;
case 32: if (usesFloatingPointData) ReadHelper<AudioData::Float32, AudioData::Float32, Endianness>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples);
else ReadHelper<AudioData::Int32, AudioData::Int32, Endianness>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples); break;
default: jassertfalse; break;
}
}
int bytesPerFrame;
int64 dataChunkStart;
bool littleEndian;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AiffAudioFormatReader)
};
//==============================================================================
class AiffAudioFormatWriter : public AudioFormatWriter
{
public:
AiffAudioFormatWriter (OutputStream* out, double rate,
unsigned int numChans, unsigned int bits,
const StringPairArray& metadataValues)
: AudioFormatWriter (out, TRANS (aiffFormatName), rate, numChans, bits),
lengthInSamples (0),
bytesWritten (0),
writeFailed (false)
{
using namespace AiffFileHelpers;
if (metadataValues.size() > 0)
{
// The meta data should have been santised for the AIFF format.
// If it was originally sourced from a WAV file the MetaDataSource
// key should be removed (or set to "AIFF") once this has been done
jassert (metadataValues.getValue ("MetaDataSource", "None") != "WAV");
MarkChunk::create (markChunk, metadataValues);
COMTChunk::create (comtChunk, metadataValues);
InstChunk::create (instChunk, metadataValues);
}
headerPosition = out->getPosition();
writeHeader();
}
~AiffAudioFormatWriter()
{
if ((bytesWritten & 1) != 0)
output->writeByte (0);
writeHeader();
}
//==============================================================================
bool write (const int** data, int numSamples) override
{
jassert (data != nullptr && *data != nullptr); // the input must contain at least one channel!
if (writeFailed)
return false;
const size_t bytes = (size_t) numSamples * numChannels * bitsPerSample / 8;
tempBlock.ensureSize ((size_t) bytes, false);
switch (bitsPerSample)
{
case 8: WriteHelper<AudioData::Int8, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
case 16: WriteHelper<AudioData::Int16, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
case 24: WriteHelper<AudioData::Int24, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
case 32: WriteHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
default: jassertfalse; break;
}
if (bytesWritten + bytes >= (size_t) 0xfff00000
|| ! output->write (tempBlock.getData(), bytes))
{
// failed to write to disk, so let's try writing the header.
// If it's just run out of disk space, then if it does manage
// to write the header, we'll still have a useable file..
writeHeader();
writeFailed = true;
return false;
}
else
{
bytesWritten += bytes;
lengthInSamples += (uint64) numSamples;
return true;
}
}
private:
MemoryBlock tempBlock, markChunk, comtChunk, instChunk;
uint64 lengthInSamples, bytesWritten;
int64 headerPosition;
bool writeFailed;
void writeHeader()
{
using namespace AiffFileHelpers;
const bool couldSeekOk = output->setPosition (headerPosition);
(void) couldSeekOk;
// if this fails, you've given it an output stream that can't seek! It needs
// to be able to seek back to write the header
jassert (couldSeekOk);
const int headerLen = (int) (54 + (markChunk.getSize() > 0 ? markChunk.getSize() + 8 : 0)
+ (comtChunk.getSize() > 0 ? comtChunk.getSize() + 8 : 0)
+ (instChunk.getSize() > 0 ? instChunk.getSize() + 8 : 0));
int audioBytes = (int) (lengthInSamples * ((bitsPerSample * numChannels) / 8));
audioBytes += (audioBytes & 1);
output->writeInt (chunkName ("FORM"));
output->writeIntBigEndian (headerLen + audioBytes - 8);
output->writeInt (chunkName ("AIFF"));
output->writeInt (chunkName ("COMM"));
output->writeIntBigEndian (18);
output->writeShortBigEndian ((short) numChannels);
output->writeIntBigEndian ((int) lengthInSamples);
output->writeShortBigEndian ((short) bitsPerSample);
uint8 sampleRateBytes[10] = { 0 };
if (sampleRate <= 1)
{
sampleRateBytes[0] = 0x3f;
sampleRateBytes[1] = 0xff;
sampleRateBytes[2] = 0x80;
}
else
{
int mask = 0x40000000;
sampleRateBytes[0] = 0x40;
if (sampleRate >= mask)
{
jassertfalse;
sampleRateBytes[1] = 0x1d;
}
else
{
int n = (int) sampleRate;
int i;
for (i = 0; i <= 32 ; ++i)
{
if ((n & mask) != 0)
break;
mask >>= 1;
}
n = n << (i + 1);
sampleRateBytes[1] = (uint8) (29 - i);
sampleRateBytes[2] = (uint8) ((n >> 24) & 0xff);
sampleRateBytes[3] = (uint8) ((n >> 16) & 0xff);
sampleRateBytes[4] = (uint8) ((n >> 8) & 0xff);
sampleRateBytes[5] = (uint8) (n & 0xff);
}
}
output->write (sampleRateBytes, 10);
if (markChunk.getSize() > 0)
{
output->writeInt (chunkName ("MARK"));
output->writeIntBigEndian ((int) markChunk.getSize());
*output << markChunk;
}
if (comtChunk.getSize() > 0)
{
output->writeInt (chunkName ("COMT"));
output->writeIntBigEndian ((int) comtChunk.getSize());
*output << comtChunk;
}
if (instChunk.getSize() > 0)
{
output->writeInt (chunkName ("INST"));
output->writeIntBigEndian ((int) instChunk.getSize());
*output << instChunk;
}
output->writeInt (chunkName ("SSND"));
output->writeIntBigEndian (audioBytes + 8);
output->writeInt (0);
output->writeInt (0);
jassert (output->getPosition() == headerLen);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AiffAudioFormatWriter)
};
//==============================================================================
class MemoryMappedAiffReader : public MemoryMappedAudioFormatReader
{
public:
MemoryMappedAiffReader (const File& f, const AiffAudioFormatReader& reader)
: MemoryMappedAudioFormatReader (f, reader, reader.dataChunkStart,
reader.bytesPerFrame * reader.lengthInSamples, reader.bytesPerFrame),
littleEndian (reader.littleEndian)
{
}
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) override
{
clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
startSampleInFile, numSamples, lengthInSamples);
if (map == nullptr || ! mappedSection.contains (Range<int64> (startSampleInFile, startSampleInFile + numSamples)))
{
jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read.
return false;
}
if (littleEndian)
AiffAudioFormatReader::copySampleData<AudioData::LittleEndian>
(bitsPerSample, usesFloatingPointData, destSamples, startOffsetInDestBuffer,
numDestChannels, sampleToPointer (startSampleInFile), (int) numChannels, numSamples);
else
AiffAudioFormatReader::copySampleData<AudioData::BigEndian>
(bitsPerSample, usesFloatingPointData, destSamples, startOffsetInDestBuffer,
numDestChannels, sampleToPointer (startSampleInFile), (int) numChannels, numSamples);
return true;
}
void readMaxLevels (int64 startSampleInFile, int64 numSamples,
float& min0, float& max0, float& min1, float& max1)
{
if (numSamples <= 0)
{
min0 = max0 = min1 = max1 = 0;
return;
}
if (map == nullptr || ! mappedSection.contains (Range<int64> (startSampleInFile, startSampleInFile + numSamples)))
{
jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read.
min0 = max0 = min1 = max1 = 0;
return;
}
switch (bitsPerSample)
{
case 8: scanMinAndMax<AudioData::UInt8> (startSampleInFile, numSamples, min0, max0, min1, max1); break;
case 16: scanMinAndMax<AudioData::Int16> (startSampleInFile, numSamples, min0, max0, min1, max1); break;
case 24: scanMinAndMax<AudioData::Int24> (startSampleInFile, numSamples, min0, max0, min1, max1); break;
case 32: if (usesFloatingPointData) scanMinAndMax<AudioData::Float32> (startSampleInFile, numSamples, min0, max0, min1, max1);
else scanMinAndMax<AudioData::Int32> (startSampleInFile, numSamples, min0, max0, min1, max1); break;
default: jassertfalse; break;
}
}
private:
const bool littleEndian;
template <typename SampleType>
void scanMinAndMax (int64 startSampleInFile, int64 numSamples,
float& min0, float& max0, float& min1, float& max1) const noexcept
{
scanMinAndMax2<SampleType> (0, startSampleInFile, numSamples, min0, max0);
if (numChannels > 1)
scanMinAndMax2<SampleType> (1, startSampleInFile, numSamples, min1, max1);
else
min1 = max1 = 0;
}
template <typename SampleType>
void scanMinAndMax2 (int channel, int64 startSampleInFile, int64 numSamples, float& mn, float& mx) const noexcept
{
if (littleEndian)
scanMinAndMaxInterleaved<SampleType, AudioData::LittleEndian> (channel, startSampleInFile, numSamples, mn, mx);
else
scanMinAndMaxInterleaved<SampleType, AudioData::BigEndian> (channel, startSampleInFile, numSamples, mn, mx);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedAiffReader)
};
//==============================================================================
AiffAudioFormat::AiffAudioFormat()
: AudioFormat (TRANS (aiffFormatName), StringArray (aiffExtensions))
{
}
AiffAudioFormat::~AiffAudioFormat()
{
}
Array<int> AiffAudioFormat::getPossibleSampleRates()
{
const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
return Array <int> (rates);
}
Array<int> AiffAudioFormat::getPossibleBitDepths()
{
const int depths[] = { 8, 16, 24, 0 };
return Array <int> (depths);
}
bool AiffAudioFormat::canDoStereo() { return true; }
bool AiffAudioFormat::canDoMono() { return true; }
#if JUCE_MAC
bool AiffAudioFormat::canHandleFile (const File& f)
{
if (AudioFormat::canHandleFile (f))
return true;
const OSType type = f.getMacOSType();
// (NB: written as hex to avoid four-char-constant warnings)
return type == 0x41494646 /* AIFF */ || type == 0x41494643 /* AIFC */
|| type == 0x61696666 /* aiff */ || type == 0x61696663 /* aifc */;
}
#endif
AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream, const bool deleteStreamIfOpeningFails)
{
ScopedPointer <AiffAudioFormatReader> w (new AiffAudioFormatReader (sourceStream));
if (w->sampleRate > 0 && w->numChannels > 0)
return w.release();
if (! deleteStreamIfOpeningFails)
w->input = nullptr;
return nullptr;
}
MemoryMappedAudioFormatReader* AiffAudioFormat::createMemoryMappedReader (const File& file)
{
if (FileInputStream* fin = file.createInputStream())
{
AiffAudioFormatReader reader (fin);
if (reader.lengthInSamples > 0)
return new MemoryMappedAiffReader (file, reader);
}
return nullptr;
}
AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out,
double sampleRate,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int /*qualityOptionIndex*/)
{
if (getPossibleBitDepths().contains (bitsPerSample))
return new AiffAudioFormatWriter (out, sampleRate, numberOfChannels, (unsigned int) bitsPerSample, metadataValues);
return nullptr;
}

+ 84
- 0
source/modules/juce_audio_formats/codecs/juce_AiffAudioFormat.h View File

@@ -0,0 +1,84 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
//==============================================================================
/**
Reads and Writes AIFF format audio files.
@see AudioFormat
*/
class JUCE_API AiffAudioFormat : public AudioFormat
{
public:
//==============================================================================
/** Creates an format object. */
AiffAudioFormat();
/** Destructor. */
~AiffAudioFormat();
//==============================================================================
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleOneShot;
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleRootSet;
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleRootNote;
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleBeats;
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleDenominator;
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleNumerator;
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleTag;
/** Metadata property name used when reading a aiff file with a basc chunk. */
static const char* const appleKey;
//==============================================================================
Array<int> getPossibleSampleRates() override;
Array<int> getPossibleBitDepths() override;
bool canDoStereo() override;
bool canDoMono() override;
#if JUCE_MAC
bool canHandleFile (const File& fileToTest) override;
#endif
//==============================================================================
AudioFormatReader* createReaderFor (InputStream* sourceStream,
bool deleteStreamIfOpeningFails) override;
MemoryMappedAudioFormatReader* createMemoryMappedReader (const File&) override;
AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int qualityOptionIndex) override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AiffAudioFormat)
};

+ 528
- 0
source/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp View File

@@ -0,0 +1,528 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_MAC || JUCE_IOS
//==============================================================================
namespace
{
const char* const coreAudioFormatName = "CoreAudio supported file";
StringArray findFileExtensionsForCoreAudioCodecs()
{
StringArray extensionsArray;
CFArrayRef extensions = nullptr;
UInt32 sizeOfArray = sizeof (extensions);
if (AudioFileGetGlobalInfo (kAudioFileGlobalInfo_AllExtensions, 0, 0, &sizeOfArray, &extensions) == noErr)
{
const CFIndex numValues = CFArrayGetCount (extensions);
for (CFIndex i = 0; i < numValues; ++i)
extensionsArray.add ("." + String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (extensions, i)));
CFRelease (extensions);
}
return extensionsArray;
}
}
//==============================================================================
const char* const CoreAudioFormat::midiDataBase64 = "midiDataBase64";
const char* const CoreAudioFormat::tempo = "tempo";
const char* const CoreAudioFormat::timeSig = "time signature";
const char* const CoreAudioFormat::keySig = "key signature";
//==============================================================================
struct CoreAudioFormatMetatdata
{
static uint32 chunkName (const char* const name) noexcept { return ByteOrder::bigEndianInt (name); }
//==============================================================================
struct FileHeader
{
FileHeader (InputStream& input)
{
fileType = (uint32) input.readIntBigEndian();
fileVersion = (uint16) input.readShortBigEndian();
fileFlags = (uint16) input.readShortBigEndian();
}
uint32 fileType;
uint16 fileVersion;
uint16 fileFlags;
};
//==============================================================================
struct ChunkHeader
{
ChunkHeader (InputStream& input)
{
chunkType = (uint32) input.readIntBigEndian();
chunkSize = (int64) input.readInt64BigEndian();
}
uint32 chunkType;
int64 chunkSize;
};
//==============================================================================
struct AudioDescriptionChunk
{
AudioDescriptionChunk (InputStream& input)
{
sampleRate = input.readDoubleBigEndian();
formatID = (uint32) input.readIntBigEndian();
formatFlags = (uint32) input.readIntBigEndian();
bytesPerPacket = (uint32) input.readIntBigEndian();
framesPerPacket = (uint32) input.readIntBigEndian();
channelsPerFrame = (uint32) input.readIntBigEndian();
bitsPerChannel = (uint32) input.readIntBigEndian();
}
double sampleRate;
uint32 formatID;
uint32 formatFlags;
uint32 bytesPerPacket;
uint32 framesPerPacket;
uint32 channelsPerFrame;
uint32 bitsPerChannel;
};
//==============================================================================
struct UserDefinedChunk
{
UserDefinedChunk (InputStream& input, int64 size)
{
// a user defined chunk contains 16 bytes of a UUID first
uuid[1] = input.readInt64BigEndian();
uuid[0] = input.readInt64BigEndian();
input.skipNextBytes (size - 16);
}
int64 uuid[2];
};
//==============================================================================
static StringPairArray parseMidiChunk (InputStream& input, int64 size)
{
const int64 originalPosition = input.getPosition();
MemoryBlock midiBlock;
input.readIntoMemoryBlock (midiBlock, (ssize_t) size);
MemoryInputStream midiInputStream (midiBlock, false);
StringPairArray midiMetadata;
MidiFile midiFile;
if (midiFile.readFrom (midiInputStream))
{
midiMetadata.set (CoreAudioFormat::midiDataBase64, midiBlock.toBase64Encoding());
findTempoEvents (midiFile, midiMetadata);
findTimeSigEvents (midiFile, midiMetadata);
findKeySigEvents (midiFile, midiMetadata);
}
input.setPosition (originalPosition + size);
return midiMetadata;
}
static void findTempoEvents (MidiFile& midiFile, StringPairArray& midiMetadata)
{
MidiMessageSequence tempoEvents;
midiFile.findAllTempoEvents (tempoEvents);
const int numTempoEvents = tempoEvents.getNumEvents();
MemoryOutputStream tempoSequence;
for (int i = 0; i < numTempoEvents; ++i)
{
const double tempo = getTempoFromTempoMetaEvent (tempoEvents.getEventPointer (i));
if (tempo > 0.0)
{
if (i == 0)
midiMetadata.set (CoreAudioFormat::tempo, String (tempo));
if (numTempoEvents > 1)
tempoSequence << String (tempo) << ',' << tempoEvents.getEventTime (i) << ';';
}
}
if (tempoSequence.getDataSize() > 0)
midiMetadata.set ("tempo sequence", tempoSequence.toUTF8());
}
static double getTempoFromTempoMetaEvent (MidiMessageSequence::MidiEventHolder* holder)
{
if (holder != nullptr)
{
const MidiMessage& midiMessage = holder->message;
if (midiMessage.isTempoMetaEvent())
{
const double tempoSecondsPerQuarterNote = midiMessage.getTempoSecondsPerQuarterNote();
if (tempoSecondsPerQuarterNote > 0.0)
return 60.0 / tempoSecondsPerQuarterNote;
}
}
return 0.0;
}
static void findTimeSigEvents (MidiFile& midiFile, StringPairArray& midiMetadata)
{
MidiMessageSequence timeSigEvents;
midiFile.findAllTimeSigEvents (timeSigEvents);
const int numTimeSigEvents = timeSigEvents.getNumEvents();
MemoryOutputStream timeSigSequence;
for (int i = 0; i < numTimeSigEvents; ++i)
{
int numerator, denominator;
timeSigEvents.getEventPointer(i)->message.getTimeSignatureInfo (numerator, denominator);
String timeSigString;
timeSigString << numerator << '/' << denominator;
if (i == 0)
midiMetadata.set (CoreAudioFormat::timeSig, timeSigString);
if (numTimeSigEvents > 1)
timeSigSequence << timeSigString << ',' << timeSigEvents.getEventTime (i) << ';';
}
if (timeSigSequence.getDataSize() > 0)
midiMetadata.set ("time signature sequence", timeSigSequence.toUTF8());
}
static void findKeySigEvents (MidiFile& midiFile, StringPairArray& midiMetadata)
{
MidiMessageSequence keySigEvents;
midiFile.findAllKeySigEvents (keySigEvents);
const int numKeySigEvents = keySigEvents.getNumEvents();
MemoryOutputStream keySigSequence;
for (int i = 0; i < numKeySigEvents; ++i)
{
const MidiMessage& message (keySigEvents.getEventPointer (i)->message);
const int key = jlimit (0, 14, message.getKeySignatureNumberOfSharpsOrFlats() + 7);
const bool isMajor = message.isKeySignatureMajorKey();
static const char* majorKeys[] = { "Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#" };
static const char* minorKeys[] = { "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#", "D#", "A#" };
String keySigString (isMajor ? majorKeys[key]
: minorKeys[key]);
if (! isMajor)
keySigString << 'm';
if (i == 0)
midiMetadata.set (CoreAudioFormat::keySig, keySigString);
if (numKeySigEvents > 1)
keySigSequence << keySigString << ',' << keySigEvents.getEventTime (i) << ';';
}
if (keySigSequence.getDataSize() > 0)
midiMetadata.set ("key signature sequence", keySigSequence.toUTF8());
}
//==============================================================================
static StringPairArray parseInformationChunk (InputStream& input)
{
StringPairArray infoStrings;
const uint32 numEntries = (uint32) input.readIntBigEndian();
for (uint32 i = 0; i < numEntries; ++i)
infoStrings.set (input.readString(), input.readString());
return infoStrings;
}
//==============================================================================
static bool read (InputStream& input, StringPairArray& metadataValues)
{
const int64 originalPos = input.getPosition();
const FileHeader cafFileHeader (input);
const bool isCafFile = cafFileHeader.fileType == chunkName ("caff");
if (isCafFile)
{
while (! input.isExhausted())
{
const ChunkHeader chunkHeader (input);
if (chunkHeader.chunkType == chunkName ("desc"))
{
AudioDescriptionChunk audioDescriptionChunk (input);
}
else if (chunkHeader.chunkType == chunkName ("uuid"))
{
UserDefinedChunk userDefinedChunk (input, chunkHeader.chunkSize);
}
else if (chunkHeader.chunkType == chunkName ("data"))
{
// -1 signifies an unknown data size so the data has to be at the
// end of the file so we must have finished the header
if (chunkHeader.chunkSize == -1)
break;
input.skipNextBytes (chunkHeader.chunkSize);
}
else if (chunkHeader.chunkType == chunkName ("midi"))
{
metadataValues.addArray (parseMidiChunk (input, chunkHeader.chunkSize));
}
else if (chunkHeader.chunkType == chunkName ("info"))
{
metadataValues.addArray (parseInformationChunk (input));
}
else
{
// we aren't decoding this chunk yet so just skip over it
input.skipNextBytes (chunkHeader.chunkSize);
}
}
}
input.setPosition (originalPos);
return isCafFile;
}
};
//==============================================================================
class CoreAudioReader : public AudioFormatReader
{
public:
CoreAudioReader (InputStream* const inp)
: AudioFormatReader (inp, TRANS (coreAudioFormatName)),
ok (false), lastReadPosition (0)
{
usesFloatingPointData = true;
bitsPerSample = 32;
if (input != nullptr)
CoreAudioFormatMetatdata::read (*input, metadataValues);
OSStatus status = AudioFileOpenWithCallbacks (this,
&readCallback,
nullptr, // write needs to be null to avoid permisisions errors
&getSizeCallback,
nullptr, // setSize needs to be null to avoid permisisions errors
0, // AudioFileTypeID inFileTypeHint
&audioFileID);
if (status == noErr)
{
status = ExtAudioFileWrapAudioFileID (audioFileID, false, &audioFileRef);
if (status == noErr)
{
AudioStreamBasicDescription sourceAudioFormat;
UInt32 audioStreamBasicDescriptionSize = sizeof (AudioStreamBasicDescription);
ExtAudioFileGetProperty (audioFileRef,
kExtAudioFileProperty_FileDataFormat,
&audioStreamBasicDescriptionSize,
&sourceAudioFormat);
numChannels = sourceAudioFormat.mChannelsPerFrame;
sampleRate = sourceAudioFormat.mSampleRate;
UInt32 sizeOfLengthProperty = sizeof (int64);
ExtAudioFileGetProperty (audioFileRef,
kExtAudioFileProperty_FileLengthFrames,
&sizeOfLengthProperty,
&lengthInSamples);
destinationAudioFormat.mSampleRate = sampleRate;
destinationAudioFormat.mFormatID = kAudioFormatLinearPCM;
destinationAudioFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsNonInterleaved | kAudioFormatFlagsNativeEndian;
destinationAudioFormat.mBitsPerChannel = sizeof (float) * 8;
destinationAudioFormat.mChannelsPerFrame = numChannels;
destinationAudioFormat.mBytesPerFrame = sizeof (float);
destinationAudioFormat.mFramesPerPacket = 1;
destinationAudioFormat.mBytesPerPacket = destinationAudioFormat.mFramesPerPacket * destinationAudioFormat.mBytesPerFrame;
status = ExtAudioFileSetProperty (audioFileRef,
kExtAudioFileProperty_ClientDataFormat,
sizeof (AudioStreamBasicDescription),
&destinationAudioFormat);
if (status == noErr)
{
bufferList.malloc (1, sizeof (AudioBufferList) + numChannels * sizeof (AudioBuffer));
bufferList->mNumberBuffers = numChannels;
ok = true;
}
}
}
}
~CoreAudioReader()
{
ExtAudioFileDispose (audioFileRef);
AudioFileClose (audioFileID);
}
//==============================================================================
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) override
{
clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
startSampleInFile, numSamples, lengthInSamples);
if (numSamples <= 0)
return true;
if (lastReadPosition != startSampleInFile)
{
OSStatus status = ExtAudioFileSeek (audioFileRef, startSampleInFile);
if (status != noErr)
return false;
lastReadPosition = startSampleInFile;
}
while (numSamples > 0)
{
const int numThisTime = jmin (8192, numSamples);
const size_t numBytes = sizeof (float) * (size_t) numThisTime;
audioDataBlock.ensureSize (numBytes * numChannels, false);
float* data = static_cast<float*> (audioDataBlock.getData());
for (int j = (int) numChannels; --j >= 0;)
{
bufferList->mBuffers[j].mNumberChannels = 1;
bufferList->mBuffers[j].mDataByteSize = (UInt32) numBytes;
bufferList->mBuffers[j].mData = data;
data += numThisTime;
}
UInt32 numFramesToRead = (UInt32) numThisTime;
OSStatus status = ExtAudioFileRead (audioFileRef, &numFramesToRead, bufferList);
if (status != noErr)
return false;
for (int i = numDestChannels; --i >= 0;)
{
if (destSamples[i] != nullptr)
{
if (i < (int) numChannels)
memcpy (destSamples[i] + startOffsetInDestBuffer, bufferList->mBuffers[i].mData, numBytes);
else
zeromem (destSamples[i] + startOffsetInDestBuffer, numBytes);
}
}
startOffsetInDestBuffer += numThisTime;
numSamples -= numThisTime;
lastReadPosition += numThisTime;
}
return true;
}
bool ok;
private:
AudioFileID audioFileID;
ExtAudioFileRef audioFileRef;
AudioStreamBasicDescription destinationAudioFormat;
MemoryBlock audioDataBlock;
HeapBlock<AudioBufferList> bufferList;
int64 lastReadPosition;
static SInt64 getSizeCallback (void* inClientData)
{
return static_cast<CoreAudioReader*> (inClientData)->input->getTotalLength();
}
static OSStatus readCallback (void* inClientData,
SInt64 inPosition,
UInt32 requestCount,
void* buffer,
UInt32* actualCount)
{
CoreAudioReader* const reader = static_cast<CoreAudioReader*> (inClientData);
reader->input->setPosition (inPosition);
*actualCount = (UInt32) reader->input->read (buffer, (int) requestCount);
return noErr;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreAudioReader)
};
//==============================================================================
CoreAudioFormat::CoreAudioFormat()
: AudioFormat (TRANS (coreAudioFormatName), findFileExtensionsForCoreAudioCodecs())
{
}
CoreAudioFormat::~CoreAudioFormat() {}
Array<int> CoreAudioFormat::getPossibleSampleRates() { return Array<int>(); }
Array<int> CoreAudioFormat::getPossibleBitDepths() { return Array<int>(); }
bool CoreAudioFormat::canDoStereo() { return true; }
bool CoreAudioFormat::canDoMono() { return true; }
//==============================================================================
AudioFormatReader* CoreAudioFormat::createReaderFor (InputStream* sourceStream,
bool deleteStreamIfOpeningFails)
{
ScopedPointer<CoreAudioReader> r (new CoreAudioReader (sourceStream));
if (r->ok)
return r.release();
if (! deleteStreamIfOpeningFails)
r->input = nullptr;
return nullptr;
}
AudioFormatWriter* CoreAudioFormat::createWriterFor (OutputStream*,
double /*sampleRateToUse*/,
unsigned int /*numberOfChannels*/,
int /*bitsPerSample*/,
const StringPairArray& /*metadataValues*/,
int /*qualityOptionIndex*/)
{
jassertfalse; // not yet implemented!
return nullptr;
}
#endif

+ 77
- 0
source/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.h View File

@@ -0,0 +1,77 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_MAC || JUCE_IOS || DOXYGEN
//==============================================================================
/**
OSX and iOS only - This uses the AudioToolbox framework to read any audio
format that the system has a codec for.
This should be able to understand formats such as mp3, m4a, etc.
@see AudioFormat
*/
class JUCE_API CoreAudioFormat : public AudioFormat
{
public:
//==============================================================================
/** Creates a format object. */
CoreAudioFormat();
/** Destructor. */
~CoreAudioFormat();
//==============================================================================
/** Metadata property name used when reading a caf file with a MIDI chunk. */
static const char* const midiDataBase64;
/** Metadata property name used when reading a caf file with tempo information. */
static const char* const tempo;
/** Metadata property name used when reading a caf file time signature information. */
static const char* const timeSig;
/** Metadata property name used when reading a caf file time signature information. */
static const char* const keySig;
//==============================================================================
Array<int> getPossibleSampleRates() override;
Array<int> getPossibleBitDepths() override;
bool canDoStereo() override;
bool canDoMono() override;
//==============================================================================
AudioFormatReader* createReaderFor (InputStream*,
bool deleteStreamIfOpeningFails) override;
AudioFormatWriter* createWriterFor (OutputStream*,
double sampleRateToUse,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int qualityOptionIndex) override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreAudioFormat)
};
#endif

+ 545
- 0
source/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp View File

@@ -0,0 +1,545 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_USE_FLAC
namespace FlacNamespace
{
#if JUCE_INCLUDE_FLAC_CODE || ! defined (JUCE_INCLUDE_FLAC_CODE)
#undef VERSION
#define VERSION "1.2.1"
#define FLAC__NO_DLL 1
#if JUCE_MSVC
#pragma warning (disable: 4267 4127 4244 4996 4100 4701 4702 4013 4133 4206 4312 4505 4365 4005 4334 181 111)
#endif
#if JUCE_MAC
#define FLAC__SYS_DARWIN 1
#endif
#ifndef SIZE_MAX
#define SIZE_MAX 0xffffffff
#endif
#if JUCE_CLANG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshadow"
#endif
#define __STDC_LIMIT_MACROS 1
#include "flac/all.h"
#include "flac/libFLAC/bitmath.c"
#include "flac/libFLAC/bitreader.c"
#include "flac/libFLAC/bitwriter.c"
#include "flac/libFLAC/cpu.c"
#include "flac/libFLAC/crc.c"
#include "flac/libFLAC/fixed.c"
#include "flac/libFLAC/float.c"
#include "flac/libFLAC/format.c"
#include "flac/libFLAC/lpc_flac.c"
#include "flac/libFLAC/md5.c"
#include "flac/libFLAC/memory.c"
#include "flac/libFLAC/stream_decoder.c"
#include "flac/libFLAC/stream_encoder.c"
#include "flac/libFLAC/stream_encoder_framing.c"
#include "flac/libFLAC/window_flac.c"
#undef VERSION
#else
#include <FLAC/all.h>
#endif
#if JUCE_CLANG
#pragma clang diagnostic pop
#endif
}
#undef max
#undef min
//==============================================================================
static const char* const flacFormatName = "FLAC file";
static const char* const flacExtensions[] = { ".flac", 0 };
//==============================================================================
class FlacReader : public AudioFormatReader
{
public:
//==============================================================================
FlacReader (InputStream* const in)
: AudioFormatReader (in, TRANS (flacFormatName)),
reservoir (2, 0),
reservoirStart (0),
samplesInReservoir (0),
scanningForLength (false)
{
using namespace FlacNamespace;
lengthInSamples = 0;
decoder = FLAC__stream_decoder_new();
ok = FLAC__stream_decoder_init_stream (decoder,
readCallback_, seekCallback_, tellCallback_, lengthCallback_,
eofCallback_, writeCallback_, metadataCallback_, errorCallback_,
this) == FLAC__STREAM_DECODER_INIT_STATUS_OK;
if (ok)
{
FLAC__stream_decoder_process_until_end_of_metadata (decoder);
if (lengthInSamples == 0 && sampleRate > 0)
{
// the length hasn't been stored in the metadata, so we'll need to
// work it out the length the hard way, by scanning the whole file..
scanningForLength = true;
FLAC__stream_decoder_process_until_end_of_stream (decoder);
scanningForLength = false;
const int64 tempLength = lengthInSamples;
FLAC__stream_decoder_reset (decoder);
FLAC__stream_decoder_process_until_end_of_metadata (decoder);
lengthInSamples = tempLength;
}
}
}
~FlacReader()
{
FlacNamespace::FLAC__stream_decoder_delete (decoder);
}
void useMetadata (const FlacNamespace::FLAC__StreamMetadata_StreamInfo& info)
{
sampleRate = info.sample_rate;
bitsPerSample = info.bits_per_sample;
lengthInSamples = (unsigned int) info.total_samples;
numChannels = info.channels;
reservoir.setSize ((int) numChannels, 2 * (int) info.max_blocksize, false, false, true);
}
// returns the number of samples read
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) override
{
using namespace FlacNamespace;
if (! ok)
return false;
while (numSamples > 0)
{
if (startSampleInFile >= reservoirStart
&& startSampleInFile < reservoirStart + samplesInReservoir)
{
const int num = (int) jmin ((int64) numSamples,
reservoirStart + samplesInReservoir - startSampleInFile);
jassert (num > 0);
for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
if (destSamples[i] != nullptr)
memcpy (destSamples[i] + startOffsetInDestBuffer,
reservoir.getSampleData (i, (int) (startSampleInFile - reservoirStart)),
sizeof (int) * (size_t) num);
startOffsetInDestBuffer += num;
startSampleInFile += num;
numSamples -= num;
}
else
{
if (startSampleInFile >= (int) lengthInSamples)
{
samplesInReservoir = 0;
}
else if (startSampleInFile < reservoirStart
|| startSampleInFile > reservoirStart + jmax (samplesInReservoir, 511))
{
// had some problems with flac crashing if the read pos is aligned more
// accurately than this. Probably fixed in newer versions of the library, though.
reservoirStart = (int) (startSampleInFile & ~511);
samplesInReservoir = 0;
FLAC__stream_decoder_seek_absolute (decoder, (FLAC__uint64) reservoirStart);
}
else
{
reservoirStart += samplesInReservoir;
samplesInReservoir = 0;
FLAC__stream_decoder_process_single (decoder);
}
if (samplesInReservoir == 0)
break;
}
}
if (numSamples > 0)
{
for (int i = numDestChannels; --i >= 0;)
if (destSamples[i] != nullptr)
zeromem (destSamples[i] + startOffsetInDestBuffer, sizeof (int) * (size_t) numSamples);
}
return true;
}
void useSamples (const FlacNamespace::FLAC__int32* const buffer[], int numSamples)
{
if (scanningForLength)
{
lengthInSamples += numSamples;
}
else
{
if (numSamples > reservoir.getNumSamples())
reservoir.setSize ((int) numChannels, numSamples, false, false, true);
const unsigned int bitsToShift = 32 - bitsPerSample;
for (int i = 0; i < (int) numChannels; ++i)
{
const FlacNamespace::FLAC__int32* src = buffer[i];
int n = i;
while (src == 0 && n > 0)
src = buffer [--n];
if (src != nullptr)
{
int* const dest = reinterpret_cast<int*> (reservoir.getSampleData(i));
for (int j = 0; j < numSamples; ++j)
dest[j] = src[j] << bitsToShift;
}
}
samplesInReservoir = numSamples;
}
}
//==============================================================================
static FlacNamespace::FLAC__StreamDecoderReadStatus readCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__byte buffer[], size_t* bytes, void* client_data)
{
using namespace FlacNamespace;
*bytes = (size_t) static_cast<const FlacReader*> (client_data)->input->read (buffer, (int) *bytes);
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
static FlacNamespace::FLAC__StreamDecoderSeekStatus seekCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64 absolute_byte_offset, void* client_data)
{
using namespace FlacNamespace;
static_cast<const FlacReader*> (client_data)->input->setPosition ((int) absolute_byte_offset);
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
static FlacNamespace::FLAC__StreamDecoderTellStatus tellCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
{
using namespace FlacNamespace;
*absolute_byte_offset = (uint64) static_cast<const FlacReader*> (client_data)->input->getPosition();
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
static FlacNamespace::FLAC__StreamDecoderLengthStatus lengthCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* stream_length, void* client_data)
{
using namespace FlacNamespace;
*stream_length = (uint64) static_cast<const FlacReader*> (client_data)->input->getTotalLength();
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
static FlacNamespace::FLAC__bool eofCallback_ (const FlacNamespace::FLAC__StreamDecoder*, void* client_data)
{
return static_cast<const FlacReader*> (client_data)->input->isExhausted();
}
static FlacNamespace::FLAC__StreamDecoderWriteStatus writeCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
const FlacNamespace::FLAC__Frame* frame,
const FlacNamespace::FLAC__int32* const buffer[],
void* client_data)
{
using namespace FlacNamespace;
static_cast<FlacReader*> (client_data)->useSamples (buffer, (int) frame->header.blocksize);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static void metadataCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
const FlacNamespace::FLAC__StreamMetadata* metadata,
void* client_data)
{
static_cast<FlacReader*> (client_data)->useMetadata (metadata->data.stream_info);
}
static void errorCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__StreamDecoderErrorStatus, void*)
{
}
private:
FlacNamespace::FLAC__StreamDecoder* decoder;
AudioSampleBuffer reservoir;
int reservoirStart, samplesInReservoir;
bool ok, scanningForLength;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacReader)
};
//==============================================================================
class FlacWriter : public AudioFormatWriter
{
public:
FlacWriter (OutputStream* const out, double rate, uint32 numChans, uint32 bits, int qualityOptionIndex)
: AudioFormatWriter (out, TRANS (flacFormatName), rate, numChans, bits)
{
using namespace FlacNamespace;
encoder = FLAC__stream_encoder_new();
if (qualityOptionIndex > 0)
FLAC__stream_encoder_set_compression_level (encoder, (uint32) jmin (8, qualityOptionIndex));
FLAC__stream_encoder_set_do_mid_side_stereo (encoder, numChannels == 2);
FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, numChannels == 2);
FLAC__stream_encoder_set_channels (encoder, numChannels);
FLAC__stream_encoder_set_bits_per_sample (encoder, jmin ((unsigned int) 24, bitsPerSample));
FLAC__stream_encoder_set_sample_rate (encoder, (unsigned int) sampleRate);
FLAC__stream_encoder_set_blocksize (encoder, 0);
FLAC__stream_encoder_set_do_escape_coding (encoder, true);
ok = FLAC__stream_encoder_init_stream (encoder,
encodeWriteCallback, encodeSeekCallback,
encodeTellCallback, encodeMetadataCallback,
this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK;
}
~FlacWriter()
{
if (ok)
{
FlacNamespace::FLAC__stream_encoder_finish (encoder);
output->flush();
}
else
{
output = nullptr; // to stop the base class deleting this, as it needs to be returned
// to the caller of createWriter()
}
FlacNamespace::FLAC__stream_encoder_delete (encoder);
}
//==============================================================================
bool write (const int** samplesToWrite, int numSamples) override
{
using namespace FlacNamespace;
if (! ok)
return false;
HeapBlock<int*> channels;
HeapBlock<int> temp;
const int bitsToShift = 32 - (int) bitsPerSample;
if (bitsToShift > 0)
{
temp.malloc (numChannels * (size_t) numSamples);
channels.calloc (numChannels + 1);
for (unsigned int i = 0; i < numChannels; ++i)
{
if (samplesToWrite[i] == nullptr)
break;
int* const destData = temp.getData() + i * (size_t) numSamples;
channels[i] = destData;
for (int j = 0; j < numSamples; ++j)
destData[j] = (samplesToWrite[i][j] >> bitsToShift);
}
samplesToWrite = const_cast<const int**> (channels.getData());
}
return FLAC__stream_encoder_process (encoder, (const FLAC__int32**) samplesToWrite, (size_t) numSamples) != 0;
}
bool writeData (const void* const data, const int size) const
{
return output->write (data, (size_t) size);
}
static void packUint32 (FlacNamespace::FLAC__uint32 val, FlacNamespace::FLAC__byte* b, const int bytes)
{
b += bytes;
for (int i = 0; i < bytes; ++i)
{
*(--b) = (FlacNamespace::FLAC__byte) (val & 0xff);
val >>= 8;
}
}
void writeMetaData (const FlacNamespace::FLAC__StreamMetadata* metadata)
{
using namespace FlacNamespace;
const FLAC__StreamMetadata_StreamInfo& info = metadata->data.stream_info;
unsigned char buffer [FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
const unsigned int channelsMinus1 = info.channels - 1;
const unsigned int bitsMinus1 = info.bits_per_sample - 1;
packUint32 (info.min_blocksize, buffer, 2);
packUint32 (info.max_blocksize, buffer + 2, 2);
packUint32 (info.min_framesize, buffer + 4, 3);
packUint32 (info.max_framesize, buffer + 7, 3);
buffer[10] = (uint8) ((info.sample_rate >> 12) & 0xff);
buffer[11] = (uint8) ((info.sample_rate >> 4) & 0xff);
buffer[12] = (uint8) (((info.sample_rate & 0x0f) << 4) | (channelsMinus1 << 1) | (bitsMinus1 >> 4));
buffer[13] = (FLAC__byte) (((bitsMinus1 & 0x0f) << 4) | (unsigned int) ((info.total_samples >> 32) & 0x0f));
packUint32 ((FLAC__uint32) info.total_samples, buffer + 14, 4);
memcpy (buffer + 18, info.md5sum, 16);
const bool seekOk = output->setPosition (4);
(void) seekOk;
// if this fails, you've given it an output stream that can't seek! It needs
// to be able to seek back to write the header
jassert (seekOk);
output->writeIntBigEndian (FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
output->write (buffer, FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
}
//==============================================================================
static FlacNamespace::FLAC__StreamEncoderWriteStatus encodeWriteCallback (const FlacNamespace::FLAC__StreamEncoder*,
const FlacNamespace::FLAC__byte buffer[],
size_t bytes,
unsigned int /*samples*/,
unsigned int /*current_frame*/,
void* client_data)
{
using namespace FlacNamespace;
return static_cast<FlacWriter*> (client_data)->writeData (buffer, (int) bytes)
? FLAC__STREAM_ENCODER_WRITE_STATUS_OK
: FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
static FlacNamespace::FLAC__StreamEncoderSeekStatus encodeSeekCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64, void*)
{
using namespace FlacNamespace;
return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
}
static FlacNamespace::FLAC__StreamEncoderTellStatus encodeTellCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
{
using namespace FlacNamespace;
if (client_data == nullptr)
return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
*absolute_byte_offset = (FLAC__uint64) static_cast<FlacWriter*> (client_data)->output->getPosition();
return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
}
static void encodeMetadataCallback (const FlacNamespace::FLAC__StreamEncoder*, const FlacNamespace::FLAC__StreamMetadata* metadata, void* client_data)
{
static_cast<FlacWriter*> (client_data)->writeMetaData (metadata);
}
bool ok;
private:
FlacNamespace::FLAC__StreamEncoder* encoder;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacWriter)
};
//==============================================================================
FlacAudioFormat::FlacAudioFormat()
: AudioFormat (TRANS (flacFormatName), StringArray (flacExtensions))
{
}
FlacAudioFormat::~FlacAudioFormat()
{
}
Array<int> FlacAudioFormat::getPossibleSampleRates()
{
const int rates[] = { 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000,
88200, 96000, 176400, 192000, 352800, 384000 };
return Array<int> (rates, numElementsInArray (rates));
}
Array<int> FlacAudioFormat::getPossibleBitDepths()
{
const int depths[] = { 16, 24 };
return Array<int> (depths, numElementsInArray (depths));
}
bool FlacAudioFormat::canDoStereo() { return true; }
bool FlacAudioFormat::canDoMono() { return true; }
bool FlacAudioFormat::isCompressed() { return true; }
AudioFormatReader* FlacAudioFormat::createReaderFor (InputStream* in, const bool deleteStreamIfOpeningFails)
{
ScopedPointer<FlacReader> r (new FlacReader (in));
if (r->sampleRate > 0)
return r.release();
if (! deleteStreamIfOpeningFails)
r->input = nullptr;
return nullptr;
}
AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
double sampleRate,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& /*metadataValues*/,
int qualityOptionIndex)
{
if (getPossibleBitDepths().contains (bitsPerSample))
{
ScopedPointer<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels,
(uint32) bitsPerSample, qualityOptionIndex));
if (w->ok)
return w.release();
}
return nullptr;
}
StringArray FlacAudioFormat::getQualityOptions()
{
const char* options[] = { "0 (Fastest)", "1", "2", "3", "4", "5 (Default)","6", "7", "8 (Highest quality)", 0 };
return StringArray (options);
}
#endif

+ 65
- 0
source/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.h View File

@@ -0,0 +1,65 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_USE_FLAC || defined (DOXYGEN)
//==============================================================================
/**
Reads and writes the lossless-compression FLAC audio format.
To compile this, you'll need to set the JUCE_USE_FLAC flag.
@see AudioFormat
*/
class JUCE_API FlacAudioFormat : public AudioFormat
{
public:
//==============================================================================
FlacAudioFormat();
~FlacAudioFormat();
//==============================================================================
Array<int> getPossibleSampleRates() override;
Array<int> getPossibleBitDepths() override;
bool canDoStereo() override;
bool canDoMono() override;
bool isCompressed() override;
StringArray getQualityOptions() override;
//==============================================================================
AudioFormatReader* createReaderFor (InputStream* sourceStream,
bool deleteStreamIfOpeningFails) override;
AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int qualityOptionIndex) override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacAudioFormat)
};
#endif

+ 227
- 0
source/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp View File

@@ -0,0 +1,227 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_USE_LAME_AUDIO_FORMAT
class LAMEEncoderAudioFormat::Writer : public AudioFormatWriter
{
public:
Writer (OutputStream* destStream, const String& formatName,
const File& lameApp, int vbr, int cbr,
double sampleRate, unsigned int numberOfChannels,
unsigned int bitsPerSample, const StringPairArray& metadata)
: AudioFormatWriter (destStream, formatName, sampleRate,
numberOfChannels, bitsPerSample),
vbrLevel (vbr), cbrBitrate (cbr),
tempWav (".wav")
{
WavAudioFormat wavFormat;
if (FileOutputStream* out = tempWav.getFile().createOutputStream())
{
writer = wavFormat.createWriterFor (out, sampleRate, numChannels,
bitsPerSample, metadata, 0);
args.add (lameApp.getFullPathName());
args.add ("--quiet");
if (cbrBitrate == 0)
{
args.add ("--vbr-new");
args.add ("-V");
args.add (String (vbrLevel));
}
else
{
args.add ("--cbr");
args.add ("-b");
args.add (String (cbrBitrate));
}
addMetadataArg (metadata, "id3title", "--tt");
addMetadataArg (metadata, "id3artist", "--ta");
addMetadataArg (metadata, "id3album", "--tl");
addMetadataArg (metadata, "id3comment", "--tc");
addMetadataArg (metadata, "id3date", "--ty");
addMetadataArg (metadata, "id3genre", "--tg");
addMetadataArg (metadata, "id3trackNumber", "--tn");
}
}
void addMetadataArg (const StringPairArray& metadata, const char* key, const char* lameFlag)
{
const String value (metadata.getValue (key, String::empty));
if (value.isNotEmpty())
{
args.add (lameFlag);
args.add (value);
}
}
~Writer()
{
if (writer != nullptr)
{
writer = nullptr;
if (! convertToMP3())
convertToMP3(); // try again
}
}
bool write (const int** samplesToWrite, int numSamples)
{
return writer != nullptr && writer->write (samplesToWrite, numSamples);
}
private:
int vbrLevel, cbrBitrate;
TemporaryFile tempWav;
ScopedPointer<AudioFormatWriter> writer;
StringArray args;
bool runLameChildProcess (const TemporaryFile& tempMP3, const StringArray& args) const
{
ChildProcess cp;
if (cp.start (args))
{
const String childOutput (cp.readAllProcessOutput());
DBG (childOutput); (void) childOutput;
cp.waitForProcessToFinish (10000);
return tempMP3.getFile().getSize() > 0;
}
return false;
}
bool convertToMP3() const
{
TemporaryFile tempMP3 (".mp3");
StringArray args2 (args);
args2.add (tempWav.getFile().getFullPathName());
args2.add (tempMP3.getFile().getFullPathName());
DBG (args2.joinIntoString (" "));
if (runLameChildProcess (tempMP3, args2))
{
FileInputStream fis (tempMP3.getFile());
if (fis.openedOk() && output->writeFromInputStream (fis, -1) > 0)
{
output->flush();
return true;
}
}
return false;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Writer)
};
//==============================================================================
static const char* const lameFormatName = "MP3 file";
static const char* const lameExtensions[] = { ".mp3", nullptr };
LAMEEncoderAudioFormat::LAMEEncoderAudioFormat (const File& lameApplication)
: AudioFormat (TRANS (lameFormatName), StringArray (lameExtensions)),
lameApp (lameApplication)
{
}
LAMEEncoderAudioFormat::~LAMEEncoderAudioFormat()
{
}
bool LAMEEncoderAudioFormat::canHandleFile (const File&)
{
return false;
}
Array<int> LAMEEncoderAudioFormat::getPossibleSampleRates()
{
const int rates[] = { 32000, 44100, 48000, 0 };
return Array <int> (rates);
}
Array<int> LAMEEncoderAudioFormat::getPossibleBitDepths()
{
const int depths[] = { 16, 0 };
return Array <int> (depths);
}
bool LAMEEncoderAudioFormat::canDoStereo() { return true; }
bool LAMEEncoderAudioFormat::canDoMono() { return true; }
bool LAMEEncoderAudioFormat::isCompressed() { return true; }
StringArray LAMEEncoderAudioFormat::getQualityOptions()
{
const char* vbrOptions[] = { "VBR quality 0 (best)", "VBR quality 1", "VBR quality 2", "VBR quality 3",
"VBR quality 4 (normal)", "VBR quality 5", "VBR quality 6", "VBR quality 7", "VBR quality 8",
"VBR quality 9 (smallest)",
nullptr };
StringArray opts (vbrOptions);
const int cbrRates[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };
for (int i = 0; i < numElementsInArray (cbrRates); ++i)
opts.add (String (cbrRates[i]) + " Kb/s CBR");
return opts;
}
AudioFormatReader* LAMEEncoderAudioFormat::createReaderFor (InputStream*, const bool)
{
return nullptr;
}
AudioFormatWriter* LAMEEncoderAudioFormat::createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int qualityOptionIndex)
{
int vbr = 4;
int cbr = 0;
const String qual (getQualityOptions() [qualityOptionIndex]);
if (qual.contains ("VBR"))
vbr = qual.retainCharacters ("0123456789").getIntValue();
else
cbr = qual.getIntValue();
return new Writer (streamToWriteTo, getFormatName(), lameApp, vbr, cbr,
sampleRateToUse, numberOfChannels, bitsPerSample, metadataValues);
}
#endif

+ 71
- 0
source/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.h View File

@@ -0,0 +1,71 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_USE_LAME_AUDIO_FORMAT || defined (DOXYGEN)
//==============================================================================
/**
An AudioFormat class which can use an installed version of the LAME mp3
encoder to encode a file.
This format can't read MP3s, it just writes them. Internally, the
AudioFormatWriter object that is returned writes the incoming audio data
to a temporary WAV file, and then when the writer is deleted, it invokes
the LAME executable to convert the data to an MP3, whose data is then
piped into the original OutputStream that was used when first creating
the writer.
@see AudioFormat
*/
class JUCE_API LAMEEncoderAudioFormat : public AudioFormat
{
public:
/** Creates a LAMEEncoderAudioFormat that expects to find a working LAME
executable at the location given.
*/
LAMEEncoderAudioFormat (const File& lameExecutableToUse);
~LAMEEncoderAudioFormat();
bool canHandleFile (const File&);
Array<int> getPossibleSampleRates();
Array<int> getPossibleBitDepths();
bool canDoStereo();
bool canDoMono();
bool isCompressed();
StringArray getQualityOptions();
AudioFormatReader* createReaderFor (InputStream*, bool deleteStreamIfOpeningFails);
AudioFormatWriter* createWriterFor (OutputStream*, double sampleRateToUse,
unsigned int numberOfChannels, int bitsPerSample,
const StringPairArray& metadataValues, int qualityOptionIndex);
private:
File lameApp;
class Writer;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LAMEEncoderAudioFormat)
};
#endif

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save