diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,10 @@
 # Changelog for keid-sound-openal
 
-## Unreleased changes
+## 1.0.1.0
+
+- Loader switched to `Resource.Source`.
+- Removed unused deps.
+
+## 1.0.0.0
+
+Initial import.
diff --git a/keid-sound-openal.cabal b/keid-sound-openal.cabal
--- a/keid-sound-openal.cabal
+++ b/keid-sound-openal.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           keid-sound-openal
-version:        0.1.0.0
+version:        0.1.1.0
 synopsis:       OpenAL sound system for Keid engine.
 category:       Game Engine
 author:         IC Rainbow
@@ -92,10 +92,8 @@
   build-depends:
       OpenAL
     , base >=4.7 && <5
-    , geomancy
-    , keid-core
-    , opusfile
+    , keid-core >=0.1.2.0
+    , opusfile >=0.1.0.1
     , resourcet
     , rio >=0.1.12.0
-    , unliftio
   default-language: Haskell2010
diff --git a/src/Resource/Opus.hs b/src/Resource/Opus.hs
--- a/src/Resource/Opus.hs
+++ b/src/Resource/Opus.hs
@@ -1,39 +1,40 @@
--- {-# LANGUAGE Strict #-}
-
 module Resource.Opus
   ( Config(..)
   , Source
   , load
+  , loadPCM
   ) where
 
 import RIO
 
 import Foreign qualified
 import Foreign.C.Types (CFloat(..))
-import RIO.ByteString qualified as ByteString
+import GHC.Stack (withFrozenCallStack)
 import Sound.OpenAL qualified as OpenAL
 import Sound.OpusFile qualified as OpusFile
 
+import Resource.Source qualified as Resource
+
 data Config = Config
   { gain        :: Float
   , loopingMode :: Bool
-  , filePath    :: FilePath
+  , byteSource  :: Resource.Source
   }
 
 type Source = (Double, OpenAL.Source)
 
 load
-  :: (MonadIO m, MonadReader env m, HasLogFunc env)
+  :: ( MonadIO m
+     , MonadReader env m
+     , HasLogFunc env
+     , HasCallStack
+     )
   => OpenAL.Device
   -> Config
   -> m Source
 load _device Config{..} = do
-  logInfo $ "Loading " <> displayShow filePath
-  !pcm <- liftIO do
-    Right file <- ByteString.readFile filePath >>= OpusFile.openMemoryBS
-    pcmInt16 <- OpusFile.decodeInt16 file
-    OpusFile.free file
-    pure pcmInt16
+  pcm <- withFrozenCallStack $
+    Resource.load loadPCM byteSource
 
   alFormat <-
     case OpusFile.pcmChannels pcm of
@@ -44,7 +45,7 @@
       Left n -> do
         logError $ mconcat
           [ "unexpected channels in "
-          , displayShow filePath
+          , displayShow byteSource
           , ": "
           , displayShow n
           ]
@@ -73,3 +74,16 @@
       else
         OpenAL.OneShot
     gain' = CFloat gain
+
+-- TODO: extract to `opusfile`
+loadPCM :: MonadIO m => ByteString -> m (OpusFile.Pcm Int16)
+loadPCM bytes = do
+  !opusBytes <- liftIO $
+    OpusFile.openMemoryBS bytes >>= \case
+      Left err ->
+        throwString $ "Opus loader error: " <> show err
+      Right res ->
+        pure res
+  !pcmInt16 <- liftIO $ OpusFile.decodeInt16 opusBytes
+  liftIO $ OpusFile.free opusBytes
+  pure pcmInt16
