Version: XLD 20250302 (157.2), macOS on Apple Silicon
Reporter: Walter van der Heiden
Hardware: four USB optical drives on a powered hub —
TSSTcorp CDDVDW SE-218CN (+6), HL-DT-ST DVDRAM GP30NB40 (+6),
HL-DT-ST DVD+-RW GU40N (+103), HL-DT-ST BD-RE BP06LU10 (+667)
With several drives connected, "Set automatically if possible" does not produce a
per-drive read offset. All discs that are queued together are ripped with a single
offset value — whichever happens to be in the preferences field at that moment.
The resulting rips are complete and error-free, but the audio is shifted by up to
661 samples relative to the AccurateRip reference, and the log reports an offset
that was not the drive's own.
Two related symptoms share the same root cause (see below):
makeDriveOffsetList only auto-fills the offset when exactly one drive is found.Both logs show the same offset. Ripping the same two discs one at a time gives
the correct offset for each.
Reproducibility: always, whenever more than one disc is queued at a time.
Never when discs are ripped one by one.
60 rip logs, four drives, over eight days. Every rip started on its own has the
correct offset. Every rip started as part of a batch of discs inserted within the
same minute shares one offset. Nine out of nine mismatches follow this rule.
Two batches, four drives each:
2026-09-12 10:24:44 TSST 667 (correct: 6)
2026-09-12 10:25:04 GP30 667 (correct: 6)
2026-09-12 10:25:17 GU40N 667 (correct: 103)
2026-09-12 10:25:42 BD-RE 667 (correct: 667)
2026-09-13 14:26:19 GP30 6 (correct: 6)
2026-09-13 14:26:36 GU40N 6 (correct: 103)
2026-09-13 14:26:49 TSST 6 (correct: 6)
2026-09-13 14:26:58 BD-RE 6 (correct: 667)
In every affected log, AccurateRip reports "Accurately ripped with different
offset", and used offset + reported delta equals exactly the drive's value in
offsetlist.plist. All four drives are present in that file with the correct
values, so the data is right — only the plumbing is not.
o_offsetCorrectionValue is a single text field for the whole application.
updateOffsetCorrectionValueWithDriveName: (XLDController.m:3467) writes the[rippingSession setOffsetCorrectionValue:[o_offsetCorrectionValue intValue]])makeDriveOffsetList (XLDController.m:4137) ends withif(found == 1) [o_offsetCorrectionValue setIntValue:...] — there is a specialdriveIsBusy (XLDController.h:152) is a single BOOL for all drives. It gates both
automount (XLDController.m:1474) and the "Open Audio CD" menu item
(XLDController.m:5058), which is why reading one disc blocks the other drives.
Trunk (157.2) does not build with a current Xcode. In the hope it is useful, here
is everything that was needed on macOS 26 / Apple Silicon:
cddb.png and image.png are referenced by the project but are in neither.xib files still declare macOS 10.4 or 10.5. ibtool refuses these withIBDocument.SystemTarget, <deployment version="..."/>, andIBDocument.PluginDeclaredDependencies.MetadataEditor.xib cannot be opened by the current ibtool at all, in all-[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance.XLDGainAnalyzer.c and ebur128.c are present in the source tree but are notSCDynamicStoreCopyProxies needs -framework SystemConfiguration, which isXLDID3.framework must already exist in the sibling*/build/Release/ directories; they can be borrowed from an installed XLD.app.With those addressed, and libsndfile, libsoxr, flac, wavpack and libcddb from
Homebrew, this works:
xcodebuild -project XLD_export.xcodeproj -target XLD -configuration Release \
SDKROOT=macosx ARCHS=arm64 ONLY_ACTIVE_ARCH=YES \
MACOSX_DEPLOYMENT_TARGET=12.0 \
HEADER_SEARCH_PATHS='$(inherited) /opt/homebrew/include' \
LIBRARY_SEARCH_PATHS='$(inherited) /opt/homebrew/lib' \
OTHER_LDFLAGS='$(inherited) -framework SystemConfiguration'
The patch below was built and verified this way. With it applied, two discs
inserted fifteen seconds apart into two different drives now each receive their
own offset:
2026-09-14 15:17:18 GP30NB40 offset 6 All tracks accurately ripped
2026-09-14 15:17:33 BP06LU10 offset 667 All tracks accurately ripped
Neither log reports "with different offset" any more. The same two discs, in the
same two drives, previously both came out at offset 6.
XLDCDDARippingSession is already per-device — sessions is keyed by device path,
and each session owns both its cdread descriptor and its offsetCorrectionValue.
Letting the session resolve its own offset fixes the problem by construction and
needs no UI change. Patch below (against 157.2).
driveIsBusy is a larger change and is left out deliberately: the natural fix is to
ask the sessions dictionary whether this device is busy, but that touches menu
validation and automount and is better done separately.
--- a/XLDCDDARippingSession.h
+++ b/XLDCDDARippingSession.h
@@ -34,6 +34,7 @@
- (xld_cdread_t *)descriptor;
- (int)offsetCorrectionValue;
- (void)setOffsetCorrectionValue:(int)value;
+- (BOOL)resolveOffsetCorrectionValueFromDrive;
- (int)retryCount;
- (void)setRetryCount:(int)value;
- (xldoffset_t)firstAudioFrame;
--- a/XLDCDDARippingSession.m
+++ b/XLDCDDARippingSession.m
@@ -93,6 +93,22 @@
offsetCorrectionValue = value;
}
+- (BOOL)resolveOffsetCorrectionValueFromDrive
+{
+ /* Resolve the read offset from this session's own drive, so that discs in
+ different drives no longer share a single offset value. */
+ if(!cdread.product) return NO;
+ NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:
+ [[NSBundle mainBundle] pathForResource:@"offsetlist" ofType:@"plist"]];
+ NSString *name = [NSString stringWithUTF8String:cdread.product];
+ id value = [dic objectForKey:name];
+ if(!value && [name length] > 1)
+ value = [dic objectForKey:[name substringToIndex:[name length]-1]];
+ if(!value) return NO;
+ offsetCorrectionValue = [value intValue];
+ return YES;
+}
+
- (int)retryCount
{
return retryCount;
--- a/XLDController.m
+++ b/XLDController.m
@@ -936,6 +936,7 @@
if(ripperMode != kRipperModeBurst && [o_useC2Pointer state] == NSOnState) ripperMode |= kRipperModeC2;
[rippingSession setRipperMode:ripperMode];
[rippingSession setOffsetCorrectionValue:[o_offsetCorrectionValue intValue]];
+ if([o_autoSetOffsetValue state] == NSOnState) [rippingSession resolveOffsetCorrectionValueFromDrive];
[rippingSession setRetryCount:[o_maxRetryCount intValue]];
[rippingSession setFirstAudioFrame:[cueParser firstAudioFrame]];
[rippingSession setLastAudioFrame:[cueParser lastAudioFrame]];
@@ -946,7 +947,7 @@
[resultObj setDeviceStr:[cueParser fileToDecode]];
[resultObj setDriveAndMediaInfoFromDescriptor:[rippingSession descriptor]];
[resultObj setRipperMode:ripperMode
- offsetCorrention:[o_offsetCorrectionValue intValue]
+ offsetCorrention:[rippingSession offsetCorrectionValue]
retryCount:[o_maxRetryCount intValue]
useAccurateRipDB:(([o_queryAccurateRip state] == NSOnState) && ([discView extractionMode] != 1) && ([dbData state] != kXLDAccurateRipDBStateNetworkError))
checkInconsistency:([o_verifySuspiciousSector state] == NSOnState)