The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

444 lines
14KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. // (This file gets included by juce_mac_NativeCode.mm, rather than being
  24. // compiled on its own).
  25. #if JUCE_INCLUDED_FILE && JUCE_USE_CDBURNER
  26. //==============================================================================
  27. END_JUCE_NAMESPACE
  28. #define OpenDiskDevice MakeObjCClassName(OpenDiskDevice)
  29. @interface OpenDiskDevice : NSObject
  30. {
  31. DRDevice* device;
  32. NSMutableArray* tracks;
  33. }
  34. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device;
  35. - (void) dealloc;
  36. - (bool) isDiskPresent;
  37. - (int) getNumAvailableAudioBlocks;
  38. - (void) addSourceTrack: (JUCE_NAMESPACE::AudioSource*) source numSamples: (int) numSamples_;
  39. - (void) burn: (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener*) listener errorString: (JUCE_NAMESPACE::String*) error
  40. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting;
  41. @end
  42. //==============================================================================
  43. #define AudioTrackProducer MakeObjCClassName(AudioTrackProducer)
  44. @interface AudioTrackProducer : NSObject
  45. {
  46. JUCE_NAMESPACE::AudioSource* source;
  47. int readPosition, lengthInFrames;
  48. }
  49. - (AudioTrackProducer*) init: (int) lengthInFrames;
  50. - (AudioTrackProducer*) initWithAudioSource: (JUCE_NAMESPACE::AudioSource*) source numSamples: (int) lengthInSamples;
  51. - (void) dealloc;
  52. - (void) setupTrackProperties: (DRTrack*) track;
  53. - (void) cleanupTrackAfterBurn: (DRTrack*) track;
  54. - (BOOL) cleanupTrackAfterVerification:(DRTrack*)track;
  55. - (uint64_t) estimateLengthOfTrack:(DRTrack*)track;
  56. - (BOOL) prepareTrack:(DRTrack*)track forBurn:(DRBurn*)burn
  57. toMedia:(NSDictionary*)mediaInfo;
  58. - (BOOL) prepareTrackForVerification:(DRTrack*)track;
  59. - (uint32_t) produceDataForTrack:(DRTrack*)track intoBuffer:(char*)buffer
  60. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  61. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  62. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  63. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  64. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  65. ioFlags:(uint32_t*)flags;
  66. - (BOOL) verifyDataForTrack:(DRTrack*)track inBuffer:(const char*)buffer
  67. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  68. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  69. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  70. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  71. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  72. ioFlags:(uint32_t*)flags;
  73. @end
  74. //==============================================================================
  75. @implementation OpenDiskDevice
  76. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device_
  77. {
  78. [super init];
  79. device = device_;
  80. tracks = [[NSMutableArray alloc] init];
  81. return self;
  82. }
  83. - (void) dealloc
  84. {
  85. [tracks release];
  86. [super dealloc];
  87. }
  88. - (bool) isDiskPresent
  89. {
  90. return [device isValid]
  91. && [[[device status] objectForKey: DRDeviceMediaStateKey]
  92. isEqualTo: DRDeviceMediaStateMediaPresent];
  93. }
  94. - (int) getNumAvailableAudioBlocks
  95. {
  96. return [[[[device status] objectForKey: DRDeviceMediaInfoKey]
  97. objectForKey: DRDeviceMediaBlocksFreeKey] intValue];
  98. }
  99. - (void) addSourceTrack: (JUCE_NAMESPACE::AudioSource*) source_ numSamples: (int) numSamples_
  100. {
  101. AudioTrackProducer* p = [[AudioTrackProducer alloc] initWithAudioSource: source_ numSamples: numSamples_];
  102. DRTrack* t = [[DRTrack alloc] initWithProducer: p];
  103. [p setupTrackProperties: t];
  104. [tracks addObject: t];
  105. [t release];
  106. [p release];
  107. }
  108. - (void) burn: (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener*) listener errorString: (JUCE_NAMESPACE::String*) error
  109. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting
  110. {
  111. DRBurn* burn = [DRBurn burnForDevice: device];
  112. if (! [device acquireExclusiveAccess])
  113. {
  114. *error = "Couldn't open or write to the CD device";
  115. return;
  116. }
  117. [device acquireMediaReservation];
  118. NSMutableDictionary* d = [[burn properties] mutableCopy];
  119. [d autorelease];
  120. [d setObject: [NSNumber numberWithBool: peformFakeBurnForTesting] forKey: DRBurnTestingKey];
  121. [d setObject: [NSNumber numberWithBool: false] forKey: DRBurnVerifyDiscKey];
  122. [d setObject: (shouldEject ? DRBurnCompletionActionEject : DRBurnCompletionActionMount)
  123. forKey: DRBurnCompletionActionKey];
  124. [burn setProperties: d];
  125. [burn writeLayout: tracks];
  126. for (;;)
  127. {
  128. JUCE_NAMESPACE::Thread::sleep (300);
  129. float progress = [[[burn status] objectForKey: DRStatusPercentCompleteKey] floatValue];
  130. if (listener != 0 && listener->audioCDBurnProgress (progress))
  131. {
  132. [burn abort];
  133. *error = "User cancelled the write operation";
  134. break;
  135. }
  136. if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateFailed])
  137. {
  138. *error = "Write operation failed";
  139. break;
  140. }
  141. else if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateDone])
  142. {
  143. break;
  144. }
  145. NSString* err = (NSString*) [[[burn status] objectForKey: DRErrorStatusKey]
  146. objectForKey: DRErrorStatusErrorStringKey];
  147. if ([err length] > 0)
  148. {
  149. *error = JUCE_NAMESPACE::String::fromUTF8 ((JUCE_NAMESPACE::uint8*) [err UTF8String]);
  150. break;
  151. }
  152. }
  153. [device releaseMediaReservation];
  154. [device releaseExclusiveAccess];
  155. }
  156. @end
  157. //==============================================================================
  158. @implementation AudioTrackProducer
  159. - (AudioTrackProducer*) init: (int) lengthInFrames_
  160. {
  161. lengthInFrames = lengthInFrames_;
  162. readPosition = 0;
  163. return self;
  164. }
  165. - (void) setupTrackProperties: (DRTrack*) track
  166. {
  167. NSMutableDictionary* p = [[track properties] mutableCopy];
  168. [p setObject:[DRMSF msfWithFrames: lengthInFrames] forKey: DRTrackLengthKey];
  169. [p setObject:[NSNumber numberWithUnsignedShort:2352] forKey: DRBlockSizeKey];
  170. [p setObject:[NSNumber numberWithInt:0] forKey: DRDataFormKey];
  171. [p setObject:[NSNumber numberWithInt:0] forKey: DRBlockTypeKey];
  172. [p setObject:[NSNumber numberWithInt:0] forKey: DRTrackModeKey];
  173. [p setObject:[NSNumber numberWithInt:0] forKey: DRSessionFormatKey];
  174. [track setProperties: p];
  175. [p release];
  176. }
  177. - (AudioTrackProducer*) initWithAudioSource: (JUCE_NAMESPACE::AudioSource*) source_ numSamples: (int) lengthInSamples
  178. {
  179. AudioTrackProducer* s = [self init: (lengthInSamples + 587) / 588];
  180. if (s != nil)
  181. s->source = source_;
  182. return s;
  183. }
  184. - (void) dealloc
  185. {
  186. if (source != 0)
  187. {
  188. source->releaseResources();
  189. delete source;
  190. }
  191. [super dealloc];
  192. }
  193. - (void) cleanupTrackAfterBurn: (DRTrack*) track
  194. {
  195. }
  196. - (BOOL) cleanupTrackAfterVerification: (DRTrack*) track
  197. {
  198. return true;
  199. }
  200. - (uint64_t) estimateLengthOfTrack: (DRTrack*) track
  201. {
  202. return lengthInFrames;
  203. }
  204. - (BOOL) prepareTrack: (DRTrack*) track forBurn: (DRBurn*) burn
  205. toMedia: (NSDictionary*) mediaInfo
  206. {
  207. if (source != 0)
  208. source->prepareToPlay (44100 / 75, 44100);
  209. readPosition = 0;
  210. return true;
  211. }
  212. - (BOOL) prepareTrackForVerification: (DRTrack*) track
  213. {
  214. if (source != 0)
  215. source->prepareToPlay (44100 / 75, 44100);
  216. return true;
  217. }
  218. - (uint32_t) produceDataForTrack: (DRTrack*) track intoBuffer: (char*) buffer
  219. length: (uint32_t) bufferLength atAddress: (uint64_t) address
  220. blockSize: (uint32_t) blockSize ioFlags: (uint32_t*) flags
  221. {
  222. if (source != 0)
  223. {
  224. const int numSamples = JUCE_NAMESPACE::jmin (bufferLength / 4, (lengthInFrames * (44100 / 75)) - readPosition);
  225. if (numSamples > 0)
  226. {
  227. JUCE_NAMESPACE::AudioSampleBuffer tempBuffer (2, numSamples);
  228. JUCE_NAMESPACE::AudioSourceChannelInfo info;
  229. info.buffer = &tempBuffer;
  230. info.startSample = 0;
  231. info.numSamples = numSamples;
  232. source->getNextAudioBlock (info);
  233. JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (0),
  234. buffer, numSamples, 4);
  235. JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (1),
  236. buffer + 2, numSamples, 4);
  237. readPosition += numSamples;
  238. }
  239. return numSamples * 4;
  240. }
  241. return 0;
  242. }
  243. - (uint32_t) producePreGapForTrack: (DRTrack*) track
  244. intoBuffer: (char*) buffer length: (uint32_t) bufferLength
  245. atAddress: (uint64_t) address blockSize: (uint32_t) blockSize
  246. ioFlags: (uint32_t*) flags
  247. {
  248. zeromem (buffer, bufferLength);
  249. return bufferLength;
  250. }
  251. - (BOOL) verifyDataForTrack: (DRTrack*) track inBuffer: (const char*) buffer
  252. length: (uint32_t) bufferLength atAddress: (uint64_t) address
  253. blockSize: (uint32_t) blockSize ioFlags: (uint32_t*) flags
  254. {
  255. return true;
  256. }
  257. @end
  258. BEGIN_JUCE_NAMESPACE
  259. //==============================================================================
  260. AudioCDBurner::AudioCDBurner (const int deviceIndex)
  261. : internal (0)
  262. {
  263. OpenDiskDevice* dev = [[OpenDiskDevice alloc] initWithDevice: [[DRDevice devices] objectAtIndex: deviceIndex]];
  264. internal = (void*) dev;
  265. }
  266. AudioCDBurner::~AudioCDBurner()
  267. {
  268. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  269. if (dev != 0)
  270. [dev release];
  271. }
  272. AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
  273. {
  274. AudioCDBurner* b = new AudioCDBurner (deviceIndex);
  275. if (b->internal == 0)
  276. deleteAndZero (b);
  277. return b;
  278. }
  279. static NSArray* findDiskBurnerDevices()
  280. {
  281. NSMutableArray* results = [NSMutableArray array];
  282. NSArray* devs = [DRDevice devices];
  283. if (devs != 0)
  284. {
  285. int num = [devs count];
  286. int i;
  287. for (i = 0; i < num; ++i)
  288. {
  289. NSDictionary* dic = [[devs objectAtIndex: i] info];
  290. NSString* name = [dic valueForKey: DRDeviceProductNameKey];
  291. if (name != nil)
  292. [results addObject: name];
  293. }
  294. }
  295. return results;
  296. }
  297. const StringArray AudioCDBurner::findAvailableDevices()
  298. {
  299. NSArray* names = findDiskBurnerDevices();
  300. StringArray s;
  301. for (unsigned int i = 0; i < [names count]; ++i)
  302. s.add (String::fromUTF8 ((JUCE_NAMESPACE::uint8*) [[names objectAtIndex: i] UTF8String]));
  303. return s;
  304. }
  305. bool AudioCDBurner::isDiskPresent() const
  306. {
  307. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  308. return dev != 0 && [dev isDiskPresent];
  309. }
  310. int AudioCDBurner::getNumAvailableAudioBlocks() const
  311. {
  312. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  313. return [dev getNumAvailableAudioBlocks];
  314. }
  315. bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamps)
  316. {
  317. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  318. if (dev != 0)
  319. {
  320. [dev addSourceTrack: source numSamples: numSamps];
  321. return true;
  322. }
  323. return false;
  324. }
  325. const String AudioCDBurner::burn (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener* listener,
  326. const bool ejectDiscAfterwards,
  327. const bool peformFakeBurnForTesting)
  328. {
  329. String error ("Couldn't open or write to the CD device");
  330. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  331. if (dev != 0)
  332. {
  333. error = String::empty;
  334. [dev burn: listener
  335. errorString: &error
  336. ejectAfterwards: ejectDiscAfterwards
  337. isFake: peformFakeBurnForTesting];
  338. }
  339. return error;
  340. }
  341. //==============================================================================
  342. void AudioCDReader::ejectDisk()
  343. {
  344. const ScopedAutoReleasePool p;
  345. [[NSWorkspace sharedWorkspace] unmountAndEjectDeviceAtPath: juceStringToNS (volumeDir.getFullPathName())];
  346. }
  347. #endif