世間では、単に好きな曲のメドレーを作業用BGMと呼ぶらしいですが、私は曲の境目で集中力がそがれるタイプなので、1つの曲を1時間延々とループさせるwavを作ることにします。

wavで出力するので、容量はバカでかくなります。

1. RadioLine Freeというソフトをダウンロードします。
2. ループさせたいwavを2回RadioLineにドラッグ&ドロップ。

一方の波形をダブルクリックして、もう一方の終わり近くまでずらします。
曲の間がスムーズにつながるよう調整します。

3. ファイル→プロジェクトの保存で、rlpファイルを保存します。
4. rlpファイルをテキストエディタで開き、"Position"という値をコピーします。

このPositionが2週目を始める位置になります。

[Element]
Track=0
Path=すばらしき新世界.wav
Position=6319616 ;←この値、0ではない方
Range=0,6830208
FadeInRange=0,0
FadeInRate=0

[Element]
Track=1
Path=すばらしき新世界.wav
Position=0;←こっちではない
Range=0,6830208
FadeOutRange=6830208,6830208
FadeOutRate=0
5.スクリプトで変換
python loopwav.py すばらしき新世界.wav o.wav 3600 6319616

引数は、「入力wavファイル」「出力wavファイル」「出力するwavファイルの秒数」「2週目を始める位置」
です。

loopwav.pyの中身↓

#encoding:shift-jis
#loopwav.py
from __future__ import division, print_function
__metaclass__ = type 
from future_builtins import zip, map, filter
import sys
import wave
import os.path
from contextlib import closing
import math
import audioop

def main():
    (input_path,  # 入力wavファイル名
     output_path, # 出力wavファイル名
     duration,    # 出力するwavファイルの秒数
     position,    # 2週目を始める位置
     ) = sys.argv[1:]
    duration = int(duration)
    position = int(position)    
    
    with closing(wave.open(input_path, "r")) as input_wav:
        nchannels = input_wav.getnchannels()
        sampwidth = input_wav.getsampwidth()
        framerate = input_wav.getframerate()
        nframes   = input_wav.getnframes()
        
        bytes_per_frame = nchannels * sampwidth
        bytes_per_sec  = bytes_per_frame * framerate
        all_bytes_size = bytes_per_frame * nframes
        
        all_frames = input_wav.readframes(all_bytes_size)
    
    loop_frame_count = nframes - 2 * (nframes - position)
    loop_bytes_size = bytes_per_frame * loop_frame_count
    loop_duration = loop_bytes_size / bytes_per_sec
    
    all_duration = nframes / framerate
    
    loop_count = int(math.ceil((duration - all_duration) / loop_duration) + 1)
    
    output_byte_size = all_bytes_size + (loop_count - 1) * loop_bytes_size
    output_duration = output_byte_size / bytes_per_sec
    
    assert duration <= output_duration < duration + loop_duration, (duration, output_duration, loop_duration)
    
    print("output size = {0}MB".format(output_byte_size // 1024**2))
    
    output_hours = int(output_duration // (60*60))
    output_mins = int(output_duration // 60 % 60)
    output_secs = output_duration % 60
    
    print("output duration = {0:02}:{1:02}:{2}".format(
        output_hours, output_mins, output_secs))
    
    print("loops {0}times".format(loop_count))
    
    with closing(wave.open(output_path, "w")) as output_wav:
        output_wav.setnchannels(nchannels)
        output_wav.setsampwidth(sampwidth)
        output_wav.setframerate(framerate)
        
        overwrap_size = (nframes - position) * bytes_per_frame
        
        head   = all_frames[:overwrap_size]
        center = all_frames[overwrap_size:-overwrap_size]
        tail   = all_frames[-overwrap_size:]
        
        overwrap = audioop.add(head, tail, sampwidth)
        
        output_wav.writeframes(head)
        output_wav.writeframes(center)
        
        for i in xrange(1, loop_count):
            output_wav.writeframes(overwrap)
            output_wav.writeframes(center)
        
        output_wav.writeframes(tail)
        
        
    
if "__main__" == __name__:
    main()

できたwavファイルの秒数は、指定した長さがぴったり何ループか分の長さになっていない限り、必ずしもコマンドラインで指定した長さにはなりません。

これで、飽きるを通り越して、曲がゲシュタルト崩壊して、耳がつぶれて、精神が崩壊するまで聞き続けられます。

どうでもいいですが、audioopモジュールって組み込みライブラリなんですね。速度が必要なのでCで書かれているのは当然なんですが、pydファイルがあるのではなく、インタープリタ自体に組み込まれているんです。ctypesですら組み込みじゃないのに、
なんでaudioopなんで利用率のワースト3に入ってもおかしくないようなライブラリ組み込みなんでしょうね?